2015-10-23 4 views
0

Я начинаю вторую попытку создания приложения с KO, поэтому, пока я чувствую, что мое понимание библиотеки проходимо, мое выполнение с использованием этого по-прежнему требует работы. У меня вопрос о сложной модели для представления, которое не представляет собой только один логический объект.Complex KnockoutJS View Model

Учитывая сложный или составной вид модели, где свойства основного ViewModel сами являются объектами:

var mainViewModel = function(data){ 
    var self=this; 
    self.user = new UserModel(); 
    self.roles = new RolesCollectionModel(); 
} 

function UserModel(data){ 
    var self=this; 
    self.Name = ko.observable(data.name); 
} 

function RolesCollectionModel(data){ 
    var self=this; 
    self.Items = ko.observableArray(data.items); 
} 

Мне кажется, что KO признает только связывание на первом уровне свойств, что не существует «наблюдаемым пузыриться. Таким образом, для меня, чтобы использовать данные, обязательные для дочерних объектов, оказывается, что я должен объявить тех, наблюдаемыми, а также:

var correctViewModel = function(data){ 
    var self=this; 
    self.SetUserModel= function(userData) { 
      this.user = ko.observable(userData); 
     } 
    self.SetRoles = function (data) { 
      this.roles = ko.observableArray(data); 
     } 
} 

и, соответственно, в моем HTML, если я хочу, чтобы связать имя свойства userModel:

<input data-bind:'textInput:userModel().name'/> 

Мои вопросы, то есть:

  1. Я правильно мой вывод, что «наблюдаемый пузыриться» не происходит, и это единственный способ достичь связывания с свойствами, находятся на нескольких уровнях в графе объектов?

  2. Предполагая, что я прав в 1, синтаксис выше для меня странный. userModel и имя являются наблюдаемыми, но чтобы мои примеры работали, я должен ссылаться на объект как userModel(). name. Я ожидал бы привязки к userModel.name. Это смущает здесь, верно?

** Я отредактировал это, чтобы включить сеттеры, которые я использовал бы. Идея заключается в том, что модель верхнего уровня будет составлена ​​/ связана после> 1 вызовов API. Я сделал это так, потому что это более естественно в смысле ОО, но, похоже, от этого разговора я мог бы так же легко установить свойство объекта явно после ответа от API, например:

var topModel = new CorrectViewModel(); 
$.ajax({...}).done(function(data){ 
    topModel.Users=(new UserModel(data)); 
}) 

Могу ли я спросить Каков тем более идиоматический стиль использования?

+0

