knockout.js如何在ko.computed写入中取消confirm()后设置所选选项

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了knockout.js如何在ko.computed写入中取消confirm()后设置所选选项相关的知识,希望对你有一定的参考价值。

我有一个带选项和默认文本的选择器元素:

self._selected = ko.observable();
self.option = ko.computed({
    read:function(){
        return self._selected;
    },
    write: function(data){
        if(data){
            if(confirm('are you sure?')){
                self._selected(data);
            }else{
                //reset
            }
        }
    }
});

<select data-bind="options: options, value:option, optionsCaption: 'choose ...'"></select>

这个问题:

  • 选择“一个”
  • 在确认点击取消
  • 所选选项仍然是“一个”仍在焦点下

它应该是“选择......”

jsbin here,仅在镀铬上进行了测试

答案

这里存在不对称性:

当您更改选择框的值时,DOM会立即更新并随后进行淘汰(当然,淘汰赛取决于DOM更改事件)。因此,当您的代码询问“您确定吗?”时,DOM已经具有新值。

现在,当您不将该值写入绑定到value:的observable时,viewmodel的状态不会更改。并且当可观察到的更改时,knockout仅更新DOM。因此DOM保持在选定的值,并且viewmodel中的绑定值是不同的。


最简单的方法是将旧值保存在变量中,始终将新值写入observable,如果用户单击“否”,则只需恢复旧值。这样就破坏了不对称性,DOM和视图模型保持同步。

var AppData = function(params) {
    var self = {};
    var selected = ko.observable();
    
    self.options = ko.observableArray(params.options);  
    self.option = ko.computed({
        read: selected,
        write: function(value) {
            var oldValue = selected();
            selected(value);
            if (value !== oldValue && !confirm('are you sure?')) {
                selected(oldValue);
            }
        }
    });
  
    return self;
};

// ----------------------------------------------------------------------
ko.applyBindings(new AppData({
  options: ['one','two','three']
}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<select data-bind="options: options, value: option, optionsCaption: 'Select...'"></select>

<hr>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
另一答案

问题是底层变量的值没有变化,因此没有事件告诉Knockout它的value与viewmodel不同步。

使用正常的可观察量,你可以调用valueHasMutated来表示发生了一些隐匿性变化,但计算结果似乎没有。但他们确实有notifySubscribers。事实上,你的例子非常像this example in the docs

这是一个有效的例子:

function vm() {
  const self = {};

  self.options = ko.observableArray(['one', 'two', 'three']);
  self._selected = ko.observable();
  self.option = ko.pureComputed({
    read: self._selected,
    write: function(data) {
      if (data) {
        if (confirm('are you sure?')) {
          self._selected(data);
        } else {
          self.option.notifySubscribers(self._selected());
        }
      }
    }
  });

  return self;
}

ko.applyBindings(vm());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select data-bind="options: options, value:option, optionsCaption: 'choose ...'"></select>
<div data-bind="text:_selected"></div>
<div data-bind="text:option"></div>

以上是关于knockout.js如何在ko.computed写入中取消confirm()后设置所选选项的主要内容,如果未能解决你的问题,请参考以下文章

如何创建双向 ko.computed() 数组过滤器

在 knout.js 中遍历 observablearray 时,如何检索 foreach 的 ko.computed 运行总和

淘汰赛 - 将值写入 ko.computed

淘汰赛无法使用函数代替 ko.computed()

Typescript 类继承:覆盖 ko.computed 方法

如何在 Knockout.js 中嵌套对象