2013-11-12 3 views
0

Я прочитал каждый связанный пост по этому поводу и провел последние два дня, пытаясь понять, что я делаю неправильно здесь, без особого успеха.KnockoutJS не собирает jQuery .change() event

Работая с этим скриптом JS здесь в качестве примера: http://jsfiddle.net/rniemeyer/dtpfv/ Я пытаюсь реализовать грязный флаг. Единственное различие заключается в том, что я изменяю данные внутри регулярного диапазона по отношению к введенному файлу и используя плагин сопоставления и вручную назначая наблюдаемые.

$(document).ready(function(){ 

    ko.dirtyFlag = function(root, isInitiallyDirty) { 
     var result = function() {}, 
      _initialState = ko.observable(ko.toJSON(root)), 
      _isInitiallyDirty = ko.observable(isInitiallyDirty); 

     result.isDirty = ko.computed(function() { 
      return _isInitiallyDirty() || _initialState() !== ko.toJSON(root); 
     }); 
     result.reset = function() { 
      _initialState(ko.toJSON(root)); 
      _isInitiallyDirty(false); 
     }; 
     return result; 

    }; 

    $.getJSON('/environments/data.json', function(jsondata) { 
     var mapping = { 
      create: function (options) { 
       var innerModel = ko.mapping.fromJS(options.data); 
       for (var i=0; i < innerModel.deployments().length; i++) { 
        innerModel.deployments()[i].dirtyFlag = new ko.dirtyFlag(innerModel.deployments()[i]); 
       } 
       return innerModel; 
      } 
     } 

     var viewModel = ko.mapping.fromJS(jsondata, mapping); 

     self.save = function() { 
      console.log("Sending changes to server: " + ko.toJSON(this.dirtyItems)); 
     }; 

     self.dirtyItems = ko.computed(function() { 
      for (var i = 0; i < viewModel().length; i++) { 
       return ko.utils.arrayFilter(viewModel()[i].deployments(), function(deployment) { 
        return deployment.dirtyFlag.isDirty(); 
       }); 
      } 
     }, viewModel); 

     self.isDirty = ko.computed(function() { 
      return self.dirtyItems().length > 0; 
     }, viewModel); 

     self.changeTag = function (data, event) { 

      // Neither .change() nor .trigger('change') work for me 
      $(event.target).parents().eq(4).find('span.uneditable-input').text(data.tag).change() 

      // This value never changes. 
      console.log('Dirty on Change: '+self.dirtyItems().length) 

     } 

     ko.applyBindings(viewModel); 

    }); 

}) 

Здесь урезанная кусок HTML, который вызывает функцию changeTag(), заменяющий current_tag() с выбором из выпадающего меню. Это, однако, не вызывает обновления KnockoutJS.

<div> 
    <span data-bind="text: current_tag() }"></span> 
    <div> 
     <button data-toggle="dropdown">Select Tag</button> 
     <ul> 
      <!-- ko foreach: $.parseJSON(component.available_tags() || "null") --> 
      <li><a href="#" data-bind="click: function(data, event) { changeTag(data, event) }"></a></li> 
      <!-- /ko --> 
     </ul> 
    </div> 
</div> 

Я нахожусь на дне два, пытаясь понять это. Любая идея, что я делаю неправильно здесь? Я должен использовать поле ввода, а не обычный элемент span? Нужно ли изменять значения моих viewModel напрямую, а не использовать jQuery для управления DOM? (Я на самом деле пробовал это, но меняя viewModel, а затем повторно привязываю к нему, кажется, замедляет работу, если я не ошибаюсь)

Спасибо.

+0

В чем проблема? Не могли бы вы определить его немного лучше. Я предполагаю, что вы говорите, что скрипка, которую вы предоставили, является рабочим примером того, что вы пытаетесь выполнить, - можете ли вы предоставить скрипку с кодом? –

+0

@PWKad: Проблема в том, что KnckoutJS не подбирает обновления для диапазона, который я делаю с помощью jQuery. Создание скрипки прямо сейчас – solefald

+1

Я не уверен, 100%, почему вы хотели бы обновить наблюдаемый из jQuery - это противоречит основным принципам использования Knockout для двусторонней привязки данных. Может быть, хороший вариант использования, но почему бы просто не обновить его с помощью свойства, а не переопределить его с помощью jQuery и потенциально нарушить привязку? –

ответ

3

Как сказано в комментариях, считается «плохой практикой нокаута» для обновления значения через jQuery, когда вы также можете обновить наблюдаемый напрямую. Нокаут продвигает подход, основанный на данных.

В ответ на ваш последний комментарий (не уверен, как ответить на комментарии к переполнению стека): причина, по которой пользовательский интерфейс не подбирая изменение происходит потому, что вы назначили неверная:

var x = ko.observable(1); // x is now observable 
x = 3; // x is no longer observable. After all, you've assigned the value 3 to it. It is now just a number 
x(3); // this is what you're after. x is still an observable, and you assigned a new value to it by using Knockout's parentheses syntax. If x is bound to the ui somewhere, you'll see the value 3 appear 

Так вы хотите сделать

jsondata[environment()].deployments[deployment()].current_tag(ko.dataFor(event.target).tag); 
+0

Спасибо, Ханс, но он не работает для меня. Я получаю 'Uncaught TypeError: свойство 'current_tag' объекта # не является функцией'. Является ли мое сопоставление каким-то образом сломанным и не создает наблюдаемого из current_tag? – solefald

+0

Ничего! Догадаться. Мне пришлось использовать 'viewModel() [environment()]. ​​Deployments() [deploy()]. ​​Current_tag (ko.dataFor (event.target) .tag); вместо этого. Маркировка как решена! Еще раз спасибо! – solefald