2013-04-17 4 views
9

Ich habe eine Angular-Anwendung mit Breeze und das hat eine gemeinsame EntityManager für meine verschiedenen Controller. Einige meiner Controller können erreicht werden, ohne eine Abfrage auszuführen, um den MetadataStore des EntityManagers vorzubelegen. Ich habe etwas von einer Startrichtung gefunden here sagen, um die Metadaten zu Beginn der Anwendung zu holen. Mein Projekt basiert auf der Angular-Breezejs-Vorlage und wenn ich versuche, das Folgende zu tun, bekomme ich Fehler, weil das Versprechen nicht vollständig gelöst ist, bevor etwas den Datenkontext verwendet.Breezejs, Wie fange ich Metadaten beim Start mit freigegebenen EntityManager

app.factory('datacontext', 
    ['breeze', 'Q', 'model', 'logger', '$timeout', 
     function (breeze, Q, model, logger, $timeout) { 
      logger.log("creating datacontext"); 

      configureBreeze(); 
      var manager = new breeze.EntityManager("/api/app");    
      manager.enableSaveQueuing(true); 

      var datacontext = { 
       metadataStore: manager.metadataStore, 
       saveEntity: saveEntity, 
       getUsers: getUsers, 
       getUser: getUser, 
       createUser: createUser, 
       deleteUser: deleteUser 
      }; 

      return manager.fetchMetadata() 
        .then(function() { 
         model.initialize(datacontext); 
         return datacontext; 
        }) 
        .fail(function (error) { 
         console.log(error); 
         return error; 
        }); 
      //Function definitions 

Was ist die richtige Art zu blockieren, bis der Metadaten-Abruf abgeschlossen ist? Da es unnötig erscheint, zu prüfen, ob die Metadaten existieren, bevor jede Nicht-Abfrage-Funktion (einschließlich Entitäts-Erstellung) wie das Original-Poster der oben verlinkten Frage endete.

Antwort

11

Ich sehe dein Problem.

Wenn Angular Ihre Factory-Funktion aufruft, um den DataContext-Service zu erstellen, erwartet es, sofort (synchron) ein DataContext-Objekt zurück zu bekommen, das zur Verwendung bereit ist. Aber Sie geben ein Versprechen zurück, um dieses DataContext irgendwann in der Zukunft zurückzugeben ... und Angular gerade ist nicht dafür gebaut.

Ich mag die Idee aber. Vielleicht möchten Sie es dem Angular-Team vorschlagen :-).

Also was Sie hier versuchen, wird einfach nicht funktionieren. Sie müssen sofort eine DataContext zurückgeben. Bis die Metadaten eintreffen, müssen Sie entweder die gesamte Benutzeroberfläche blockieren oder die spezifische Funktionalität blockieren, die auf Metadaten beruht (z. B. createUser). Es ist so, als würde man darauf warten, dass das DOM sich beruhigt, bevor man es mit jQuery manipuliert.

Diese Situation ist nicht angularspezifisch. Sie stehen in einer Knockout-App dem gleichen Dilemma gegenüber. Die Auflösung ist ähnlich.

Beginnen Sie mit dem Aussetzen einer Art von "whenReady" Hook auf dem DataContext. Ein Versprechen könnte eine gute Idee sein. Etwas wie folgt aus:

 
function (breeze, Q, model, logger, $timeout) { 
    logger.log("creating datacontext"); 
    ... 
    var readyDeferred = Q.defer(), whenReady = readyDeferred.promise; 

    var datacontext = { 
      whenReady: whenReady, 
      ... 
     }; 

    initializeDatacontext(); 

    return datacontext; // now Angular is happy because it has a datacontext 

    function initializeDatacontext() { 
     manager.fetchMetadata() 
       .then(function() { 
        readyDeferred.resolve(); 
        // do success stuff; 
       }) 
       .fail(function (error) { 
        readyDeferred.reject(error); 
        // do error stuff; 
       }); 
    } 

    //Function definitions 
} 

Anderswo in der Bootstrapping Ihrer Anwendung, binden Sie in die datacontext.whenReady Versprechen.

 
    // somewhere inside your main controller 
    $scope.isReady = false; 
    datacontext.whenReady.then(function() { 
      $scope.isReady = true; 
      $scope.$apply(); 
     }) 
    .fail(function() { alert("Uh oh!"); }); 
    ... 

Nun ist der isReady auf der HTML so den Umfang binden, dass Sie das gewünschte Verhalten zu bekommen. Sie können damit die gesamte Benutzeroberfläche blockieren oder Funktionen (z. B. "Benutzer erstellen") sperren, bis der Datenkontext bereit ist.

Pleae dieses Pseudo-Code nicht wörtlich verwenden. Verwenden Sie es zur Inspiration.

+0

Dies sollte aktualisiert werden. fetchMetadata benötigt einen Dataservice-Parameter – cecilphillip

+3

Nein, tut es nicht. Sie denken an die 'MetadataStore.fetchMetadata'. Dies ist der 'EntityManager.fetchMetadata'. – Ward