Bind ASP.NET MVC model value to checkbox with knockout.js - asp.net-mvc

I am new to knockout.js. I have a Y/N value from my model that I want to bind to a checkbox.
This is my view:
<tbody id="tblMultiEdit" data-bind="foreach: UUTs">
<tr>
<td data-bind="text: SerialNumber"></td>
<td><input type="checkbox" data-bind="ReqDowngrade" /></td>
<td><input type="checkbox" data-bind="ACTSupported"/></td>
<td><input type="checkbox" data-bind="ProdModeOff"/></td>
</tr>
</tbody>
Knockout code:
function ViewModel(UUTs)
{
var self = this;
self.UUTs = UUTs;
};
var viewModel = new ViewModel(#Html.HtmlConvertToJson(Model));
ko.applyBindings(viewModel);
So far I can bind the text with no problem, but checkboxes are in blank.

I was able to resolve this by adding a ternary operation.
<td><input type="checkbox" data-bind="checked: (ReqDowngrade == 'Y' ? 1 : 0)" /></td>
If anybody knows a more efficient way using knockout let me know!

Related

POST action returns the model in a valid state but returns Model.Count as 0 when using foreach or for loop

As shown in my post here the GET action method Test(..) works fine when using foreach loop in the corresponding Test.chtml view but the POST action method Test(...) returns null. But, as mentioned by many users, the foreach is not reliable for POST method. So, I decided to use the for loop as shown below. But that returned unexpected results in the view since, according to this post, in a foreachloop type casting is done automatically but in for loop you have to type cast the objects Model[i].BlogID etc to a proper class object type.
So, I decided to type cast the objects Model[i].BlogID etc to a BlogsWithRelatedPostsViewModel class object type as shown in the second version of Test.cshml view below; and this time the Test.cshtml view is displayng the correct records. But although the submit button in the view is sending a a valid model (ModelState.IsValid is true) the Model.Count is 0 that results in no update to database. Why Model.Count is 0 and how to correct it? As you can see below the html page source of the view is showing the name attributes of the tags matching the property values in the View Model.
Note: For complete code, please see this OP. I'm using ASP.NET Core with EF Core and Tag Helpers.
Test.cshtml view with for loop - without type casting the loop objects:
#model IList<ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel>
#using ASP_Core_Blogs.Models.BlogPostViewModels
#{ ViewData["Title"] = "Index"; }
<div class="row">
<div class="col-md-12">
<form asp-controller="Blogs" asp-action="Test" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post">
#{
IEnumerable<SelectListItem> yearsList = (IEnumerable<SelectListItem>)ViewBag.YearsList;
var currentlySelectedIndex = 0; // Currently selected index (usually will come from model)
}
<strong>Select a Post Year</strong>
<h6>Choose a year and a URL to begin:</h6>
<label>Year:</label><select asp-for="#currentlySelectedIndex" asp-items="yearsList"></select><input type="submit" class="btn btn-default" name="GO" value="GO" />
<table class="table">
<thead>
<tr>
<th></th>
<th></th>
<th>Url</th>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
#for (int i=0; i< Model.Count(); i++)
{
<tr>
<td><input type="hidden" asp-for="#Model[i].BlogID" /></td>
<td><input type="hidden" asp-for="#Model[i]).PostID" /></td>
<td>
<input type="text" asp-for="#Model[i].Url" style="border:0;" readonly />
</td>
<td>
<input asp-for="#Model[i].Title" />
</td>
<td>
<input asp-for="#Model[i].Content" />
</td>
</tr>
}
</tbody>
</table>
<button type="submit" class="btn btn-default">Save</button>
</form>
</div>
</div>
Test.cshtml view with for loop objects being casted as BlogsWithRelatedPostsViewModel class objects:
#model IList<ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel>
#using ASP_Core_Blogs.Models.BlogPostViewModels
#{ ViewData["Title"] = "Index"; }
<div class="row">
<div class="col-md-12">
<form asp-controller="Blogs" asp-action="Test" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post">
#{
IEnumerable<SelectListItem> yearsList = (IEnumerable<SelectListItem>)ViewBag.YearsList;
var currentlySelectedIndex = 0; // Currently selected index (usually will come from model)
}
<strong>Select a Post Year</strong>
<h6>Choose a year and a URL to begin:</h6>
<label>Year:</label><select asp-for="#currentlySelectedIndex" asp-items="yearsList"></select><input type="submit" class="btn btn-default" name="GO" value="GO" />
<table class="table">
<thead>
<tr>
<th></th>
<th></th>
<th>Url</th>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
#for (int i=0; i< Model.Count(); i++)
{
<tr>
<td><input type="hidden" asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).BlogID" /></td>
<td><input type="hidden" asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).PostID" /></td>
<td>
<input type="text" asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).Url" style="border:0;" readonly />
</td>
<td>
<input asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).Title" />
</td>
<td>
<input asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).Content" />
</td>
</tr>
}
</tbody>
</table>
<button type="submit" class="btn btn-default">Save</button>
</form>
</div>
</div>
A Portion of html generated by View after Submit:
<tr>
<td><input type="hidden" data-val="true" data-val-required="The BlogID field is required." id="BlogID" name="BlogID" value="1" /></td>
<td><input type="hidden" data-val="true" data-val-required="The PostID field is required." id="PostID" name="PostID" value="1" /></td>
<td>
<input type="text" style="border:0;" readonly id="Url" name="Url" value="blog1#test.com" />
</td>
<td>
<input type="text" id="Title" name="Title" value="Title1" />
</td>
<td>
<input type="text" id="Content" name="Content" value="Content1" />
</td>
</tr>

