How can I detect a change to an entity's EntityState?

╄→尐↘猪︶ㄣ 提交于 2019-11-30 09:40:24

You are correct that Breeze does not raise propertyChanged whent the EntityState changes. Maybe it should. We will consider that.

Nor does Breeze have a separate event on the entity - no entityStateChanged event - to notify you when the EntityState changes. We've considered that several times. We keep talking ourselves out of it.

There is a perfectly good solution that performs better than a dedicated entityStateChanged event. Right now you'll have to code it yourself.

The trick is to listen to the EntityManager, not to the entity. You'll find one variant of this solution in the DocCode "Teach Tests" sample; look for "can control custom ko entityState property via entityManager.entityChanged" in the entityTest.js module.

I'll tweak that to fit your example. The essence of it is as follows:

  1. Subscribe to the entityManager.entityChanged event; when it is raised and the cause is that an entity's EntityState changed, you update that entity's isChanged boolean KO observable (if that property exists).

  2. Add the isChanged observable to entity types that should be watched in this way.

Here's an example of step #1: listening for state changes

// subscribe with handler watching for EntityState changes
addEntityStateChangeTracking(manager);

function addEntityStateChangeTracking(entityManager) {

    if (entityManager._entityStateChangeTrackingToken) { return; } // already tracking it

    // remember the change tracking subscription with a token; 
    // might unsubscribe with that token in future
    entityManager._entityStateChangeTrackingToken =
        entityManager.entityChanged.subscribe(entityChanged);

    var entityStateChangeAction = breeze.EntityAction.EntityStateChange;

    function entityChanged(changeArgs) {            
        if (changeArgs.entityAction === entityStateChangeAction) {
            var entity = changeArgs.entity;
            if (entity && entity.isChanged) { // entity has the observable
                var isUnchanged = entity.entityAspect.entityState.isUnchanged();
                entity.isChanged(!isUnchanged);
            }
        }
    }
}

Let's talk about step #2: adding the isChanged observable to the type. You seem to have tackled that one but I'm not sure how. Perhaps the best place to do add it to the type is in the type's initializer so you can be sure the property will be there, whether the entity is created or materialized by a query. Here's an example:

var store = manager.metadataStore;

function customerInit(entity) {
    var isUnchanged = entity.entityAspect.entityState.isUnchanged();
    entity.isChanged = ko.observable(!isUnchanged);
}

store.registerEntityTypeCtor('Customer', null, customerInit);

This all seems like a lot of work. It would be easier if Breeze raised the propertyChanged event when the EntityState changes. We'll give that more consideration ... there may be some good counter arguments. Meanwhile, I think what you see here is the best approach.

We found wrapping the breeze entity manager inside our own gives us nice flexibility that makes this challenge a walk in the park, especially with the hasChangesChanged event.

var EntityManager = (function () {
    function EntityManager(breezeEntityManager) {
        this.breezeEntityManager = breezeEntityManager;
        this.hasChanges = ko.observable(breezeEntityManager.hasChanges());

        // Subscribe with handler watching for EntityState changes
        this.addEntityStateChangeTracking(breezeEntityManager, this);
    }

    EntityManager.prototype.addEntityStateChangeTracking = function (bem, em) {
        if (this.entityStateTrackingToken != null) return;
        this.entityStateTrackingToken = bem.hasChangesChanged.subscribe(function (changeArgs) {
            em.hasChanges(changeArgs.hasChanges);
        });
    };
    return EntityManager;
})();

Then on your viewModels, expose the EntityManager.

var ViewModel = (function (_super) {
    __extends(ViewModel, _super);
    function ViewModel(typeName) {
        _super.call(this);
        this.type = entities.getType(typeName);
    }

    ViewModel.prototype.loadEntity = function (id) {
        this.entityManager = new breeze.EntityManager("MyManager");;
    };
    return ViewModel;
})(ViewModelBase);
exports.ViewModel = ViewModel;

Then in your Knockout UI:

<button type="button" class="btn btn-info" data-i18n="common.save" data-bind="click: save, enable: entityManager.hasChanges">
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!