Вопрос по javascript, knockout.js – Обнаружение изменений в модели вида нокаута

62

Конечно, это очень простой вопрос, но есть ли простой способ определить, изменилось ли какое-либо свойство модели вида с выбыванием?

Проверьте этот пост:Creating a Smart, Dirty Flag in KnockoutJS Homer

Ваш Ответ

8   ответов
3

Вы можете использовать плагин ниже для этого:

https://github.com/ZiadJ/knockoutjs-reactor

Код, например, позволит вам отслеживать все изменения в любой viewModel:

ko.watch(someViewModel, { depth: -1 }, function(parents, child) { 
    alert('New value is: ' + child());
});

PS: На данный момент это не будет работать с подписками, вложенными в массив, но новая версия, которая поддерживает его, находится на подходе.

Update: Пример кода был обновлен для работы с версией 1.2b, в которую добавлена поддержка элементов массива и свойств «подписка в подписке».

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
1

Я сделал это, сделав снимок модели представления при загрузке страницы, а затем сравнив этот снимок с текущей моделью представления. Мне было все равно, какие свойства изменились, только если они изменились.

Сделайте снимок:

var originalViewModel = JSON.stringify(ko.toJS(viewModel));

Сравните позже:

if(originalViewModel != JSON.stringify(ko.toJS(viewModel))){
    // Something has changed, but we don't know what
}
Error: User Rate Limit ExceededJSON.stringify(ko.toJS(VM))Error: User Rate Limit Exceededko.toJSON(vm).
5

Рассмотреть возможность использованияПлагин Knockout-Validation

Он реализует следующее:

yourProperty.isModified() - Checks if the user modified the value.

yourProperty.originalValue - So you can check if the value really changed.

Наряду с другими проверочными материалами, которые пригодятся!

ура

2

Я адаптировал код @Brett Green и расширил его, чтобы мы могли иметь AcceptChanges, помечая модель как грязную, и имея более удобный способ маркировки моделей как отслеживаемых. Вот код:

var viewModel = {
    name: ko.observable()   
};

ko.track(viewModel);

http://jsfiddle.net/david_freire/3HZEu/2/

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
48

Вы можете подписаться на свойства, которые вы хотите отслеживать:

myViewModel.personName.subscribe(function(newValue) {
    alert("The person's new name is " + newValue); 
});

Это предупредит, когда personName изменится.

Итак, вы хотите знать, когда что-то меняется в вашей модели ...

var viewModel = … // define your viewModel

var changeLog = new Array();  

function catchChanges(property, value){
    changeLog.push({property: property, value: value});
    viewModel.isDirty = true;
}

function initialiseViewModel()
{
    // loop through all the properties in the model
    for (var property in viewModel) {

        if (viewModel.hasOwnProperty(property)) { 

            // if they're observable
            if(viewModel[property].subscribe){

                // subscribe to changes
                viewModel[property].subscribe(function(value) {
                    catchChanges(property, value);
                });
            }
        }
    }
    viewModel.isDirty = false;
}

function resetViewModel() {
    changeLog = new Array();  
    viewModel.isDirty = false;
}

(haven't tested it - but you should get the idea)

Error: User Rate Limit Exceeded user1389723
Error: User Rate Limit Exceeded user1389723
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
2

У меня была та же проблема, мне нужно было наблюдать какие-либо изменения в viewModel, чтобы отправить данные обратно на сервер, Если кто-то еще заинтересовался, я провел небольшое исследование, и это лучшее решение, которое мне удалось собрать:

function GlobalObserver(viewModel, callback) {  
    var self = this;
    viewModel.allChangesObserver = ko.computed(function() {
        self.viewModelRaw = ko.mapping.toJS(viewModel);
    });
    viewModel.allChangesObserver.subscribe(function() {
        callback(self.viewModelRaw);
    });
    self.dispose = function() {
        if (viewModel.allChangesObserver)
            viewModel.allChangesObserver.dispose();
        delete viewModel.allChangesObserver;
    };
};

чтобы использовать этот «глобальный наблюдатель»:

function updateEntireViewModel() {
    var rawViewModel = Ajax_GetItemEntity(); //fetch the json object..    
    //enter validation code here, to ensure entity is correct.
    if (koGlobalObserver)
        koGlobalObserver.dispose(); //If already observing the older ViewModel, stop doing that!
    var viewModel = ko.mapping.fromJS(rawViewModel);        
    koGlobalObserver = new GlobalObserver(viewModel, Ajax_Submit);
    ko.applyBindings(viewModel [ ,optional dom element]);   
}

Следует отметить, что данный обратный вызов (в данном случае «Ajax_Submit») будет запускаться при ЛЮБОМ изменении, которое происходит в модели представления, поэтому я думаю, что действительно рекомендуется создать некоторый механизм задержки для отправки объекта только тогда, когда пользователь закончил редактировать свойства:

var _entitiesUpdateTimers = {};

function Ajax_Submit(entity) { 
    var key = entity.ID; //or whatever uniquely related to the current view model..
    if (typeof _entitiesUpdateTimers[key] !== 'undefined')
        clearTimeout(_entitiesUpdateTimers[key]);    
    _entitiesUpdateTimers[key] = 
        setTimeout(function() { SendEntityFunction(entity); }, 500);           
}

Я новичок в JavaScript и нокаут-фреймворке (только вчера я начал работать с этим замечательным фреймворком), поэтому не сердитесь на меня, если я что-то не так сделал ... (-:

Надеюсь это поможет!

Error: User Rate Limit Exceeded
1

Рассмотрим модель представления следующим образом

function myViewModel(){
    var that = this;
    that.Name = ko.observable();
    that.OldState = ko.observable();
    that.NewState = ko.observable();

    that.dirtyCalcultions - ko.computed(function(){
    // Code to execute when state of an observable changes.
});
}

После привязки ваших данных вы можете сохранить состояние, используя функцию ko.toJS (myViewModel).

myViewModel.Name("test");
myViewModel.OldState(ko.toJS(myViewModel));

Вы можете объявить переменную внутри вашей модели представления как вычисляемую наблюдаемую как

that.dirtyCalculations = ko.computed(function () {});

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

Затем вы можете сравнить два состояния модели представления как:

that.dirtyCalculations = ko.computed(function () {
  that.NewState(that);

  //Compare old state to new state
  if(that.OldState().Name == that.NewState().Name()){
       // View model states are same.
  }
  else{
      // View model states are different.
  }

});

** Примечание. Эта вычисляемая наблюдаемая функция также выполняется в первый раз при инициализации модели представления. **

Надеюсь это поможет ! Ура !!

96

Используйте удлинители:

ko.extenders.trackChange = function (target, track) {
    if (track) {
        target.isDirty = ko.observable(false);
        target.originalValue = target();
        target.setOriginalValue = function(startingValue) {
            target.originalValue = startingValue; 
        };
        target.subscribe(function (newValue) {
            // use != not !== so numbers will equate naturally
            target.isDirty(newValue != target.originalValue);
        });
    }
    return target;
};

Затем:

self.MyProperty= ko.observable("Property Value").extend({ trackChange: true });

Теперь вы можете проверить, как это:

self.MyProperty.isDirty()

Вы также можете написать некоторый общий обход viewModel, чтобы увидеть, изменилось ли что-нибудь:

self.isDirty = ko.computed(function () {
    for (key in self) {
        if (self.hasOwnProperty(key) && ko.isObservable(self[key]) && typeof self[key].isDirty === 'function' && self[key].isDirty()) {
            return true;
        }
    }
});

... а затем просто проверить на уровне viewModel

self.isDirty()
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы