2017-01-26 2 views
1

(я знаю, что название это не самый лучший - не стесняйтесь редактировать)

JSFiddle for easy testing

Я следующие Knockout.js просмотра модели:

function Bar() { 
    var self = this; 
    self.baz = "baz"; 
} 

function Foo() { 
    var self = this; 
    self.bars = ko.observableArray([]); 

    self.addBar = function() { self.bars.push(new Bar()); }; 
    self.removeBar = function (bar) { self.bars.remove(bar); }; 
} 

function ViewModel() { 
    var self = this; 
    self.foo = new Foo(); 
} 

ko.applyBindings(new ViewModel()); 

И следующий HTML:

<a href="#" data-bind="click: foo.addBar">Add</a> 

<ul data-bind="foreach: foo.bars"> 
    <li><span data-bind="text: baz"></span> <a href="#" data-bind="click: $root.foo.removeBar">Remove</a></li> 
</ul> 

Это работает, как ожидалось. Но если изменить абсолютный путь к $root.foo.removeBar$parent.removeBar так:

<a href="#" data-bind="click: $parent.removeBar">Remove</a> 

удаления элемента перестает работать; однако я не вижу никаких ошибок на консоли.

С некоторым экспериментированием, я мог бы узнать, что $parent здесь относится к текущему элементу в наблюдаемом массиве (а Bar экземпляра), не содержащий объект (Foo экземпляра).

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

EDIT: Я нашел способ, который работает:

<!-- ko with: foo --> 
<ul data-bind="foreach: bars"> 
    <li> 
     <span data-bind="text: baz"></span> 
     <a href="#" data-bind="click: $parent.removeBar">Remove</a> 
    </li> 
</ul> 
<!-- /ko --> 

Это не красиво, но это работает. Это в основном сводится к открытию новой области для имущества foo до foreach.

Так что мой следующий вопрос: есть ли лучший способ сделать это?

ответ

2

Контексты связывания нокаутов создаются «каждый раз, когда вы используете привязку потока управления, такую ​​как« с »или« foreach »(reference). Поэтому я думаю, что путаница в том, что иерархия привязки определяется html, а не вашей моделью представления. В вашей модели просмотра иерархия - ViewModel -> Foo -> Bars, но в разметке есть $ root, который является ViewModel, а затем созданный следующий контекст для объекта Bars, поэтому его родитель непосредственно сопоставляется с ViewModel, таким образом пропуская Foo.

Что касается лучшего способа ... На самом деле я не возражаю против того, что у вас есть привязка. Я думаю, что он делает код более чистым, чем необходимость переходить на foo на каждое связывание. Лучше в этом случае чисто мнение. Вы можете поочередно использовать $ parent.foo.removeBar вместо $ root.foo.removeBar, зная, что в вашем контексте они относятся к одной и той же вещи. Третьим вариантом будет использование Foo в качестве модели корневого представления, поскольку, похоже, он не делает ничего другого, кроме как обслуживать Foo в этом примере, но, возможно, ваш фактический прецедент более сложный.

+0

Спасибо @JasonSpake, отличное объяснение! Мой фактический прецедент действительно намного сложнее, и важно не зависеть от полного пути к свойствам (я использую различные вспомогательные функции, которые генерируют части HTML). –

Смежные вопросы