感谢您对此进行调查。
我构建了以下示例:http://jsfiddle.net/zm381qjx/5/
这是一个菜单列表生成器。添加菜单时,会弹出一个编辑表单。使用protectedObservable,这样我就可以提交或重置(根据代码)。我遇到的一个问题是,有一个单选按钮列表(用于TypeId),根据值(10=Url,20=Category,30=Page),您可以设置相应的属性(10=Url,20=CategoryId,30=PageId)。
点击单选按钮,如果选择了Url,则应显示另一个文本框(基于urlVisible),以便用户可以输入Url。我添加了一个带有文本的span:TypeId.temp,这样我就可以看到临时值。这是非常不规则的。试着浏览几次。
任何帮助都将不胜感激。
我的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>
我的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);
});
如果您将单选按钮绑定更改为
<input type="radio" name="MenuTypeId" value="10" data-bind="checked: TypeId.temp" />
临时id将相应地更改,单选按钮的行为是一致的,但不使用TypeId作为值。
同时protectedObservable绑定单选按钮值也不太好
当您手动单击单选按钮时,TypeId值永远不会更改(因为您没有提交该值),我猜由于单选按钮值永远不会从10更改,因此它无法识别随后手动单击Url单选按钮。
我用一个按钮更新了值,它也在相应地改变;但在随后的单选按钮点击时,它不会从该TypeId中移动值
问题仍然出现在protectedObservable绑定中,但不是简单的observable。
进一步探讨这一想法的代码:http://jsfiddle.net/zm381qjx/101/