2014-01-20 8 views
0

У меня есть viewModel и шаблон, который предоставляет данные, основанные на if условия:Нокаут вычислен срабатывает слишком много раз

<!-- ko template: { data: selectedFolder, if: isTemplateVisible, name: 'selectedFoldersProperties-template' } --><!-- /ko --> 

Я думаю, что шаблон визуализируется 4 раза подряд, и одна из причин, заключается в том, что isTemplateVisible является ko.computed.

Если я меняю if: isTemplateVisible на if: selectedFolder, тогда шаблон получается рендерингом 2 раза подряд.

У меня есть демо-версия jsfiddle.

Вы увидите, что «нажатие» выводится в течение 4-х раз после нажатия кнопки.

Есть ли причина, почему функция называется так много раз?

<button id="button" type="button"> 
    Set folder 
</button> 

<div> 
    <!-- ko template: { data: selectedFolder, if: isTemplateVisible, name: 'selectedFoldersProperties-template' } --><!-- /ko --> 
</div> 

<script type="text/html" id="selectedFoldersProperties-template"> 
    <span data-bind="text: FolderName"></span> 

    <ul data-bind="foreach: $root.getFiles($data)"> 
     <li> 
      <span data-bind="text: FileName"></span> 
     </li> 
    </ul> 
</script> 

var viewModel = { 
    selectedFolder: ko.observable(null), 
    getFiles: function(folderData) { 
     console.log("hit"); 
     return [ 
      { FileName: "File 1" }, 
      { FileName: "File 2" } 
     ]; 
    } 
}; 
viewModel.isTemplateVisible = ko.computed(function(){ 
    return this.selectedFolder(); 
}, viewModel); 

ko.applyBindings(viewModel); 

document.getElementById("button").onclick = function() { 
    viewModel.selectedFolder({ 
     FolderName: "Folder 1" 
    }); 
}; 
+0

Ваш «вычисляемый» оценивается только один раз за клик, для чего это стоит. – ebohlman

ответ

3

Ваш isTemplateVisible имеет зависимость от selectedFolder так, что заставляет шаблон для повторной визуализации.

изменения isTemplateVisible не быть вычислен первым:

viewModel.isTemplateVisible = function(){ 
    return this.selectedFolder(); 
}; 

, а затем измените если связывание на шаблоне для выполнения вэлью:

if: isTemplateVisible() 

тогда ваш tmeplate не будет работать в два раза из-за зависимости.

Here is the working fiddle


Альтернативно

Вы можете просто все это, удалив iftemplateisvisible материал:

<button id="button" type="button"> 
    Set folder 
</button> 

<div> 
    <!-- ko if: selectedFolder --> 
    <!-- ko template: { data: selectedFolder, name: 'selectedFoldersProperties-template' } --><!-- /ko --> 
    <!-- /ko --> 
</div> 

<script type="text/html" id="selectedFoldersProperties-template"> 
    <span data-bind="text: FolderName"></span> 

    <ul data-bind="foreach: $root.getFiles($data)"> 
     <li> 
      <span data-bind="text: FileName"></span> 
     </li> 
    </ul> 
</script> 

и ViewModel:

var viewModel = { 
    selectedFolder: ko.observable(null), 
    getFiles: function(folderData) { 
     console.log("hit"); 
     return [ 
      { FileName: "File 1" }, 
      { FileName: "File 2" } 
     ]; 
    } 
}; 
ko.applyBindings(viewModel); 

document.getElementById("button").onclick = function() { 
    viewModel.selectedFolder({ 
     FolderName: "Folder 1" 
    }); 
}; 

Here is fiddle for the second solution


Дальнейшие разъяснения, почему у вас есть этот вопрос

If you want to delve deeper in what's going wrong I have created another fiddle which is time stamping your template:

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

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

Если вы измените ваши привязки не имеет взаимозависимость и быть, например:

if: selectedFolder(), data: selectedFolder 

Тогда цикл не будет происходить, как вы не имеете две вещей зависят друг от друга и ответственных за оказание шаблон.

На основании этого также Throttle не поможет вам, поскольку все это делает это, чтобы отложить изменение стоимости наблюдаемого, которое задержит ваш первый рендер, а затем цикл взаимозависимости, вызванный перекрестными ссылками.


Функция getFiles запускается дважды из-за того, что вы выполняете функцию самообучения на вашей привязке. Он настраивается один раз, когда он помещается на страницу, и снова, когда наступает его очередь запускать внутри foreach.

This can be demonstrated here где вы можете видеть, что пользователи вашей функции getFiles являются function(){return $root.getFiles() } из вашего шаблона.

Если вы измените эту функцию на foreach: $root.getFiles без скобок и сделаете getFiles наблюдаемым массивом, чтобы она была разрешена нокаутом, тогда у вас не будет проблемы с двойным исполнением.

+0

Отличное решение, спасибо. Однако почему это делает 2 раза? Могу ли я использовать расширитель «дроссельной заслонки» или что-то вроде этого, чтобы избежать этого? – Catalin

+0

Добавлена ​​еще одна скрипка для вас с отметками времени, чтобы узнать, что происходит не так. – XGreen

+0

@XGreen Почему он регистрируется дважды, даже после устранения взаимозависимости? –

1

Это потому, что у вас есть привязка foreach.

Этот код <ul data-bind="foreach: $root.getFiles($data)"> приведет к его вычислению 4 раза.

Надежда его ясно

+0

Вы говорите, что, поскольку 'getFiles' возвращает список с двумя элементами? если я заставляю его возвращать только 1 элемент или 6, функция по-прежнему вызывается 4 раза – Catalin

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