Reputation: 114
thank you for looking into this.
I have the following example built: http://jsfiddle.net/zm381qjx/5/
This is a menu list builder. When you add a menu, an edit form pops up. Using protectedObservable so that i can either commit or reset (as per code). One functionality, which i am having problems with, is there is radio button list (for TypeId), and depending on the value (10 = Url, 20 = Category, 30 = Page), you set the respective properties (10 = Url, 20 = CategoryId, 30 = PageId).
Flicking through the radio buttons, if Url is selected, another textbox should show (based on urlVisible) so user can enter the Url. I have added a span with text: TypeId.temp so i can see the temporary value. This is very irregular. Try to flick through several times.
Any help will be greatly appreciated.
My HTML
<a class="btn btn-primary" data-bind="click: addMenu">Add Menu</a>
<ul data-bind="foreach: Menus">
<li><a href="#" data-bind="text: Name, click: editMenu"></a></li>
</ul>
<div class="panel panel-default" data-bind="slideIn: editMenuItem, with: editMenuItem">
<div class="panel-body">
<div class="form-group">
<label for="MenuName">Name: </label>
<input type="text" id="MenuName" data-bind="value: Name" class="form-control" />
</div>
<label class="radio-inline">
<input type="radio" name="MenuTypeId" value="10" data-bind="checked: TypeId" /> Url
</label>
<label class="radio-inline">
<input type="radio" name="MenuTypeId" value="20" data-bind="checked: TypeId" /> Category
</label>
<label class="radio-inline">
<input type="radio" name="MenuTypeId" value="30" data-bind="checked: TypeId" /> Page
</label>
<div class="form-group" data-bind="visible: urlVisible">
<label for="MenuUrl">Url: </label>
<input type="text" id="MenuUrl" data-bind="value: Url" class="form-control" />
</div>
<br />
<p>TypeId.temp = <span data-bind="text: TypeId.temp"></span></p>
<br /><br />
<input type="button" class="btn btn-success" value="Update" data-bind="click: commit" /> or
<a href="#" data-bind="click: reset">Cancel</a>
</div>
</div>
My JS:
var vm = null;
//wrapper for an observable that protects value until committed
ko.protectedObservable = function (initialValue) {
//private variables
var _temp = ko.observable(initialValue);
var _actual = ko.observable(initialValue);
var result = ko.dependentObservable({
read: function () {
return _actual();
},
write: function (newValue) {
_temp(newValue);
}
});
//commit the temporary value to our observable, if it is different
result.commit = function () {
var temp = _temp();
if (temp !== _actual()) {
_actual(temp);
}
};
//notify subscribers to update their value with the original
result.reset = function () {
_actual.valueHasMutated();
_temp(_actual());
};
result.temp = _temp;
return result;
};
ko.bindingHandlers.slideIn = {
init: function (element) {
$(element).hide();
},
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (value) {
$(element).stop().hide().slideDown('fast');
} else {
$(element).stop().slideUp('fast');
}
}
};
var Menu = function (Id, Name, TypeId, CategoryId, PageId, Url) {
var self = this;
/* Core Properties */
self.Id = ko.observable(Id);
self.Name = ko.protectedObservable(Name);
self.TypeId = ko.protectedObservable(TypeId);
self.CategoryId = ko.protectedObservable(CategoryId);
self.PageId = ko.protectedObservable(PageId);
self.Url = ko.protectedObservable(Url);
/* Virtual Properties */
self.urlVisible = ko.computed(function () {
return self.TypeId.temp() == "10";
}, self);
/* Virtual Functions */
self.editMenu = function (data) {
if(vm.editMenuItem()) {
vm.editMenuItem(null);
}
vm.editMenuItem(data);
};
/* Core Functions */
self.commit = function () {
if (self.Name.temp() == '' || self.Name.temp() == null) {
alert('Please enter a name.'); return;
}
self.Name.commit();
self.TypeId.commit();
self.CategoryId.commit();
self.PageId.commit();
self.Url.commit();
vm.editMenuItem(null);
};
self.reset = function () {
self.Name.reset();
self.TypeId.reset();
self.CategoryId.reset();
self.PageId.reset();
self.Url.reset();
vm.editMenuItem(null);
};
};
var ViewModel = function() {
var self = this;
/* Core Properties */
self.Menus = ko.observableArray([]);
/* Virtual Properties */
self.editMenuItem = ko.observable(null);
self.addMenu = function(){
var menu = new Menu(0, "New Menu", "10", 0, 0, "");
self.Menus.push(menu);
self.editMenuItem(menu);
};
};
$(function () {
vm = new ViewModel();
ko.applyBindings(vm);
});
Upvotes: 0
Views: 682
Reputation: 1070
If you change your radio button binding to
<input type="radio" name="MenuTypeId" value="10" data-bind="checked: TypeId.temp" />
The temp id will be changed accordingly and radio button behaviour is consistent, but not with TypeId as value.
also the protectedObservable binding the radio button value is not playing nice
When you manually click the radio the TypeId value is never changed (as you are not committing the value) and I guess that as the radio button value never changes from 10 , it is not recognizing the subsequent manual clicks on Url radio button.
I updated the value using a button and it is changing accordingly; but then it will not move the value from that TypeId on subsequent radio button clicks
And the problem is still appearing for protectedObservable binding but not with a simple observable.
Code which explores this idea further: http://jsfiddle.net/zm381qjx/101/
Upvotes: 1