1

Я создал массив с данными о некоторых музыкальных альбомах в режиме просмотра. Я могу использовать этот массив в цикле foreach (например), но я не могу отобразить только одно значение из этого массива.Нокаут: невозможно получить определенное значение от наблюдаемогоArray

Мой ViewModel:

function CD(data) { 
    this.Author = ko.observable(data.Author); 
    this.Title = ko.observable(data.Title); 
    this.Price = ko.observable(data.Price); 
    this.Label = ko.observable(data.Label); 
    this.Id = ko.observable(data.Id); 
} 

function NewsListViewModel() { 
    var self = this; 
    self.newsList = ko.observableArray([]); 

    $.getJSON("/music/news", function (allData) { 
     var mapped = $.map(allData, function (item) { return new CD(item) }); 
     self.newsList(mapped); 
    }); 

    self.oneObject = ko.computed(function() { 
     return self.newsList()[0].Title; 
    }); 
} 

$(document).ready(function() { 
    ko.applyBindings(new NewsListViewModel()); 
}); 

И как я использовал его в HTML:

<ul data-bind="foreach: newsList"> 
    <li data-bind="text: Title"></li> 
    <li data-bind="text: Author"></li> 
    <li data-bind="text: Price"></li> 
    <li data-bind="text: Label"></li> 
</ul> 

Это отлично работает. Но если я пытаюсь дополнительно отображать одно значение:

<ul data-bind="foreach: newsList"> 
    <li data-bind="text: Title"></li> 
    <li data-bind="text: Author"></li> 
    <li data-bind="text: Price"></li> 
    <li data-bind="text: Label"></li> 
</ul> 
... 
<p data-bind="text: oneObject"</p> 

он dosen't работает, Firebug брошенную ошибку:

Type error: self.newsList()[0].Title is undefined

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

PS. Код <p data-bind="text: newsList()[0].Title"</p> тоже не работает.

+1

Side Примечание: Там никогда никаких причин, чтобы написать 'ko.observableArray ([]) '. Просто 'ko.observableArray()' достаточно. –

ответ

3

Вы получаете сообщение об ошибке, поскольку $.getJSON is asynchronous.

Таким образом, когда ваши вычисленные объявлены, ваши предметы не обязательно готовы в newsList, поэтому нет первого элемента, к которому вы могли бы получить доступ.

Таким образом, вы должны проверить в вашем вычислено, что ваш newsList не пуст (в любом случае ваш сервер может также возвращать пустой список, так что всегда хорошо иметь эту проверку), и только затем получить доступ к первому элементу:

self.oneObject = ko.computed(function() { 
    if (self.newsList().length > 0) 
     return self.newsList()[0].Title(); 
    return 'no title yet'; 
}); 

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

+0

Это не просто проблема асинхронности. KO вызывает вычисленную функцию сразу, когда вы ее определяете, чтобы она могла настроить цепочку зависимостей для нее. –

+0

@ T.J.Crowder Поскольку OP в любом случае хочет первого элемента, массив не должен быть пустым и проверять 'self.newsList(). Length' создает зависимость. Нет никакой проблемы с вычисленной функцией, выполняемой немедленно, потому что 'self.newsList' уже объявлен и существует до того, как вычислено объявлено. – nemesv

+0

Решение в порядке. Моя проблема заключалась в первом предложении, но, опять же, глядя на код OP, он применяется. –

1

Я вижу несколько проблем с кодом:

  1. $.getJSON асинхронный так self.newsList пуст, когда это доступ Нокаут впервые. Это, в свою очередь, означает, что self.newsList[0] не определено.
  2. return self.newsList()[0].Title; в вычисленном наблюдаемом не возвращает значение, которое вы хотите вернуть. Он должен быть return self.newsList()[0].Title();
  3. Вам не нужно изобретать колесо, есть отображение плагин, который можно использовать для отображения данных: http://knockoutjs.com/documentation/plugins-mapping.html
Смежные вопросы