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/

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


person user3647591    schedule 17.05.2014    source источник
comment
Не могли бы вы сделать образец jsfiddle, пожалуйста   -  person GSerjo    schedule 18.05.2014
comment
Не могли бы вы уточнить, что не работает? Выдает ошибки? Где возникает ошибка?   -  person PatrickSteele    schedule 18.05.2014
comment
jsfiddle.net/3EWVR/2   -  person user3647591    schedule 18.05.2014
comment
Например, когда я выбираю заказ/сумма/›=/8 и сохраняю его в JSON, я выбираю другие значения (например, клиент/адрес/вход из строки/0) и загружаю сохраненные модели данных из JSON, я ожидаю получить оригинал ввод (порядок/сумма/›=/8), но в выбранном элементе нет никаких значений, и он дублирует значения в списке выбора.   -  person user3647591    schedule 18.05.2014


Ответы (1)


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

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

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

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

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

в параметрах ko.mapping 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) } };

person Origineil    schedule 19.05.2014
comment
Я пытаюсь добавить параметры в свой пример, но это не работает. jsfiddle.net/3EWVR/8 . Можете ли вы объяснить, как применить параметры параметров ko.mapping для моего примера? - person user3647591; 23.05.2014