asp.net mvc razor cannot pass counter increment

i am increment i in this code which i am not able to parse. what is wrong with i in the code below?
#{
int i=0;
}
#foreach (var item in Model.PortServiceTariffIncluded)
{
<tr id="#("sp" + item.ServiceId)">
<td>#item.ServiceName <input type="hidden" name="QuotationDetailList[i].ServiceId" value="#item.ServiceId" /></td>
<td>#item.ServiceCriteria</td>
<td>#item.ItemBasis</td>
<td>#Html.DropDownListFor(model => model.Currency, ViewBag.CurrencyDd as SelectList) <input type ="text" id="Amount#i" name="QuotationDetailList[i].Amount" /></td>
<td><input type="hidden" value="#item.ServiceId" class="serviceslist" name="serviceslist" /><input type ="button" id="#item.ServiceId" name="btnremove" value="Remove" class="clsremove" /></td>
</tr>
i = i + 1;
}
Use the following, instead:
#foreach (var item in Model.PortServiceTariffIncluded.Select((value, i) => new { i, value })
{
<tr id="#("sp" + item.value.ServiceId)">
<td>#item.ServiceName <input type="hidden" name="QuotationDetailList[item.i].ServiceId" value="#item.value.ServiceId" /></td>
<td>#item.value.ServiceCriteria</td>
<td>#item.value.ItemBasis</td>
<td>#Html.DropDownListFor(model => model.Currency, ViewBag.CurrencyDd as SelectList) <input type ="text" id="Amount#item.i" name="QuotationDetailList[item.i].Amount" /></td>
<td><input type="hidden" value="#item.value.ServiceId" class="serviceslist" name="serviceslist" /><input type ="button" id="#item.value.ServiceId" name="btnremove" value="Remove" class="clsremove" /></td>
</tr>
}
Basically, this causes your item variable to be an object consisting of an iterator (item.i) and the actual item (item.value).
First, I would set a variable to contain your QuotationDetailList :
#{ var QuotationDetailList = Model.QuotationDetailList;}
Then, use a for here instead of a foreach :
#for (var ListIndex = 0; ListIndex < Model.PortServiceTariffIncluded.Count(); ListIndex++)
Now you can reference items using your variable and the index :
<td>#QuotationDetailList[ListIndex].ServiceName <input type="hidden" name="#QuotationDetailList[ListIndex].ServiceId" value="#QuotationDetailList[ListIndex].ServiceId" /></td>

two-way binding of a single object in observableArray

