简体   繁体   English

KnockoutJS清除函数中的Observable

[英]KnockoutJS Clearing a Observable within function

My Razor View is as follows: 我的剃刀视图如下:

<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>

My Knockout function is as follows: 我的淘汰赛功能如下:

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;
    };
}

Methodology: 方法:

For each user message that I have, if a user specifies a filter then: 对于我拥有的每条用户消息,如果用户指定过滤器,则:

  1. Count the number of messages in that filter range based on the passed in MessageDate and have them available in an observable, ie self.lastMonthCount() will hold the amount of messages in the last month 根据传入的MessageDate计算该过滤器范围内的消息数,并以可观察的方式使它们可用,即self.lastMonthCount()将保存上个月的消息量
  2. When the count reaches the total amount of messages we would like to reset the count as well as the observable counters so that the observable counts don't roll over any values. count达到消息总数时,我们希望重置计数以及可观察的计数器,以使可观察的计数不会超过任何值。

Problem: 问题:

It seems as though I have some form of circular dependencies on my observables as there are issues when running the function ie the 'reset' expression never properly evaluates and it seems as though the function loops with an large number (greater than the amount of messages) in the Observables. 好像我对可观察对象有某种形式的循环依赖关系,因为在运行函数时存在问题,即“ reset”表达式永远无法正确求值,并且似乎函数循环次数大(大于消息量) )中。

Notes: 笔记:

  • When replacing the observables with regular variables everything works fine, naturally I have no data-binds in my view which is no good. 当用常规变量替换可观察对象时,一切正常,自然地,我认为没有数据绑定是不好的。
  • If I re-declare my Observables in the reset expression then it solves my issues but again my previously bound Observables will not receive updates from the newly created Observables, again no good. 如果我在重置表达式中重新声明了我的Observable,那么它解决了我的问题,但是我以前绑定的Observable仍然不会收到来自新创建的Observable的更新,同样也没有好处。
  • I have also tried setting the Observables to null and undefinied . 我还尝试将Observables设置为nullundefinied

You are doing this the wrong way around. 您这样做的方式错误。

If you have a view model with a list of objects and you want to make them filterable, all you need to do is 如果您有一个带有对象列表的视图模型,并且想使其成为可过滤对象,那么您要做的就是

  • add an observable that holds the active filter condition 添加一个包含活动过滤条件的observable
  • add a computed that holds the filtered list 添加一个包含过滤列表的计算式
  • base your view entirely on the filtered list 将视图完全基于过滤后的列表

The rest will follow naturally. 其余的自然而然。

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;
            }
        });
    };
}

and

<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>

That being said, your method of filtering messages (via multiple indexOf() calls) isn't very pretty. 话虽这么说,您过滤消息的方法(通过多个indexOf()调用)不是很漂亮。

How about a regex-based one: 如何基于正则表达式的:

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));
        });
    };
}

and

<select 
    data-bind="options: availableFilters, optionsText: 'name', value: activeFilter"
></select>

The rest of the view is the same, except that references to activeFilter() must change to activeFilter().name . 视图的其余部分相同,除了对activeFilter()引用必须更改为activeFilter().name

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM