KnockoutJS 清除函数内的 Observable
KnockoutJS Clearing a Observable within function
我的 Razor 视图如下:
<div id="allMessages" data-bind="foreach: messages">
<!-- ko if: $root.filterMessageTime($data.MessageDate) -->
//Show some messages
<!-- /ko -->
</div>
<div data-bind="visible: lastHourCount() > 1 && selectedFilterMessageTime() == 'Last Hour'">
<p><span class="h4" data-bind="text: lastHourCount()"></span> messages in the <span class="h4">last hour</span>.</p>
</div>
<div data-bind="visible: lastHourCount() == 0 && selectedFilterMessageTime() == 'Last Hour'">
<p>No new messages in the <span class="h4">last hour</span>.</p>
</div>
我的Knockout功能如下:
function ViewModel() {
var self = this;
var count = 0;
self.lastHourCount = ko.observable(0);
self.lastDayCount = ko.observable(0);
self.lastWeekCount = ko.observable(0);
self.lastMonthCount = ko.observable(0);
self.filterMessageTime = function (MessageDate) {
//Reset Expression
if (count == self.messages().length) {
count = 0;
self.lastHourCount(0);
self.lastDayCount(0);
self.lastWeekCount(0);
self.lastMonthCount(0);
}
if (self.selectedFilterMessageTime() == 'Any' || self.selectedFilterMessageTime() == null) {
return true;
}
count = count + 1;
if (self.selectedFilterMessageTime() == 'Last Hour') {
if (((MessageDate.indexOf('minute') >= 0) || (MessageDate.indexOf('hour') >= 0)) && (MessageDate.indexOf('hours') == -1)) {
self.lastHourCount(self.lastHourCount() + 1);
return true;
}
else
return false;
}
else if (self.selectedFilterMessageTime() == 'Last Day') {
if (((MessageDate.indexOf('day') >= 0) || (MessageDate.indexOf('hours') >= 0) || (MessageDate.indexOf('hour') >= 0) || (MessageDate.indexOf('minute') >= 0)) && (MessageDate.indexOf('days') == -1)) {
self.lastDayCount(self.lastDayCount() + 1);
return true;
}
else
return false;
}
else if (self.selectedFilterMessageTime() == 'Last Week') {
if ((MessageDate.indexOf('days') >= 0) || (MessageDate.indexOf('day') >= 0) || (MessageDate.indexOf('hours') >= 0) || (MessageDate.indexOf('hour') >= 0) || (MessageDate.indexOf('minute') >= 0)) {
self.lastWeekCount(self.lastWeekCount() + 1);
return true;
}
else
return false;
}
else if (self.selectedFilterMessageTime() == 'Last Month') {
if ((MessageDate.indexOf('month') >= 0) || (MessageDate.indexOf('days') >= 0) || (MessageDate.indexOf('day') >= 0) || (MessageDate.indexOf('hours') >= 0) || (MessageDate.indexOf('hour') >= 0) || (MessageDate.indexOf('minute') >= 0)) {
self.lastMonthCount(self.lastMonthCount() + 1);
return true;
}
else
return false;
}
return false;
};
}
方法论:
对于我收到的每条用户消息,如果用户指定了过滤器,则:
- 根据传入的
MessageDate
计算该过滤器范围内的消息数量,并在可观察对象中提供它们,即 self.lastMonthCount()
将保存上个月的消息数量
- 当
count
达到消息总数时,我们希望重置计数以及可观察计数器,以便可观察计数不会翻转任何值。
问题:
似乎我对我的可观察对象有某种形式的循环依赖,因为当 运行 函数出现问题时,即 'reset' 表达式从未正确求值,而且似乎函数循环在 Observables 中有大量(大于消息的数量)。
备注:
- 当用常规变量替换 observables 时一切正常,在我看来自然没有数据绑定,这不好。
- 如果我在重置表达式中重新声明我的 Observables 那么它解决了我的问题,但是我之前绑定的 Observables 将不会从新创建的 Observables 接收更新,同样不好。
- 我还尝试将 Observables 设置为
null
和 undefinied
。
你做错了。
如果您有一个包含对象列表的视图模型并且您想让它们可过滤,您需要做的就是
- 添加一个包含活动过滤条件的可观察对象
- 添加一个包含过滤列表的计算
- 您的观点完全基于过滤列表
接下来的就自然而然了
function ViewModel() {
var self = this;
self.availableFilters = ['any', 'last hour', 'last day', 'last week', 'last month'];
self.activeFilter = ko.observable(self.availableFilters[0]);
self.allMessages = ko.observableArray([/* ... fill this ... */]);
self.filteredMessages = ko.pureComputed(function () {
return self.filterMessages(self.activeFilter());
});
self.filteredMessagesCount = ko.pureComputed(function () {
return self.filteredMessages().length;
});
self.filterMessages = function (filter) {
return ko.utils.arrayFilter(self.allMessages(), function (message) {
var d = message.Date();
switch (filter) {
case 'any': return true;
case 'last hour': return (d.indexOf('minute') >= 0 || d.indexOf('hour') >= 0) && d.indexOf('hours') == -1;
case 'last day': return (d.indexOf('day') >= 0 || d.indexOf('hours') >= 0 || d.indexOf('hour') >= 0 || d.indexOf('minute') >= 0) && d.indexOf('days') == -1;
case 'last week': return d.indexOf('days') >= 0 || d.indexOf('day') >= 0 || d.indexOf('hours') >= 0 || d.indexOf('hour') >= 0 || d.indexOf('minute') >= 0;
case 'last month': return d.indexOf('month') >= 0 || d.indexOf('days') >= 0 || d.indexOf('day') >= 0 || d.indexOf('hours') >= 0 || d.indexOf('hour') >= 0 || d.indexOf('minute') >= 0;
default: return false;
}
});
};
}
和
<select data-bind="options: availableFilters, value: activeFilter"></select>
<div id="allMessages" data-bind="foreach: filteredMessages">
// show the message
</div>
<div>
<p>
<!-- ko if: filteredMessagesCount -->
<span class="h4" data-bind="text: filteredMessagesCount"></span> messages
<!-- /ko -->
<!-- ko ifnot: filteredMessagesCount -->
No new messages
<!-- /ko -->
<!-- ko ifnot: activeFilter() === 'any' -->
in the <span class="h4" data-bind="text: activeFilter"></span>
<!-- /ko -->
</p>
</div>
也就是说,您过滤消息的方法(通过多次 indexOf()
调用)不是很漂亮。
基于正则表达式的怎么样:
function ViewModel() {
var self = this;
self.availableFilters = [
{name: 'any', include: /./, exclude: null},
{name: 'last hour', include: /minutes?|hour/i, exclude: /hours|days?|weeks?|months?/i},
{name: 'last day', include: /minutes?|hours?|day/i, exclude: /days|weeks?|months?/i},
{name: 'last week', include: /minutes?|hours?|days?|week/i, exclude: /weeks|months?/i},
{name: 'last month', include: /minutes?|hours?|days?|weeks?|month/i, exclude: /months/i}
];
self.activeFilter = ko.observable(self.availableFilters[0]);
self.allMessages = ko.observableArray([/* ... fill this ... */]);
self.filteredMessages = ko.pureComputed(function () {
return self.filterMessages(self.activeFilter());
});
self.filteredMessagesCount = ko.pureComputed(function () {
return self.filteredMessages().length;
});
self.filterMessages = function (filter) {
return ko.utils.arrayFilter(self.allMessages(), function (message) {
var d = message.Date();
return filter.include && filter.include.test(d) &&
!(filter.exclude && filter.exclude.test(d));
});
};
}
和
<select
data-bind="options: availableFilters, optionsText: 'name', value: activeFilter"
></select>
视图的其余部分相同,只是对 activeFilter()
的引用必须更改为 activeFilter().name
。
我的 Razor 视图如下:
<div id="allMessages" data-bind="foreach: messages">
<!-- ko if: $root.filterMessageTime($data.MessageDate) -->
//Show some messages
<!-- /ko -->
</div>
<div data-bind="visible: lastHourCount() > 1 && selectedFilterMessageTime() == 'Last Hour'">
<p><span class="h4" data-bind="text: lastHourCount()"></span> messages in the <span class="h4">last hour</span>.</p>
</div>
<div data-bind="visible: lastHourCount() == 0 && selectedFilterMessageTime() == 'Last Hour'">
<p>No new messages in the <span class="h4">last hour</span>.</p>
</div>
我的Knockout功能如下:
function ViewModel() {
var self = this;
var count = 0;
self.lastHourCount = ko.observable(0);
self.lastDayCount = ko.observable(0);
self.lastWeekCount = ko.observable(0);
self.lastMonthCount = ko.observable(0);
self.filterMessageTime = function (MessageDate) {
//Reset Expression
if (count == self.messages().length) {
count = 0;
self.lastHourCount(0);
self.lastDayCount(0);
self.lastWeekCount(0);
self.lastMonthCount(0);
}
if (self.selectedFilterMessageTime() == 'Any' || self.selectedFilterMessageTime() == null) {
return true;
}
count = count + 1;
if (self.selectedFilterMessageTime() == 'Last Hour') {
if (((MessageDate.indexOf('minute') >= 0) || (MessageDate.indexOf('hour') >= 0)) && (MessageDate.indexOf('hours') == -1)) {
self.lastHourCount(self.lastHourCount() + 1);
return true;
}
else
return false;
}
else if (self.selectedFilterMessageTime() == 'Last Day') {
if (((MessageDate.indexOf('day') >= 0) || (MessageDate.indexOf('hours') >= 0) || (MessageDate.indexOf('hour') >= 0) || (MessageDate.indexOf('minute') >= 0)) && (MessageDate.indexOf('days') == -1)) {
self.lastDayCount(self.lastDayCount() + 1);
return true;
}
else
return false;
}
else if (self.selectedFilterMessageTime() == 'Last Week') {
if ((MessageDate.indexOf('days') >= 0) || (MessageDate.indexOf('day') >= 0) || (MessageDate.indexOf('hours') >= 0) || (MessageDate.indexOf('hour') >= 0) || (MessageDate.indexOf('minute') >= 0)) {
self.lastWeekCount(self.lastWeekCount() + 1);
return true;
}
else
return false;
}
else if (self.selectedFilterMessageTime() == 'Last Month') {
if ((MessageDate.indexOf('month') >= 0) || (MessageDate.indexOf('days') >= 0) || (MessageDate.indexOf('day') >= 0) || (MessageDate.indexOf('hours') >= 0) || (MessageDate.indexOf('hour') >= 0) || (MessageDate.indexOf('minute') >= 0)) {
self.lastMonthCount(self.lastMonthCount() + 1);
return true;
}
else
return false;
}
return false;
};
}
方法论:
对于我收到的每条用户消息,如果用户指定了过滤器,则:
- 根据传入的
MessageDate
计算该过滤器范围内的消息数量,并在可观察对象中提供它们,即self.lastMonthCount()
将保存上个月的消息数量 - 当
count
达到消息总数时,我们希望重置计数以及可观察计数器,以便可观察计数不会翻转任何值。
问题:
似乎我对我的可观察对象有某种形式的循环依赖,因为当 运行 函数出现问题时,即 'reset' 表达式从未正确求值,而且似乎函数循环在 Observables 中有大量(大于消息的数量)。
备注:
- 当用常规变量替换 observables 时一切正常,在我看来自然没有数据绑定,这不好。
- 如果我在重置表达式中重新声明我的 Observables 那么它解决了我的问题,但是我之前绑定的 Observables 将不会从新创建的 Observables 接收更新,同样不好。
- 我还尝试将 Observables 设置为
null
和undefinied
。
你做错了。
如果您有一个包含对象列表的视图模型并且您想让它们可过滤,您需要做的就是
- 添加一个包含活动过滤条件的可观察对象
- 添加一个包含过滤列表的计算
- 您的观点完全基于过滤列表
接下来的就自然而然了
function ViewModel() {
var self = this;
self.availableFilters = ['any', 'last hour', 'last day', 'last week', 'last month'];
self.activeFilter = ko.observable(self.availableFilters[0]);
self.allMessages = ko.observableArray([/* ... fill this ... */]);
self.filteredMessages = ko.pureComputed(function () {
return self.filterMessages(self.activeFilter());
});
self.filteredMessagesCount = ko.pureComputed(function () {
return self.filteredMessages().length;
});
self.filterMessages = function (filter) {
return ko.utils.arrayFilter(self.allMessages(), function (message) {
var d = message.Date();
switch (filter) {
case 'any': return true;
case 'last hour': return (d.indexOf('minute') >= 0 || d.indexOf('hour') >= 0) && d.indexOf('hours') == -1;
case 'last day': return (d.indexOf('day') >= 0 || d.indexOf('hours') >= 0 || d.indexOf('hour') >= 0 || d.indexOf('minute') >= 0) && d.indexOf('days') == -1;
case 'last week': return d.indexOf('days') >= 0 || d.indexOf('day') >= 0 || d.indexOf('hours') >= 0 || d.indexOf('hour') >= 0 || d.indexOf('minute') >= 0;
case 'last month': return d.indexOf('month') >= 0 || d.indexOf('days') >= 0 || d.indexOf('day') >= 0 || d.indexOf('hours') >= 0 || d.indexOf('hour') >= 0 || d.indexOf('minute') >= 0;
default: return false;
}
});
};
}
和
<select data-bind="options: availableFilters, value: activeFilter"></select>
<div id="allMessages" data-bind="foreach: filteredMessages">
// show the message
</div>
<div>
<p>
<!-- ko if: filteredMessagesCount -->
<span class="h4" data-bind="text: filteredMessagesCount"></span> messages
<!-- /ko -->
<!-- ko ifnot: filteredMessagesCount -->
No new messages
<!-- /ko -->
<!-- ko ifnot: activeFilter() === 'any' -->
in the <span class="h4" data-bind="text: activeFilter"></span>
<!-- /ko -->
</p>
</div>
也就是说,您过滤消息的方法(通过多次 indexOf()
调用)不是很漂亮。
基于正则表达式的怎么样:
function ViewModel() {
var self = this;
self.availableFilters = [
{name: 'any', include: /./, exclude: null},
{name: 'last hour', include: /minutes?|hour/i, exclude: /hours|days?|weeks?|months?/i},
{name: 'last day', include: /minutes?|hours?|day/i, exclude: /days|weeks?|months?/i},
{name: 'last week', include: /minutes?|hours?|days?|week/i, exclude: /weeks|months?/i},
{name: 'last month', include: /minutes?|hours?|days?|weeks?|month/i, exclude: /months/i}
];
self.activeFilter = ko.observable(self.availableFilters[0]);
self.allMessages = ko.observableArray([/* ... fill this ... */]);
self.filteredMessages = ko.pureComputed(function () {
return self.filterMessages(self.activeFilter());
});
self.filteredMessagesCount = ko.pureComputed(function () {
return self.filteredMessages().length;
});
self.filterMessages = function (filter) {
return ko.utils.arrayFilter(self.allMessages(), function (message) {
var d = message.Date();
return filter.include && filter.include.test(d) &&
!(filter.exclude && filter.exclude.test(d));
});
};
}
和
<select
data-bind="options: availableFilters, optionsText: 'name', value: activeFilter"
></select>
视图的其余部分相同,只是对 activeFilter()
的引用必须更改为 activeFilter().name
。