Невозможно наблюдать основные свойства модели просмотра, нет. [Вот упрощенный пример] (http://jsfiddle.net/ktmv4pcz/) того, что у вас есть выше. –

+0

Спасибо Джеймс, я вижу твои работы, как я и ожидал. Мой не сделал, например. Мне пришлось использовать синтаксис, который я показал здесь, поэтому я разместил этот вопрос. Я буду копаться дальше. – monkeydeus

+0

Я вижу, что происходит. Я непреднамеренно отказался от ключевой информации. В модели, с которой я тестировал, я создал методы setter, потому что модель верхнего уровня не была бы создана сразу. Свойства дочерних объектов, скорее всего, будут вызваны отдельными вызовами API: [link] (http://jsfiddle.net/monkeydeus/BnEDD/) – monkeydeus

ответ

0

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

Предположим, вы являетесь менеджером франчайзинга, и у вас есть несколько магазинов/мест для франчайзинга, которыми вы управляете.

var vm = { 
    activate: activate, 
    user: ko.observable(), 
    currentFranchiseLocation: ko.observable(), 
}; 

function activate() { 
    vm.user(LoadYourUserHere().Result); 
    vm.currentFranchiseLocation(LoadTheInitialLocation().result) 
} 

function changeLocation() { 
    loadOtherLocation.done(function (data) { 
     vm.currentFranchiseLocation(new FranchiseLocationVM(data)); 
    }); 
} 

Html связывание

<div data-bind="with: currentLocation"> 
    <h3 data-bind="text:Name"></h3> 
    <div data-bind="text:numEmployees"></div> 
</div> 

Магия здесь действительно with ключевое слово. Он нацелен на наблюдение и изменение, перепроверяет его общее поддерево. В то же время он разворачивает и сглаживает содержимое своей цели, видимой для местного масштаба, поэтому вы можете делать привязки, такие как text:Name, а не currentLocation().Name

1

Ответа на вопрос 1: да, вы правы, наблюдаемые не "пузырь".

Ответ на 2: вы должны использовать этот синтаксис.

И теперь то, что объясняет как 1, так и 2 в одно и то же время: наблюдаемая функция, которую можно вызвать с параметром, чтобы установить его значение, или указать параметр для его получения.

Когда Нокаут находит выражение привязки, он проверяет, если его наблюдаемый или нет:

  • если это наблюдаемый Нокаут «вызывает» это, чтобы получить его значение
  • , если это не является наблюдаемым, нокаут оценивает код, как "нормальный" JavaScript

Давайте рассмотрим несколько случаев:

// 1 
var vm = { name: ko.observable(); }; 
// 2 
var vm = { hidden: ko.observable(true); }; 
// 3 
var userModel = ko.observable({ 
    name: ko.observable() 
}); 

Во всех этих случаях, как объяснялось выше, наблюдаемые являются функциями, которые необходимо вызвать, чтобы получить или установить его значение.

  1. Простейший случай: text: name. Нокаут проверяет, что name является наблюдаемым, поэтому ko вызывает его, чтобы получить его значение

  2. Немного сложнее: visible: !hidden(). В этом случае нокаут видит, что !hidden() не является наблюдаемым и оценивает его как «обычный JavaScript». Если вы написали visible: !hidden, нокаут также проверил бы, что он не является наблюдаемым, поэтому он будет оценивать его как «обычный javascript», и результат всегда будет false, потому что hidden, без круглых скобок для его вызова, является function, что является JavaScript truish value, а ! преобразует истинное значение в false.

  3. Если в нем есть наблюдаемые с наблюдаемыми свойствами, вы должны вызвать внешний наблюдаемый, чтобы получить доступ к объекту внутри него, который содержит наблюдаемые. В выражении userModel().name скобки ссылаются на userModel, чтобы получить объект внутри него, и ссылается на наблюдаемый name. Итак, когда Knockout проверяет, является ли это наблюдаемым, он обнаруживает, что он является наблюдаемым и оценивает его. Если вы указали userModel.name, это будет доходность undefined, becasue userModel, без вызова его круглыми скобками, является функцией, которая не имеет свойства name.

Примечание 1: есть функции полезности в нокауте, чтобы обнаружить, если что-то наблюдаемым или нет: ko.isObservable(expr), и, чтобы получить значение выражения, Wheter это наблюдаемым или нет: ko.unwrap(expr)

ПРИМЕЧАНИЕ 2A: наблюдаемые реализованы как функция, так что, когда они вызываются, чтобы установить их значение, они могут уведомить, что они были изменены на всех своих подписчиков. Подписки создаются atuomatically. Например, когда вы указываете привязку text: userModel().name, код, который должен установить текст, подписывается на наблюдаемый name, что означает, что каждый раз, когда вызывается name, и его значение изменяется, он уведомляет этот код, чтобы он мог изменить текст.На самом деле вы можете также сделать explicit subscriptions как Aurelia

ПРИМЕЧАНИЕ 2B: некоторые языки, в том числе современных разновидностях свойств поддержки JavaScript. Свойство читается или записывается так, как если бы оно было простой переменной, но оно способно выполнять некоторый код вместо простой установки или получения значения. Есть некоторые библиотеки JavaScript, которые используют эту функцию, которая позволяет использовать более простой синтаксис, без круглых скобок.