My page is as follows:
<button id="add">Add Data</button>
<button id="show">show</button>
<table>
<tr style="vertical-align:top">
<td>
<table border="1">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody data-bind="foreach: students">
<tr>
<td data-bind="text: id"></td>
<td>
<input type="text" data-bind="value: name" />
</td>
<td> Select
</td>
</tr>
</tbody>
</table>
</td>
<td>
<table id="data">
<tbody data-bind="with: selectedData">
<tr>
<td>Id</td>
<td>
<input type="text" data-bind="value: id" />
</td>
</tr>
<tr>
<td>Name</td>
<td>
<input type="text" data-bind="value: name" />
</td>
</tr>
<tr>
<td></td>
<td>
<input type="button" value="Close" />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
The javascript is as follows:
function ViewModel() {
var self = this;
self.students = ko.observableArray([]);
self.showData = function (dt) {
if (window.console) console.log(dt);
self.selectedData(dt);
$('#data').show();
}
this.selectedData = ko.observable();
}
$(function () {
window.appViewModel = new ViewModel();
ko.applyBindings(window.appViewModel);
$('#add').click(function () {
var model = window.appViewModel;
$.each(students, function (idx, student) {
if (window.console) console.log(student);
model.students.push(student);
});
$('table').show();
});
$('table').hide();
$('input').click(function () {
$('#data').hide();
});
$('#show').click(function () {
var s = JSON.stringify(window.appViewModel.students());
alert(s);
});
});
Preview:
In pic, I click on the select corresponding to student with id = 3. The other table shows up with the selected student details. Suppose I enter something in textbox 1, textbox 2 doesn't update, and vice versa.
What to do to make that happen?
Fiddle: http://jsfiddle.net/deostroll/YdrQf/1/
Your inputs aren't updating because the id and name values are not being stored or bound against observables, which are the special object that knockout provides specifically for this purpose. You can easily solve this with your code by adding a new Student type:
function Student(data) {
this.id = ko.observable(data.id);
this.name = ko.observable(data.name);
};
and use it to populate your students array with:
$.each(students, function (idx, student) {
if (window.console) console.log(student);
model.students.push(new Student(student));
});
With those properties now being observables, their changes will propagate to the UI. Here is the fiddle, with these two minor changes.
That being said, I think you have largely missed the point of Knockout. I strongly suggest you go through the Knockout tutorials, if you haven't done so already.
You're use of jQuery to create click functions for your viewmodel really goes against the model that Knockout encourages. Please take a look at this fiddle, which converts your code into 100% Knockout, using viewmodel functions, and drops all the jQuery.

if statement should check part of string exists in mvc

Below code saying substring doesnt exist in current context. Give me someother way to check whether my id contains 'DOM' or 'INT' in my view in mvc.
My table:
My code:
#if( (SUBSTRING(Model.Id,7,9)) !== 'DOM' )
{
<tr>
<td>Amount Approved for Domestic sector : </td>
<td><input id="Text1" type="text" /></td>
</tr>
}
You could use the Contains method to check if a given string contains a specified substring:
#if(Model.Id.Contains("DOM"))
{
<tr>
<td>Amount Approved for Domestic sector : </td>
<td><input id="Text1" type="text" /></td>
</tr>
}
or:
#if(Model.Id.Split('/')[1].Trim() == "DOM")
{
<tr>
<td>Amount Approved for Domestic sector : </td>
<td><input id="Text1" type="text" /></td>
</tr>
}
I think it should be
#if((Model.Id.Substring(7,9)) !== 'DOM')
Since Substring is a method of String

Struts 2.0 pass selected checkbox mapping value to JavaScript function

I am using struts 2 framework and iterating 4 fields (checkbox,rollnumber,name,location) in Jsp. It is working fine. Now i need to delete the selected checkbox record, for that i require rollnumber(which is primary key in table) object to be pass to javascript function. How can I pass the rollnumber object to javascript function. I have already pass the checkbox object(document.myForm.subCheckBox) to java script function, i need to pass one more rollnumber object.
<table border="1">
<tr>
<s:if test="%{mode != 'view'}">
<td><input type="checkbox" id="mainCheckBox" onclick="return checkAll(document.myForm.subCheckBox)"/></td>
</s:if>
<th>Roll Number</th>
<td>Name</td>
<td>Location</td>
</tr>
<s:iterator value="beanList" >
<tr>
<s:if test="%{mode != 'view'}">
<td>
<input type="checkbox" name="subCheckBox"/>
</td>
</s:if>
<td>
<s:property value="rollnumber" />
</td>
<td>
<s:property value="name"/>
</td>
<td>
<s:property value="location"/>
</td>
</tr>
</s:iterator>
</table>
<table>
<s:if test="%{mode != 'view'}">
<tr>
<input type="button" value="Delete" onclick="return deleteRecord(document.myForm.subCheckBox) "/>
</tr>
</s:if>
</table>

Resources