2013-11-22 4 views
0

Я пытаюсь отобразить список элементов в таблице с помощью Knockout JS. Это похоже на типичный интерфейс поиска, где пользователь вводит запрос, а интерфейс отображает список результатов, возвращаемых поисковой системой. Сначала я извлекаю их с сервера через вызов AJAX, а затем пытаюсь связать их. Это очень удобно для первого запроса. Но когда я пытаюсь выполнить второй запрос (и последующие запросы), каждый результирующий элемент представляется в 10 раз (дублируется), затем для третьего запроса каждый элемент отображается как 30 раз (и так далее). Ниже приведен код.Ajax-запросы с нокаутом JS

<body > 
<p> 
    <input type="search" id="skynet-query" name="q" placeholder="scientific search" autofocus /> 
    <input type="submit" id="skynet-submit" value="Ignite!" onclick="getAttachments(document.getElementById('skynet-query').value)" /> 
</p> 
<article data-bind="foreach: seats"> 
     <h3> 
      <input data-bind="attr:{value: papers().id }" type="checkbox" name="article-to-basket" /> 
      <a data-bind="attr:{href: papers().url }, text: papers().title"> </a> 
     </h3> 
     <address class="authors" data-bind="text: papers().authors"/> 
</article> 
</body> 

Ниже приводится часть сценария

<script> 

var array = new Array(); 

function getAttachments(keyword) { 

    var request = $.ajax({ 
    type: "GET", 
    datatype: "json", 
    url: "get-papers?q="+keyword+"&format=json&full-articles=true&kw-count=10&article-count=10&task-type=m1" 
    }); 

    request.done(function (response) { 

    for (i=0;i<response.articles.length; i++){ 
     array[i] = new PaperData(response.articles[i]); 
    } 
    ko.cleanNode(document); 
    ko.applyBindings(new ReservationsViewModel()); 
    console.log("DONE"); 
    }); 

} 

function PaperData(papers) { 
    var self = this; 
    self.papers = ko.observable(papers); 
} 

function ReservationsViewModel() { 
    //var self = this; 
    self.seats = ko.observableArray(array); 

} 

</script> 

Может кто-то помочь мне найти то, что случилось с этим кодом?

Это то, что мои данные-модель выглядит

{ 
    articles: [ 
    { 
    "is-saved": false, 
    title: "title", 
    abstract: "Abstract", 
    date: "2005-01-01 00:00:00", 
    "publication-forum": "forum", 
    "publication-forum-type": "article", 
    authors: "Authors", 
    keywords: "keyword1, keyword2, keywordn", 
    id: "4f5a318e573ce53e03000015" 
    } 
    ] 

    } 
+0

Фактически в 3-й раз каждый элемент отображался 45 раз :(Очень странно, и я не могу понять, почему – Paba

+0

Ваш 'массив' является« глобальным », и вы всегда добавляете элементы, и вы никогда его не очищаете. – nemesv

+0

Откуда возникают «сиденья»? Ваша модель просмотра кажется неполной. – Tomalak

ответ

1

Ваш подход к нокаутировать не совсем верно.

  • Каждое значение, отображаемое на экране, должно быть наблюдаемым, которое привязано к вашей модели просмотра.
  • Например, элементы ввода с именами не нужны - привязка value заботится об обновлении модели представления. Вам никогда не придется обращаться по адресу <input>.
  • Не использовать inline обработчики событий, такие как onclick. Не в нокауте, ни в другом месте.
  • Не используйте глобальные переменные. Ваша проблема связана с использованием глобальной переменной array, которая на самом деле должна быть наблюдаемым массивом на вашей модели представления.
  • Не очищайте все и не реконструируйте всю модель обзора с нуля только потому, что что-то изменилось. Нокаут будет обрабатывать любые частичные обновления.

Вот улучшенный подход.

<p> 
    <input type="search" data-bind="value: query" placeholder="scientific search" autofocus /> 
    <input type="submit" data-bind="click: getAttachments" /> 
</p> 
<article data-bind="foreach: seats"> 
    <h3> 
     <input data-bind="value: id, checked: selected" type="checkbox" /> 
     <a data-bind="attr: {href: url}, text: title"></a> 
    </h3> 
    <address class="authors" data-bind="text: authors"/> 
</article> 

и

function PaperData(data) { 
    ko.utils.extend(this, data); 
    this.selected = ko.observable(false); 
} 
PaperData.create = function (data) { 
    return new PaperData(data); 
}; 

function ReservationsViewModel() { 
    var self = this; 

    self.query = ko.observable(); 
    self.seats = ko.observableArray(); 

    self.queryParams = { 
     "q": self.query, 
     "format": "json", 
     "full-articles": true, 
     "kw-count": 10, 
     "article-count": 10, 
     "task-type": "m1" 
    }; 

    self.getAttachments = function() { 
     $.get("get-papers", ko.toJS(self.queryParams)) 
     .then(function (response) { 
      return ko.utils.arrayMap(response.articles, PaperData.create); 
     }) 
     .done(self.seats); 
    }; 
} 

ko.applyBindings(new ReservationsViewModel()); 

Примечания

  • Вы можете использовать .then() для преобразования данных отклика Ajax на лету.
  • Вы можете использовать .done(), чтобы записать преобразованный результат в наблюдаемый.
  • Создание свойства queryParams Отдельное свойство модели просмотра позволяет динамически настраивать другие параметры запроса, как показано на рисунке: "q".
  • Вы можете использовать ko.utils.extend для переноса свойств с одного объекта на другой. В качестве альтернативы вы можете использовать плагин сопоставления.
+0

Спасибо за очень хороший ответ. Я понял, что я до сих пор не понял понятия «Нокаут». Я попытался заменить свой код на ваш, но получил следующую ошибку.Uncaught ReferenceError: не удалось обработать привязку "value: function() {return id}" Сообщение: id не определено - это может быть потому, что идентификатор значения не находится в поэтому я заменил его на this.id, тогда эта ошибка исчезла, но я не получил результатов. – Paba

+0

Не используйте код JavaScript в объявлениях привязки. Такие вещи, как '' значение: function() {return id} "' никогда не должно происходить. Все вычисления должны выполняться в модели представления, привязки должны содержать только имена свойств. Для целей отладки попробуйте добавить '

' в проблемные разделы шаблонов. Таким образом, вы можете проверить фактический объект, с которым Knockout пытается работать в любом контексте. –
                        
                            
    Tomalak
                                
                            
                        
                    

+0

Конечно, я должен был сделать несколько догадок о вашей модели данных, так как вы не показывали JSON. Я уверен, что если вы пройдете через код, вы сможете выяснить, как все должно выглядеть в вашем конкретном случае. – Tomalak

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