2013-01-12 9 views
8

Voglio mettere un pulsante "Elimina" e un pulsante "Annulla" su ogni riga di un elenco di clienti. Il pulsante "Annulla" è disabilitato quando un cliente è "Invariato". Ma quando un cliente passa a uno stato modificato ("Aggiunto", "Modificato", "Cancellato"), voglio abilitare il pulsante "Annulla" in modo che l'utente possa invertire le modifiche - qualunque esse siano - prima di salvare.Come posso rilevare una modifica a EntityState di un'entità?

Posso quasi farlo iscrivendomi allo customer.entityAspect.propertyChanged. Un cambio di proprietà segnala un potenziale cambiamento nel EntityState. Posso iscrivermi a quell'evento e far aggiornare il gestore uno isChanged osservabile che ho aggiunto alle entità del mio cliente. Poi lego il pulsante "Annulla" abilitato allo isChanged e sono a posto.

Ma l'evento propertyChanged viene generato solo quando un proprietà dei dati cambiamenti, per esempio, customer.Name("New Co.");. Non viene generato quando l'utente fa clic sul pulsante "Elimina". I trigger "Elimina" customer.entityAspect.setDelete(); che non toccano una proprietà dati; cambia semplicemente il numero EntityState del cliente.

(1) Perché non un cambiamento di EntityState rilancio del cliente propertyChanged e (2) come posso ascoltare per una modifica al EntityState in modo da poter controllare il pulsante "Annulla"?

P.S .: Sto utilizzando Knockout.

P.P.S: questa domanda è stata ispirata da una precedente domanda SO "entityAspect.setDeleted doesn't fire the subscribed propertyChanged event".

risposta

10

È corretto che Breeze non rilevi propertyChanged mentre le modifiche di EntityState. Forse dovrebbe. Lo prenderemo in considerazione.

né Breeze ha un evento separato sull'entità - nessun entityStateChanged evento - per informare l'utente quando il EntityState modifiche. L'abbiamo preso in considerazione diverse volte. Continuiamo a parlarci da soli.

Esiste una soluzione perfettamente funzionante che offre prestazioni migliori rispetto a un evento dedicato entityStateChanged. In questo momento dovrai codificarlo da solo.

Il trucco è ascoltare lo EntityManager, non l'entità. Troverai una variante di questa soluzione nell'esempio DocCode "Teach Tests"; cercare "può controllare la proprietà personalizzata ko entityState tramite entityManager.entityChanged" nel modulo entityTest.js.

L'ho modificato per adattarlo al tuo esempio. L'essenza di questo è la seguente:

  1. Iscriviti all'evento entityManager.entityChanged; quando viene sollevato e la causa è che il numero EntityState di un'entità è cambiato, si aggiorna il valore KO booleano di entità isChanged (se tale proprietà esiste).

  2. Aggiungi il isChanged osservabile ai tipi di entità che devono essere guardati in questo modo.

Ecco un esempio di passo # 1: l'ascolto per lo stato cambia

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

Parliamo di passo # 2: aggiungere il isChanged osservabile al tipo. Sembra che tu abbia affrontato quello ma non sono sicuro di come. Forse il miglior posto per aggiungerlo al tipo è nel type's initializer così puoi essere sicuro che la proprietà sarà lì, sia che l'entità sia creata o materializzata da una query. Ecco un esempio:

 
var store = manager.metadataStore; 

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

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

Questo sembra tutto un sacco di lavoro. Sarebbe più facile se Breeze avesse sollevato l'evento propertyChanged quando le modifiche di EntityState. Daremo questa considerazione in più ... potrebbero esserci alcuni buoni argomenti contrari. Nel frattempo, penso che quello che vedi qui sia l'approccio migliore.

+0

C'è un biglietto possiamo guardare per vedere come questa funzionalità progredisce? La mia squadra lo troverebbe molto utile se Breeze lo gestisse. –

+1

Non siamo inclini ad aggiungere questo alla proprietàChangedEvent. In linea di principio, si tratta di una modifica a una proprietà dell'oggetto business, non a una proprietà dell'infrastruttura dell'entità. Desideriamo inoltre incoraggiare le persone a utilizzare l'evento EntityManager.entityChange che ha meno probabilità di generare collegamenti di memoria. La rete di esso: improbabile che cambi il comportamento dell'evento propertyChanged. – Ward

+0

Grazie per questa risposta @ward! –

0

Abbiamo scoperto che il gestore dell'entità brezza all'interno della nostra ci offre una buona flessibilità che rende questa sfida una passeggiata nel parco, specialmente con l'evento hasChangesChanged.

Quindi, su viewModels, esporre 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; 

Poi, nel tuo Knockout UI:

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