简体   繁体   English

为什么以这种方式更改此格式 function 会导致 Knockout 绑定开始工作?

[英]Why did changing this formatting function in this way, cause the Knockout binding to start working?

I have an element on a page, like this:我在页面上有一个元素,如下所示:

<span data-bind="text: FormattedCountOfPeople"></span>

And the function that calculates it I first wrote like this:而计算它的 function 我首先这样写:

self.FormattedCountOfPeople = ko.computed(function () {
    if(!self.PeopleCountFormatString)                 //a string like "{0} people in the conference", but set by a service call so starts out undefined
      return "not set yet";

    let sizes = self.Params().PermittedCounts();      //an array of discrete permitted sizes e.g. [2, 10, 30]
    let size = self.Params().ChosenCount();           //value set by a jquery slider, could be any double, even 5.7435 - to achieve smooth dragging of the slider it has a small step but snaps to a permitted count
    let n = nearest(size, sizes);                     //a "round to nearest" helper function that given args of e.g. (5.7345, [2, 10, 30]) will pick 2 because 5.7345 is nearer to 2 than 10
    let s = self.PeopleCountFormatString.csFormat(n); //csformat is a helper function that performs C# style string Formatting e.g. "{0} people".csFormat(2) -> "2 people"
    return s;
});

And I went round in circles for hours wondering why the text on the page just jammed at "not set yet" no matter what the slider setting was, but another element that was <span data-bind="text: Params().ChosenCount"></span> added as a test, was updating perfectly and elsewhere a different slider was setting an hours and minutes duration just fine, using a similar logic:我转了几个小时想知道为什么页面上的文本只是卡在“尚未设置”,不管 slider 设置是什么,但另一个元素是<span data-bind="text: Params().ChosenCount"></span>作为测试添加,正在完美更新,在其他地方,不同的 slider 使用类似的逻辑设置了小时和分钟的持续时间:

//if the user picks 61.2345, it rounds to 60, then returns "1 hour". Picking 74.11 rounds to 75 then returns "1 hour, 15 min"
self.FormattedDurationText = ko.computed(function () {
    var duration = self.Params().ChosenDuration();  
    duration = Math.round(duration / 15) * 15;

    if (Math.floor(duration / 60) > 0)
        var hours = self.DurationTextHours.csFormat(Math.floor(duration / 60));
    if (duration % 60 > 0)
        var minutes = self.DurationTextMinutes.csFormat(duration % 60);
    if (minutes && hours)
        return self.DurationTextLayout.csFormat(hours, minutes)
    if (hours && !minutes)
        return hours;
    if (!hours && minutes)
        return minutes;
    return "";
});

Adding some console logging in various places it became apparent that after the first invocation of FormattedCountOfPeople that returned "not set yet", the FormattedCountOfPeople was never being called again when dragging the people count slider.在不同的地方添加一些控制台日志,很明显,在第一次调用返回“尚未设置”的FormattedCountOfPeople之后,在拖动人数 slider 时再也没有调用FormattedCountOfPeople The other span, bound straight to the raw Params().ChosenCount would update continually, so the value was changing ok.直接绑定到原始Params().ChosenCount的另一个跨度将不断更新,因此值变化正常。 Similarly the slider bound to Params().ChosenDuration was updating the value, and FormattedDuration() was being called every time the value changed and providing a new formatted string to go in the span同样,绑定到Params().ChosenDuration的 slider 正在更新该值,并且每次值更改时都会调用FormattedDuration()并向跨度中的 go 提供新的格式化字符串

In the end, the code change that made things work seems incredibly inconsequential.最后,使事情正常进行的代码更改似乎非常无关紧要。 I dropped the initial if and swapped it for an inline conditional:我放弃了最初的if并将其换成内联条件:

self.FormattedCountOfPeople = ko.computed(function () {
    let sizes = self.Params().PermittedCounts();
    let size = self.Params().ChosenCount();
    let n = nearest(size, sizes); 
    let s = (self.PeopleCountFormatString ? self.PeopleCountFormatString: "not set yet").csFormat(n); 
    return s;

Why did making this change suddenly mean that knockout started calling FormattedCountOfPeople every time the value changed?为什么做这个改变突然意味着每次值改变时,淘汰赛都开始调用FormattedCountOfPeople The only thing I can see that really differs is that FormattedDurationText is structured such that it always calls eg Params().ChosenDuration() before deciding the values are no good and returns "" whereas the first version of FormattedCountOfPeople had a behavior that occasionally decided not to call anything and the second version always calls.我能看到的唯一真正不同的是FormattedDurationText的结构使得它总是在决定值不好之前调用例如Params().ChosenDuration()并返回"" ,而FormattedCountOfPeople的第一个版本有一个偶尔决定的行为不要调用任何东西,第二个版本总是调用。 Is there a side effect to calling Params().Xxx() such as "resetting a flag", and if the flag is never reset, knockout never calls the function again even if the value changes?调用Params().Xxx()是否有副作用,例如“重置标志”,如果标志从未重置,即使值发生变化,淘汰赛也不会再次调用 function?

When you reference an observable in a computed, KO will internally subscribe to that observable, so the computed is re-evaluated every time the observable changes.当您在计算中引用一个可观察对象时,KO 将在内部订阅该可观察对象,因此每次可观察对象更改时都会重新评估计算对象。

When you do this right at the start of the computed:当您在计算开始时执行此操作时:

if(!self.PeopleCountFormatString)
  return "not set yet";

And self.PeopleCountFormatString isn't an observable (which it doesn't appear to be), your computed isn't evaluated any further because of the return statement, the subscription to ChosenCount never happens and because PeopleCountFormatString itself isn't an observable either, the computed is not re-evaluated later on when PeopleCountFormatString does have a value.而且self.PeopleCountFormatString不是可观察的(它似乎不是),由于 return 语句,您的计算不会进一步评估,对ChosenCount的订阅永远不会发生,因为PeopleCountFormatString本身也不是可观察的,当PeopleCountFormatString确实有值时,计算后不会重新评估。 Hence, its value will forever stay "not set yet".因此,它的价值将永远保持“尚未设定”。

The updated computed works because you reference the other observables immediately, so internally KO will subscribe to those and re-evaluate the computed whenever the observables change.更新后的计算有效,因为您立即引用其他可观察值,因此在内部 KO 将订阅那些并在可观察值更改时重新评估计算值。

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

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