4

Я новичок в knockout.js (и это тоже мой первый пост stackoverflow), и теперь у меня возникла следующая проблема.Как повторить нокаут ObservableArray? (длина 0)

Я не могу связать данные из веб-api с ko.observablearray. Почему длина этих объявлений ko.observablearray всегда равна 0? Код прекрасно работает с клиентскими данными (путем добавления новых объявлений) ..

Вот JS-код:

var AnnouncementModel = function() { 
    var self = this; 

    self.AnnouncementText = ko.observable(); 
    self.AllDepartmentsBool = ko.observable(); 
    self.Editable = ko.observable(false); 

    self.Add = function() { 
     viewModel.Announcements.push(self); 
     viewModel.AnnouncementToEdit(new AnnouncementModel()); 
    }; 

    self.Delete = function() { 
     ajaxHelper(announcementsUri + self.ID, 'DELETE').done(
     viewModel.Announcements.remove(self)); 
    }; 

    self.Edit = function() { 
     self.Editable(!self.Editable()); 
    }; 
} 

//The ViewModel 
function AnnouncementsViewModel() { 
    var self = this; 

    self.InitialData = ko.observableArray(); 
    self.Announcements = ko.observableArray(); 
    self.AnnouncementToEdit = ko.observable(new AnnouncementModel()); 
    self.error = ko.observable(); 

    function getAllAnnouncements() { 
     ajaxHelper(announcementsUri, 'GET').done(function(data) { 
      self.InitialData(data);   
     }); 
    }; 

    getAllAnnouncements(); 
}; 

var viewModel = new AnnouncementsViewModel(); 
ko.applyBindings(viewModel, document.getElementById("announcements-container")); 

function createAnnouncement(announcementDto) { 
    var announcement = new AnnouncementModel(); 
    announcement.AnnouncementText = ko.observable(announcementDto.AnnouncementText); 
    announcement.AllDepartmentsBool = ko.observable(announcementDto.AllDepartmentsBool); 
    announcement.Editable = ko.observable(false); 

    return announcement; 
} 

var length = viewModel.InitialData.length; 
for (i = 0; i < length; i++) { 
    var newAnnouncement = createAnnouncement(InitialData[i]); 
    viewModel.Announcements.push(newAnnouncement); 
} 

HTML:

<div id="announcements-container" style="display: inline-block; float: right"> 
    <ul id="announcements-list" class="newsticker" data-bind="foreach: Announcements"> 
     <li> 
      <span data-bind="html: AnnouncementText"></span> 
     </li> 
    </ul> 
    @Html.Partial("_AnnouncementsModal") 
</div> 

В InitialData их получает от апи как следует:


ПОЛУЧИТЬ ЭТО РАБОТУ! :

Благодарим за ответы. Я получил код, работающий путем итерации данных с помощью .forEach(). Другая проблема заключалась в том, что initialData не заполнит список в его нынешнем объеме, так что я отредактирован getAnnouncements работать работать так:

function getAllAnnouncements() { 
    ajaxHelper(announcementsUri, 'GET').done(function(data) { 
     data.forEach(function (entry) { 
      var newAnnouncement = createAnnouncement(entry); 
      self.Announcements.push(newAnnouncement); 
     }); 
    }); 
}; 

ответ

5

Эта линия является вероятным виновником:

var length = viewModel.InitialData.length; 

Помните, что InitialData является функцией . Функции имеют length (это их «арность», число формальных аргументов они имеют), но наблюдаемую функция для наблюдаемого массива length не массив length ..

Вы, вероятно, хотели длину массива внутри это:

var length = viewModel.InitialData().length; 
// -------------------------------^^ 

Ваши различные вызовы к push на наблюдаемых массивов работать, даже если length не потому, что Knockout provides push (and several other things) на наблюдаемой функции массива, а James points out.


Аналогичным образом, эта линия:

var newAnnouncement = createAnnouncement(InitialData[i]); 

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

Так что весь раздел, вероятно, хочет быть переработан немного:

viewModel.InitialData().forEach(function(entry) { 
    var newAnnouncement = createAnnouncement(entry); 
    viewModel.Announcements.push(newAnnouncement); 
}); 

или без forEach (но на самом деле, это почти 2016, и это shimmable на устаревших браузеров);

var data = viewModel.InitialData(); 
for (var i = 0; i < data.length; ++i) { 
    var newAnnouncement = createAnnouncement(data[i]); 
    viewModel.Announcements.push(newAnnouncement); 
} 

Side Примечание: Ваш код (по крайней мере, как в вопросе) также становится жертвой The Horror of Implicit Globals, не объявляя i, что вы используете в этом for цикле.Я добавил var выше, но это еще одна причина для использования forEach для циклического перемещения массивов.

+1

Да, в то время как 'наблюдаемыйArray' [переопределяет многие функции] (http://knockoutjs.com/documentation/observableArrays.html#manipulating-an-observablearray) на этом уровне, например' push', поэтому он знает, когда изменения происходят, свойство 'length' не входит в их число, поэтому для этого вам нужно получить базовый массив. –

+0

omg, уже любящий этот stackoverflow thingy ..: D Спасибо T.J за очень точный и полезный ответ! Получил мой код, работающий с вашей помощью! Я добавлю решение вопроса. –

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