如何检测实体的EntityState的更改?

时间:2013-01-12 21:00:38

标签: breeze

我想在客户列表的每一行上放置一个“删除”按钮和一个“取消”按钮。当客户“未更改”时,“取消”按钮被禁用。但是当客户转换到更改状态(“已添加”,“已修改”,“已删除”)时,我想启用“取消”按钮,以便用户可以在保存之前撤消更改 - 无论它们是什么。 / p>

我几乎可以通过订阅customer.entityAspect.propertyChanged来做到这一点。属性变化表示EntityState中的潜在变化。我可以订阅该事件并让我的处理程序更新我已添加到我的Customer实体的isChanged observable。然后我将“取消”按钮启用绑定到isChanged,我很高兴。

propertyChanged事件仅在数据属性更改时引发,例如customer.Name("New Co.");。用户单击“删除”按钮时不会引发此问题。 “删除”触发customer.entityAspect.setDelete();,它不会触及数据属性;它只是改变了客户的EntityState

(1)为什么不更改客户的EntityState加注propertyChanged和(2)如何监听EntityState的更改,以便我可以控制“取消“按钮?

P.S。:我正在使用Knockout。

P.P.S:这个问题的灵感来自之前的SO问题"entityAspect.setDeleted doesn't fire the subscribed propertyChanged event"

2 个答案:

答案 0 :(得分:10)

propertyChanged更改时,Breeze不会引发EntityState,这是正确的。也许它应该。我们会考虑这一点。

Breeze在实体上没有单独的事件 - 没有entityStateChanged事件 - 在EntityState更改时通知您。我们已经多次考虑过了。我们一直在谈论自己。

有一个非常好的解决方案,比专用的entityStateChanged事件表现更好。现在你必须自己编写代码。

诀窍是听EntityManager,而不是实体。您可以在DocCode "Teach Tests"示例中找到此解决方案的一个变体;在 entityTest.js 模块中查找“可以通过entityManager.entityChanged 控制自定义ko entityState属性”。

我会调整一下以适应你的榜样。其实质如下:

  1. 订阅entityManager.entityChanged活动;当它被引发时,原因是实体的EntityState发生了变化,你更新了该实体的isChanged布尔KO observable(如果该属性存在)。

  2. isChanged observable添加到应以这种方式观看的实体类型中。

  3. 以下是步骤1的示例:侦听状态更改

    // 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);
                }
            }
        }
    }
    

    让我们谈谈第2步:将isChanged observable添加到该类型中。你似乎已经解决了那个,但我不确定如何。也许在type's initializer中将其添加到类型的最佳位置可以确保属性存在,无论实体是由查询创建还是实现。这是一个例子:

    var store = manager.metadataStore;
    
    function customerInit(entity) {
        var isUnchanged = entity.entityAspect.entityState.isUnchanged();
        entity.isChanged = ko.observable(!isUnchanged);
    }
    
    store.registerEntityTypeCtor('Customer', null, customerInit);
    

    这一切似乎都是很多工作。如果propertyChanged更改时Breeze引发EntityState事件会更容易。我们会给予更多的考虑......可能会有一些好的反驳论点。同时,我认为你在这里看到的是最好的方法。

答案 1 :(得分:0)

我们发现将微风实体管理器包装在我们自己的内部为我们提供了很好的灵活性,使这个挑战成为了公园里的一个步骤,特别是在hasChangesChanged事件中。

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;
})();

然后在viewModels上公开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;

然后在你的Knockout UI中:

<button type="button" class="btn btn-info" data-i18n="common.save" data-bind="click: save, enable: entityManager.hasChanges">