我从敲门开始,我的计算观察者似乎总是在视图模型被实例化时触发,我不知道为什么。
我将问题简化为荒谬只是为了测试:计算属性只是在控制台中打印一条消息,并且没有绑定到DOM的任何元素。这是:
(function() {
function HomeViewModel() {
var self = this;
(...)
self.FullName = ko.computed(function () {
console.log("INSIDE");
});
(...)
};
ko.applyBindings(new HomeViewModel());
})();
如何避免?
更新
以下是ViewModel的完整代码,仅供您更好地理解:
function HomeViewModel() {
var self = this;
self.teachers = ko.observableArray([]);
self.students = ko.observableArray([]);
self.FilterByName = ko.observable('');
self.FilterByLastName = ko.observable('');
self.FilteredTeachers = ko.observableArray([]);
self.FilteredStudents = ko.observableArray([]);
self.FilteredUsersComputed = ko.computed(function () {
var filteredTeachers = self.teachers().filter(function (user) {
return (user.name.toUpperCase().includes(self.FilterByName().toUpperCase()) &&
user.lastName.toUpperCase().includes(self.FilterByLastName().toUpperCase())
);
});
self.FilteredTeachers(filteredTeachers);
var filteredStudents = self.students().filter(function (user) {
return (user.name.toUpperCase().includes(self.FilterByName().toUpperCase()) &&
user.lastName.toUpperCase().includes(self.FilterByLastName().toUpperCase())
);
});
self.FilteredStudents(filteredStudents);
$("#LLAdminBodyMain").fadeIn();
}).extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 800 } });
self.FilteredUsersComputed.subscribe(function () {
setTimeout(function () { $("#LLAdminBodyMain").fadeOut(); }, 200);
}, null, "beforeChange");
$.getJSON("/api/User/Teacher", function (data) {
self.teachers(data);
});
$.getJSON("/api/User/Student", function (data) {
self.students(data);
});
}
ko.applyBindings(new HomeViewModel());
})();
我需要它不能在加载时执行,因为在加载时self.students
和self.teachers
数组不会被填充。
注意:只想突出显示两个代码(荒谬和完整),计算属性在加载时执行(或首次实例化ViewModel时)。
答案 0 :(得分:1)
您的方法存在两个主要错误。
ko.computed
将填充该角色,无需将计算结果存储在任何位置。 (计算器被缓存,它们在内部存储自己的值。重复调用计算器不会重新计算其值。)小点/改进建议:
...Computed
- 这与您的观点无关,没有理由指出它。对于视图中的所有实际用途,计算和观察是完全相同的。$.getJSON("...", function (data) { someObservable(data) });
$.getJSON("...", someObservable);
。这是一个更好的viewmodel:
function HomeViewModel() {
var self = this;
self.teachers = ko.observableArray([]);
self.students = ko.observableArray([]);
self.filterByName = ko.observable().extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 800 } });
self.filterByLastName = ko.observable().extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 800 } });
function filterUsers(userList) {
var name = self.filterByName().toUpperCase(),
lastName = self.filterByLastName().toUpperCase(),
allUsers = userList();
if (!name && !lastName) return allUsers;
return allUsers.filter(function (user) {
return (!name || user.name.toUpperCase().includes(name)) &&
(!lastName || user.lastName.toUpperCase().includes(lastName));
});
}
self.filteredTeachers = ko.computed(function () {
return filterUsers(self.teachers);
});
self.filteredStudents = ko.computed(function () {
return filterUsers(self.students);
});
self.filteredUsers = ko.computed(function () {
return self.filteredTeachers().concat(self.filteredStudents());
// maybe sort the result?
});
$.getJSON("/api/User/Teacher", self.teachers);
$.getJSON("/api/User/Student", self.students);
}
有了它,不再重要的是立即计算计算结果。您可以将视图绑定到filteredTeachers
,filteredStudents
或filteredUsers
,视图将始终反映事态。
当涉及到使用户界面元素对viewmodel状态更改做出反应时,无论反应是“更改HTML”还是“淡入/淡出”都没有区别。这不是viewmodel的工作。它始终是绑定的任务。
如果没有符合您要求的“股票”绑定,make a new one。这个是直接来自the examples in the documentation:
// Here's a custom Knockout binding that makes elements shown/hidden via jQuery's fadeIn()/fadeOut() methods
// Could be stored in a separate utility library
ko.bindingHandlers.fadeVisible = {
init: function(element, valueAccessor) {
// Initially set the element to be instantly visible/hidden depending on the value
var value = valueAccessor();
$(element).toggle(ko.unwrap(value)); // Use "unwrapObservable" so we can handle values that may or may not be observable
},
update: function(element, valueAccessor) {
// Whenever the value subsequently changes, slowly fade the element in or out
var value = valueAccessor();
ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();
}
};
它根据绑定值淡入/淡出绑定元素。空数组[]
的计算结果为false是可行的,因此您可以在视图中执行此操作:
<div data-bind="fadeVisible: filteredUsers">
<!-- show filteredUsers... --->
</div>
在绑定值更改之前和之后淡化元素的自定义绑定如下所示。
init
阶段订阅了值。update
阶段,它需要做的一切都是通过订阅完成的。if
或foreach
绑定触发器),我们的绑定也会清除订阅。我们称之为fadeDuringChange
:
ko.bindingHandlers.fadeDuringChange = {
init: function(element, valueAccessor) {
var value = valueAccessor();
var beforeChangeSubscription = value.subscribe(function () {
$(element).delay(200).fadeOut();
}, null, "beforeChange");
var afterChangeSubscription = value.subscribe(function () {
$(element).fadeIn();
});
// dispose of subscriptions when the DOM node goes away
// see http://knockoutjs.com/documentation/custom-bindings-disposal.html
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
// see http://knockoutjs.com/documentation/observables.html#explicitly-subscribing-to-observables
beforeChangeSubscription.dispose();
afterChangeSubscription.dispose();
});
}
};
用法与上述相同:
<div data-bind="fadeDuringChange: filteredUsers">
<!-- show filteredUsers... --->
</div>