нокаутировать вложенные наблюдаемые с помощью контроллера представления

Мы рефакторим наш клиентский код и реализуем модели представления. Я хотел бы, чтобы наши модели представления были как можно более тупыми, чтобы они были исключительно представлениями данных.

Мы будем использовать контроллер представления и публикацию/подписку, чтобы получать свежие данные для виртуальной машины по мере необходимости, и просто помещать данные в модель представления в модели односторонней иерархии данных, похожей на то, как компоненты взаимодействуют в Vue.

Для плоских свойств модели просмотра этот подход отлично работает, используя функцию «Props», но в случае вложенных наблюдаемых, таких как адрес, я теряю наблюдаемые (конечно).

var model = function() {
  var self = this;
  self.name = ko.observable();
  self.occupation= ko.observable();
  self.address = ko.observable({
    street: ko.observable('Streetname'),
    zip: ko.observable('Zipcode')
  });

  self.doUpdate = function() {
      self.props({name: 'Tom', address: {street:'NewStreet'}});
  };
  self.props = function(data) {
    var viewmodel = self;
    for (p in data) {
      if (self[p]) {
        self[p](data[p]);
      }
    }
  };
}

ko.applyBindings(new model());

я не могу пройти

self.props({name: 'Tom', address: {street:ko.observable('NewStreet')}});

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

Альтернативой, о которой я думал, было просто использование функции сопоставления ko, но это требует немного большего интеллекта в моей функции Props, где я бы сделал что-то вроде

if(self['mapping_' + p]){
  //If self.mapping_address() exists, use that to 
  //create mapped observables...
}else if(self[p]){}...

Мне было бы удобно с этим, но это кажется немного неуклюжим. Есть ли лучший способ поддерживать вложенные наблюдаемые объекты при передаче иерархических данных из службы или контроллера?


person monkeydeus    schedule 19.05.2019    source источник


Ответы (1)


Я так понимаю, у вас есть собственная реализация ajax(get/post), завернутая в небольшую библиотеку, что мы делаем, так это то, что у нас есть собственный xhrObject(jqXHR), который возвращает обещание, прежде чем мы разрешим отложенное выполнение этого обещания, мы можем выбрать, будем ли мы измените свойства на наблюдаемые или нет, чтобы реализации модели представления не приходилось иметь дело с преобразованием каждого вызова API.

Вот небольшая штука, чтобы помочь вам, надеюсь, это поможет

//fakedata
var $stub = {
  id: 'foo',
  name: 'bar',
  complex: {
    name: 'test'
  }
};
//fakeapi
var $fakeAsync = function(api, result) {
  var dfd = $.Deferred(function() {
    setTimeout(function() {
      dfd.resolve(result);
    }, 100);
  });
  return dfd.promise();
};
//ajaxlib
var $ajaxlib = new function() {
  var self = this;
  //normal json object
  self.getAsJson = function(api) {
    return $fakeAsync(api, $stub);
  };
  //everything changed to observables before returning
  self.getAsObservable = function(api) {
    var dfd = $.Deferred();
    $fakeAsync(api, $stub).done(function(result) {
      var propNames = [];
      for (var prop in result) {
        propNames.push(prop);
      }
      mappedResult = ko.mapping.fromJS(result);
      $.each(propNames, function(index, propName) {
        if (_.isObject(mappedResult[propName]) && !_.isFunction(mappedResult[propName])) {
          var obj = mappedResult[propName];
          mappedResult[propName] = ko.observable(obj);
        }
      });

      dfd.resolve(mappedResult);
    });
    return dfd;
  };
};
//viewmodel
ko.applyBindings(() => {
  var self = this;

  self.json = ko.observable();
  self.obse = ko.observable();

  self.init = function() {
    $ajaxlib.getAsJson('/api/fake/1').done((result) => {
      self.json(result)
    });
    $ajaxlib.getAsObservable('/api/fake/1').done((result) => {
      self.obse(result)
    });
  };
  self.init();
});
div {
  padding: 5px;
  border: 1px solid #555;
  margin: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<div>
  <!-- ko with: json -->
  <!-- ko with: complex -->
  json: <span data-bind="text: name"></span>
  <br />(isObservable: <span data-bind="text: ko.isObservable(name)"></span>)
  <br /><input type="text" data-bind="textInput: name" />
  <!-- /ko -->
  <!-- /ko -->
</div>
<div>
  <!-- ko with: obse -->
  <!-- ko with: complex -->
  observable: <span data-bind="text: name"></span>
  <br />(isObservable: <span data-bind="text: ko.isObservable(name)"></span>)
  <br /><input type="text" data-bind="textInput: name" />
  <!-- /ko -->
  <!-- /ko -->
</div>

person Sam    schedule 21.05.2019