为啥我的 ko 计算 observable 在其值更改时不会更新绑定的 UI 元素?

Posted

技术标签:

【中文标题】为啥我的 ko 计算 observable 在其值更改时不会更新绑定的 UI 元素?【英文标题】:Why does my ko computed observable not update bound UI elements when its value changes?为什么我的 ko 计算 observable 在其值更改时不会更新绑定的 UI 元素? 【发布时间】:2012-04-06 13:04:00 【问题描述】:

我正在尝试将一个 cookie 包装在一个计算的 observable 中(我稍后会变成一个 protectedObservable),但我在计算 observable 时遇到了一些问题。我认为对计算出的 observable 的更改将被广播到任何绑定到它的 UI 元素。

我创建了the following fiddle

JavaScript

var viewModel = ;

// simulating a cookie store, this part isnt as important
var cookie = function ()   

    // simulating a value stored in cookies
    var privateZipcode = "12345";

    return 
        'write' : function (val)  privateZipcode = val; , 
        'read': function ()  return privateZipcode; 
    
();

viewModel.zipcode = ko.computed(
        read: function () 
            return cookie.read();
        ,
        write: function (value) 
            cookie.write(value);
        ,
        owner: viewModel
    );

ko.applyBindings(viewModel);?

HTML

zipcode:
<input type='text' data-bind="value: zipcode"> <br />

zipcode: 
<span data-bind="text: zipcode"></span>?

我没有使用 observable 来存储 privateZipcode,因为它实际上只是在 cookie 中。我希望ko.computed 将提供我需要的通知和绑定功能,尽管大多数examples I've seen 和ko.computed 最终在封面下使用ko.observable

将值写入我计算的 observable 的行为不应该向绑定到其值的 UI 元素发出信号吗?这些不应该更新吗?

解决方法

我有一个简单的解决方法,我只需在我的 cookie 存储旁边使用 ko.observable 并使用它会触发对我的 DOM 元素的所需更新,但这似乎完全没有必要,除非 ko.computed 缺少信号 / ko.observable 具有的依赖类型功能。

My workaround fiddle,你会注意到唯一改变的是我添加了一个不用作存储的seperateObservable,它的唯一目的是向 UI 发出底层数据已更改的信号。

// simulating a cookie store, this part isnt as important
var cookie = function ()   

    // simulating a value stored in cookies
    var privateZipcode = "12345";

    // extra observable that isnt really used as a store, just to trigger updates to the UI
    var seperateObservable = ko.observable(privateZipcode);

    return 
        'write' : function (val)  
            privateZipcode = val; 
            seperateObservable(val);
        , 
        'read': function ()  
            seperateObservable();
            return privateZipcode; 
        
    
();

这是有道理的,并且可以按我的预期工作,因为viewModel.zipcode 依赖于seperateObservable,并且对其进行更新应该(并且确实)通知 UI 进行更新。 我不明白, 是为什么我的ko.computed 上的write 函数调用没有通知UI 更新,因为该元素绑定到ko.computed

我怀疑我可能不得不在淘汰赛中使用某些东西来手动表示我的ko.computed 已更新,我对此很好,这是有道理的。我只是无法找到一种方法来实现这一点。

【问题讨论】:

【参考方案1】:

sigh,我找到了my exact same problem的人

如果dependentObservables 在写入时不通知订阅者,他们为什么要这样做 甚至懒得看书?它们被添加到 observables 列表中 并订阅了,但是他们永远不会触发更新。那么什么是 订阅它们的意义何在?

Ryan Niemeyer 答案:

我认为对于您的场景,dependentObservables 可能不是 适合工作的工具。设置dependentObservables 来检测 读取函数中的依赖关系,并在任何时候重新评估/通知 这些依赖项发生了变化。在可写的dependentObservable 中, write 函数实际上只是一个拦截写入并允许的地方 您可以设置任何必要的可观察值,以便您的读取功能 将返回正确的值(写通常与读相反 在大多数情况下,除非您正在转换值)。

对于您的情况,我个人会使用 observable 来表示 值,然后手动订阅该 observable 以更新 原始值(您可能无法控制的值)。

就像:http://jsfiddle.net/rniemeyer/Nn5TH/

所以看起来this fiddle 将是一个解决方案

var viewModel = ;

// simulating a cookie store, this part isnt as important
var cookie = function ()   

    // simulating a value stored in cookies
    var privateZipcode = "12345";

    return 
        'write' : function (val)  
            console.log("updated cookie value with: " + val);
            privateZipcode = val; 
        , 
        'read': function ()  
            return privateZipcode; 
        
    
();

viewModel.zipcode = ko.observable(cookie.read());

// manually update the cookie when the observable changes
viewModel.zipcode.subscribe(function(newValue) 
   cookie.write(newValue);   
);

ko.applyBindings(viewModel);​

这是有道理的,而且使用起来更简单。总的来说,我不确定将 cookie 视为可观察对象是多么棒的想法,因为服务器可以在 ajax 请求等中对其进行编辑。

【讨论】:

【参考方案2】:

尝试使您的内部私人邮政编码成为可观察的。见这里:http://jsfiddle.net/KodeKreachor/fAGes/9/

【讨论】:

它实际上是通过$.cookie.get()$.cookie.set() 写入/读取该值,在我的示例中通过cookie 模拟。除了我在ko.computed observable 中尝试做的事情之外,我没有能力让它成为可观察的。这个想法是ko.computed 将封装写入/读取cookie,这就是为什么我不喜欢使用subscribe 是的,但是如果您的 cookie 对象没有任何内在的东西可以被淘汰赛依赖跟踪系统跟踪,那么您可能不走运。如果您只是将内部 privateZipcode 设为可观察,那么您应该能够看到值更新。 所以 cookie 对象本身不是 observable,它只包含一个 observable,以便在写入时可以对其进行跟踪。 基本上你的建议与尼迈耶相同,我会为此 +1。他通过基本上说“将其存储在可观察对象中并订阅它”,更进一步(这就是我所要理解的)。通过这样做,它完全消除了拥有ko.computed 的需要。这是这两种方法的唯一区别。

以上是关于为啥我的 ko 计算 observable 在其值更改时不会更新绑定的 UI 元素?的主要内容,如果未能解决你的问题,请参考以下文章

KnockoutJS 查找 ko.observable() 长度

将 ko observables 组合成一个 ko observable 数组

计算的 observable 没有被执行

KnockoutJs - 计算数据库评级

如何将从 json 接收到的 ko.observable 字符串解析为整数(数字)值

计算的 observable 不更新