Reputation: 995
I have read the docs on knockoutjs and i understand that for a radio button to use check bindings. The issue with this for me is the way the binding works doesn't fit my scenario. In their examples, a radio button is assigned a value and when the radio button is selected, it validates the value of the radio button versus a value in a ko.computed function to determine which radio button was checked. However, in my below example, i have a radio button per table row.
I need the property "IsPrimary" to update to true when they select a radio button for a row..the name of the radio buttons being the same prevents multiple selections. I have been able to get the property to update for KO but it does not update the property in my mvc Model for the post back nor does it check the radio button to show it was selected.
<table data-bind="foreach: details">
<tr>
<td>
<div>
<input data-bind="value: StandardAccountNo, attr: {name: 'NewAccountGroupDetails[' + $index() + '].StandardAccountNo'}" />
</div>
</td>
<td>
<div class="radiobutton">
<input type="radio" data-bind="click: $parent.markPrimary, attr: {value: $index()}" name="primary" />
</div>
</td>
<td>
<a href="#" data-bind="click: $parent.removeDetail">Remove</a>
</td>
<tr>
</table>
<button data-bind="click: addDetail">New</button>
Knockout
var Detail = function () {
this.StandardAccountNo = ko.observable(new Date());
this.IsPrimary = ko.observable(false);
this.EffectiveDate = ko.observable(formattedDate(new Date()));
this.EndDate = ko.observable(formattedDate(new Date()));
};
function ViewModel() {
var self = this;
var rawList = '@Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model.NewAccountGroupDetails))';
self.details = ko.observableArray(convertJSONToKoObservableObject($.parseJSON(rawList)));
self.details.push(new Detail());
self.addDetail = function () {
self.details.push(new Detail());
$('.datepicker').each(function (i, obj) {
$(obj).datepicker({ changeYear: true, changeMonth: true });
});
}
self.markPrimary = function () {
console.log(this);
this.IsPrimary(true);
$('.radiobutton').each(function (i, obj) {
console.log(obj);
});
}
self.removeDetail = function () {
self.details.remove(this);
}
}
ko.applyBindings(new ViewModel());
NOTES: The console.logs output the KO object that represents the row selected and this works. The next one just outputs each row that has a radio button on it and it works. I was trying to use this to figure out how to mark the radio button on the page as checked and then also ensure the property on my mvc model gets updated so that it post back.
Upvotes: 0
Views: 450
Reputation: 13549
I think you're approaching this from the asp.net mvc point of view a bit too much. Try to isolate problems with your client side first, then serialize the model, then deal with your server.
As far as knockout is concerned, this would be how to do what you're trying: http://jsfiddle.net/z1b3mh89/
// items have names and a computed function that knows whether
// this item is primary among other items
function Item(name, primaryObservable) {
this.name = name;
this.isPrimary = ko.computed(function (){
return this.name === primaryObservable();
}, this);
}
(function(){
var i = 0;
var viewModel = {
primaryItemName: ko.observable(),
items: ko.observableArray(),
add: function (a,b,c) {
this.items.push(new Item(i++ + ' choice', this.primaryItemName));
}
};
// add a few items
viewModel.add();
viewModel.add();
viewModel.add();
// add a computed that renders a textual representation of the model
// just to see the changes live (this is only for DEBUG)
viewModel.log = ko.computed(function () {
return this.items().map(function (item) {
return item.name + (item.isPrimary() ? ' [primary]' : '');
}).join(', ');
}, viewModel);
ko.applyBindings(viewModel);
})();
and your html is simple:
<!-- ko foreach: items -->
<label>
<input type="radio" name="group1" data-bind="checked: $parent.primaryItemName, value: name"/>
<span data-bind="text: name"/>
</label>
<!-- /ko -->
<h3>The Items in the view model:</h3>
<p data-bind="text: log"></p>
<button data-bind="click: add">Add Item</button>
Once you get that working, your view model should always be in a good state. You can worry about serializing and sending it to mvc then.
Upvotes: 0
Reputation: 1316
Try this:
self.markPrimary = function (currentDetail) {
ko.utils.arrayForEach(self.details(), function (detail) {
detail.IsPrimary(false);
});
currentDetail.IsPrimary(true);
return true;
}
Upvotes: 0