Knockout js: загрузить модель из JSON

У меня проблема с моей моделью. Я пытаюсь загрузить модель из JSON, но она не работает должным образом:(Я создал каскадные списки выбора. Когда я пытаюсь сохранить модель в JSON и после этого загрузить ее из сохраненного JSON, это вызывает неправильные значения выбора списки.

Вот моя привязка:

<div id="condition-template" type="text/html">
  <div class="condition">
    <select class="textbox1" 
            data-bind="options: entarea, 
                       optionsText : &apos;displayName&apos;,
                       value: selectedArea " ></select>
    <select class="textbox1" 
            data-bind="options: Selectedfields, 
                       optionsText : &apos;fieldDisplayName&apos;,
                       value: selectedField "></select>
    <select class="textbox1" 
            data-bind="options: Selectedcomparisons, 
                       optionsText : &apos;comparsionDisplayName&apos;,
                       value: selectedComparison "></select>    
    <input class="textbox1" type="text" data-bind="value: value"></input>
    <button data-bind='click: save'>Save to JSON</button>
    <button data-bind='click: loadModel'>AddModel</button>
</p>

    <textarea data-bind='value: lastSavedJson' rows='5' cols='60' > </textarea>
    <inner type = "textarea" id="t_test"></inner>
  </div>
</div>   

Моя модель:

function Condition() {
 var self = this;
 var sqlArea = function(sqlAreaId, displayName) {
     this.displayName = ko.observable(displayName);
     this.sqlAreaId = ko.observable(sqlAreaId);
 };
 var field = function(fieldId, fieldDisplayName, sqlAreaId, fieldType) {
     this.fieldId = ko.observable(fieldId);
     this.fieldDisplayName = ko.observable(fieldDisplayName);
     this.sqlAreaId = ko.observable(sqlAreaId);
     this.fieldType = ko.observable(fieldType);
 };
 var comparison = function(comparsionId, comparsionDisplayName, fieldType) {
     this.comparsionId = ko.observable(comparsionId);
     this.comparsionDisplayName = ko.observable(comparsionDisplayName);
     this.fieldType = ko.observable(fieldType);
 };
 self.templateName = "condition-template";
 self.entarea = ko.observableArray([new sqlArea(1, "Client"), 
                                    new sqlArea(2, "Order")]);
 self.selectedArea = ko.observable();
 self.fields = ko.observableArray([new field( 1, "Name", 1, 1), 
                                   new field( 2, "Address", 1, 1), 
                                   new field( 3, "Phone number", 1, 1), 
                                   new field( 4, "Manager", 1, 1), 
                                   new field( 5, "Type", 1, 2), 
                                   new field( 6, "Order number", 2, 2), 
                                   new field( 7, "Sum", 2, 2), 
                                   new field( 8, "Date", 2, 3)]); 
 self.selectedField = ko.observable();
 self.comparisons = ko.observableArray([new comparison( 1,">=", 2),
                                     new comparison( 2,">", 2),
                                    new comparison( 3,"<=", 3), 
                                    new comparison( 4,"IN from date", 3),
                                    new comparison( 5,"IN from string", 1)
                                  ]);
 self.selectedComparison = ko.observable();
 //------------------------------------------------------------------------
 //Cascading select list
 self.Selectedfields = ko.dependentObservable(function () {
   var area = self.selectedArea(), sqlAreaId;
   if (area) {
      sqlAreaId = area.sqlAreaId();
      return ko.utils.arrayFilter(self.fields(), function(field) {
          return field.sqlAreaId() === sqlAreaId;
      });
   }
   return [];
 }, self);

 self.Selectedcomparisons = ko.dependentObservable(function() {
     var field = self.selectedField(), fieldType;
     if (field) {
       fieldType = field.fieldType();
       return ko.utils.arrayFilter(self.comparisons(),function(comparison) {
           return comparison.fieldType() === fieldType;
       });
     }
     return [];
 }, self);
 //-----------------------------------------------------------------------
 self.value = ko.observable(0);

 self.save = function() {
    self.lastSavedJson(JSON.stringify( ko.mapping.toJS(self), null, 2));
    var test = document.getElementById('t_test');
    test.innerHTML = (JSON.stringify( ko.mapping.toJS(self), null, 2));
 };
 self.lastSavedJson = ko.observable("");    
 self.loadModel = function() {
    var test = document.getElementById('t_test');
    var data = JSON.parse(test.innerHTML);

     ko.mapping.fromJS(data, {}, self);
     /* var viewModel = {};
        viewModel.model = ko.mapping.fromJS(data, {}, self);
                    self.updateFromModel(self, viewModel.model);*/
 };
}
ko.applyBindings(new Condition());

ОБНОВЛЕНИЕ 1: http://jsfiddle.net/3EWVR/2/

Например, когда я выбираю order/sum/>=/8 и сохраняю его в JSON, я выбираю другие значения (например, client / address / in из строки / 0) и загружаю сохраненные модели данных из JSON, я ожидаю получить оригинал вход (order/sum/>=/8), но в элементе выбора нет никаких значений, и он дублирует значения в списке выбора.

1 ответ

Решение

Я полагаю, что корень проблемы заключается в некотором разделении ссылок на объекты. Примите к сведению различные сценарии, изображенные в этой скрипке.

  • Однако это базовое объяснение требует дальнейшего разъяснения, поскольку Order Модели вызовут дублирование в течение первого <select> в то время как Client моделей нет. Оба типа также вызовут дублирование во втором <select>,

  • Указанный индекс всегда равен [0], что объясняет, почему Client не дублирует Затронутый индекс 0 часть я еще не совсем понял.

По причинам, которые мне еще предстоит расследовать, указав update callback

  ko.mapping.fromJS( init, {
      'selectedArea': {
          update: function (options) {
              return options.data;
          }
      }
  }, new Condition())

в пределах карты options параметры, кажется, смягчают проблему.


Альтернативой было бы ввести optionsValue привязка и поиск объектов при необходимости с помощью функции ko.utils


редактировать

После более пристального взгляда на применение options в фактическом источнике против моего уменьшенного примера у меня все еще были некоторые проблемы со ссылками на объекты. Поэтому я применил свой альтернативный подход.

<select> элементы теперь используют optionsValue обязательный параметр. Единственное место, где это влияет на источник, находится в Selectedcomparisons, Вы должны найти поле для доступа к fieldType имущество.

var selectedField = ko.utils.arrayFirst(self.Selectedfields(), function (field) {
    return field.fieldId() === self.selectedField();
});

Другие соображения

  • Вы разбирали JSON а потом ko.mapping.fromJS на этом я изменил это

    ko.mapping.fromJSON(self.lastSavedJson(), options, self)

  • dependentObservables не может быть записано как определено, поэтому я пометил их как проигнорированные

    var options = {ignore: []} var propertyNames = Object.keys(self); for(index in propertyNames){ var property = propertyNames[index] if(ko.isComputed(self[property])){ options.ignore.push(property) } };

Другие вопросы по тегам