在Knockout

时间:2017-02-27 11:00:46

标签: javascript knockout.js observable

在Knockout中我有可观察变量location。它的类型为LocationEdit。此viewModel具有可观察而非字段。

我收集了字段名称:fields。对于每个字段,我想重置location

的值
fields.forEach(field => {
       if (this.uniqueField(locs, field)) {
           if (ko.isObservable(this.location()[field])) {
               this.location()[field](locs[0][field]);
           } else {
               this.location()[field] = locs[0][field];
           }
       }
});

为了使这段代码更简单(删除if-clauses),我能以某种方式在一行中将值设置为this.location()[field]吗?

2 个答案:

答案 0 :(得分:2)

您可以使用条件运算符(... ? ... : ... ;),尽管它没有太大变化:

fields.forEach(field => {
       if (this.uniqueField(locs, field)) {
           ko.isObservable(this.location()[field]) ? this.location()[field](locs[0][field]) : this.location()[field] = locs[0][field];
       }
});

或者你可以写一个函数:

function upd(arr, index, val) {
    ko.isObservable(arr[index]) ? arr[index](val) : arr[index] = val;
}

用法:

fields.forEach(field => {
       if (this.uniqueField(locs, field)) {
           upd(this.location(), field, locs[0][field]);
       }
});

请参阅 demo

您甚至可以将此功能添加到ko

if(typeof ko.updatePotentialObservable == 'undefined')
    ko.updatePotentialObservable = function (arr[index], val) {
        ko.isObservable(obj) ? arr[index](val) : arr[index]= val;
    }

用法:

fields.forEach(field => {
       if (this.uniqueField(locs, field)) {
           ko.updatePotentialObservable(this.location(), field, locs[0][field]);
       }
});

请参阅其他 demo

答案 1 :(得分:0)

说实话,我认为Gôtô的答案肯定是你最好的选择。基本上,您需要创建一个类似于ko.unwrap的效用函数,但设置一个值。

但是既然你说“也想找到另一个解决方案”,这里有一个不同的效用函数。我认为代码中最令人困惑的部分是对locs[0][field]this.location()[field]的回复。我想要一些有这个签名的东西:

reset(source, target, keys);

因此,在您的代码中,您可以这样做:

reset(
  this.location(), 
  locs[0], 
  fields.filter(f => this.uniqueField(locs, f))
);

现在,写这个方法,我最终得到了这个:

const mergePropsObs = (function() {
  // Return a method for setting a specific property in object
  const getSetter = obj => prop => ko.isObservable(obj[prop])
    ? obj[prop]
    : val => obj[prop] = val;
    
  // Return unique keys for two objects
  // (I went with a quick oneliner; there are many ways to do this)
  const allKeys = (obj1, obj2) => 
    Object.keys(Object.assign({}, obj1, obj2));

  return (base, ext, onlyProps) => {
    const props = onlyProps || allKeys(base, ext);
    const values = props.map(p => ko.unwrap(ext[p]));
    
    props
      .map(getSetter(base))
      .forEach((setter, i) => setter(values[i]));
  };
}());

var base = { a: 1, b: ko.observable(2), c: 5 };

mergePropsObs(
  base, 
  { a: 2, b: 3 },
  ["a", "b"]);
  
console.log(base.a);
console.log(base.b());
console.log(base.c);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

此实用程序方法可与上述签名一起使用。当您不提供字段名称数组时,它也有一个后备。