Knockout.js:如何动态地将字段绑定到对象的属性,而该对象又是兄弟姐妹的数组

时间:2015-10-08 21:27:41

标签: javascript knockout.js

我正在构建一个HTML页面,它从REST Api发送和获取数据(作为SPA的一部分)。

对于特定实体,应该可以用多种语言创建其内容(语言数量可由用户改变)。

让我们想象一个具有一个字段的实体:" Field1"。我希望能够在GUI中为不同语言输入Field1的值,然后将REST Api发送回这些实体的JSON数组。

我们的想法是拥有一个语言选择器和一个可以为每种语言重用的表单。此表单的Field1应绑定到包含语言和Field1值的可观察对象。数组会保存这些对象。

以下小提琴显示我所做的事情并且按预期工作(数组相应更新)。 但作为Knockout的初学者,我觉得我的解决方案真的不是最好的......

http://jsfiddle.net/rtacsltng/sb4ws0dj/(小提琴代码也在下面添加)

特别是,为了更新数组(elementArray),我已经订阅了Field1,但我觉得可能有一种更优雅/更有效的方法。

另外,另一个问题是:我还没有将elementArray声明为可观察的,因为我只对"观察"它的元素。是不是?

最后,为了增加复杂性,请注意在最终版本中,字段将通过自定义绑定声明(请参阅Material Design Lite: How to programatically reset a floating label input text,其中Roy J很好地解释了我如何操作)。您是否认为可以将此自定义绑定集成到整体"机制"?

提前感谢您的帮助!

HTML

Please choose a language first (en = English, sp = Spanish)
<br>
<br>
<form>
    <select data-bind="
                        options: availableLangs,
                        optionsCaption: 'Choose Language',
                        value: chosenLang;
                    "></select>
    <input type="text" id="field1" data-bind="value: field1, valueUpdate: 'keypress'" />
</form>
<br>Value of Field in English: <span data-bind="text: elementArray[0].elementField1"></span>

<br>Value of Field in Spanish: <span data-bind="text: elementArray[1].elementField1"></span>

JS

function EditableElement(lang) {
    var self = this;
    self.elementLang = lang;
    self.elementField1 = ko.observable();
}

function MyViewModel() {
    var self = this;

    self.availableLangs = [ //Available languages
    "en",
        "sp"];

    self.field1 = ko.observable("");

    self.field1.subscribe(function (newValue) {
        self.elementArray[self.chosenLangIndex()].elementField1(newValue);
    });


    self.elementArray = [];
    for (var i = 0, arrLength = self.availableLangs.length; i < arrLength; i++) {
        self.elementArray.push(new EditableElement(self.availableLangs[i]));
    }

    self.chosenLang = ko.observable("");
    self.chosenLangIndex = ko.observable("");
    self.chosenLang.subscribe(function (newValue) {
        self.chosenLangIndex(self.availableLangs.indexOf(newValue));
        self.field1("");
    });
}

var vm = new MyViewModel();

ko.applyBindings(vm);

1 个答案:

答案 0 :(得分:0)

完全更新

现在我明白了你要做的事情,让我们完全不同地做到这一点!输入字段现在是依赖字段:根据选择的语言,它会读取/写入您要保存的值之一。

我充实了availableLanguages结构,然后制作了一个由语言代码索引的savedValues字典。输入字段是可写的计算机,它根据所选语言选择一个savedValues条目。更改语言时不清除字段,它会自动设置为在适当位置保存的内容。

当没有选择任何语言时,我也隐藏了该字段,因为它不会映射到任何语言。

function MyViewModel() {
  var self = this;

  //Available languages
  self.availableLangs = [{
    code: "en",
    name: 'English'
  }, {
    code: "sp",
    name: 'Spanish'
  }];

  self.chosenLang = ko.observable("");

  self.savedValues = {};

  ko.utils.arrayForEach(self.availableLangs, function(langInfo) {
    self.savedValues[langInfo.code] = ko.observable();
  });

  self.saveValue = ko.computed({
    read: function() {
      var lang = self.chosenLang();
      return lang ? self.savedValues[lang]() : '';
    },
    write: function(newValue) {
      var lang = self.chosenLang();
      if (lang) {
        self.savedValues[lang](newValue);
      }
    }
  });
}

var vm = new MyViewModel();

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
Please choose a language first (en = English, sp = Spanish)
<br>
<br>
<form>
  <select data-bind="options: availableLangs,
                     optionsCaption: 'Choose Language',
                     optionsText: 'name',
                     optionsValue: 'code',
                     value: chosenLang;
                    "></select>
  <input type="text" id="field1" data-bind="value: saveValue, valueUpdate: 'input', visible: chosenLang" />
</form>
<div data-bind="foreach: availableLangs">
  <br>Value of Field in <span data-bind="text:name"></span>: <span data-bind="text: $parent.savedValues[code]()"></span>
</div>