35 votes

Angularjs promet de ne pas se lier au template dans 1.2

Après la mise à niveau vers la version 1.2, les promesses retourné par mes services se comportent différemment... Un service Simple myDates:

getDates: function () {
           var deferred = $q.defer();

            $http.get(aGoodURL).
                 success(function (data, status, headers, config) {
                     deferred.resolve(data);  // we get to here fine.
            })......

Dans la version antérieure seulement je pouvais faire, dans mon controller:

$scope.theDates = myDates.getDates();

et les promesses retourné à partir de getDates pourrait être lié directement à un élément Select. Maintenant cela ne fonctionne pas et je suis obligé de fournir un rappel de la promesse de mon contrôleur ou les données habitude de lier:

$scope.theDates = matchDates.getDates();
$scope.theDates.then(function (data) {
      $scope.theDates = data;  // this wasn't necessary in the past

Les docs encore dire:

$q promesses sont reconnus par le moteur de template dans angulaire, ce qui signifie que dans les modèles, vous pouvez traiter les promesses attachées à un champ comme s'ils étaient les valeurs résultantes.

Ils (les promesses) travaillaient dans les anciennes versions de Anguleux, mais dans la 1.2 RC3 automatique de la liaison échoue dans toutes mes services simples.... toutes les idées sur ce que je fais de mal.

41voto

Nenad Points 3779

Il y a des changements dans 1.2.0-rc3, y compris celui que vous avez mentionné:

AngularJS 1.2.0-rc3 féroce contraction résout un certain nombre de haute priorité questions de $compiler et $animer et ouvre la voie à 1.2. Ce communiqué a également introduit un certain importante de rupture des changements qui, dans certains cas, pourraient briser vos directives et des modèles. Merci assurez-vous de lire le changelog pour comprendre ces changements et apprendre comment migrer votre code si nécessaire. Pour plus de détails de cette version, voir le changelog.

Il y a la description dans le journal des modifications:

$parse:

  • en raison de 5dc35b52, $parse et des modèles dans la volonté générale n'est plus automatiquement déballer promesses. Cette fonctionnalité a été supprimée et si absolument nécessaire, il peut être réactivé pendant la période de transition via $parseProvider.unwrapPromises(true) api.
  • en raison de b6a37d11, fonction qui a été ajoutée dans le rc.2 qui déballe les valeurs de retour des fonctions si les valeurs sont des promesses (si la promesse est d'ôter activée - voir point précédent), a été repris en raison de la rupture populaire le mode d'utilisation.

22voto

Peter Kriens Points 6632

Comme @Nenad les avis, les promesses ne sont plus automatiquement déréférencé. C'est l'un des plus bizarres les décisions que j'ai jamais vu, car il silencieusement supprime une fonction que j'ai invoqué (et qui a été l'un des points de vente uniques angulaire pour moi, le moins est le mieux). Donc il m'a fallu un peu de temps pour comprendre cela. Surtout depuis le $cadre de ressources semble toujours bien fonctionner. Sur le dessus de tout cela, c'est aussi une release candidate. Si ils ont vraiment eu de déprécier ce (les arguments de son très faible), ils pourraient au moins avoir donné un délai de grâce où il y avait des avertissements avant silencieusement l'éteindre. Bien que généralement très impressionné par angulaire, c'est un gros moins. Je ne serais pas surpris si cela sera revenue, même si il semble y avoir relativement peu de protestations jusqu'à présent.

De toute façon. Quelles sont les solutions?

  • Toujours utiliser l'époque(), et d'attribuer le $champ d'application de la méthode

    function Ctrl($scope) {
       foo().then( function(d) { $scope.d = d; });
    )
    
  • appel de la valeur grâce à une déballer fonction. Cette fonction retourne un champ dans la promesse et définit ce champ par le biais de la méthode. Il sera donc indéfini tant que la promesse n'est pas résolu.

    $rootScope.unwrap = function (v) {
      if (v && v.then) {
        var p = v;
        if (!('$$v' in v)) {
          p.$$v = undefined;
          p.then(function(val) { p.$$v = val; });
        }
        v = v.$$v;
      }
      return v;
    };
    

    Vous pouvez maintenant appeler:

    Hello {{ unwrap(world) }}.
    

    C'est à partir de http://plnkr.co/edit/Fn7z3g?p=preview qui n'a pas un nom qui lui est associée.

  • Ensemble $parseProvider.unwrapPromises(true) et de vivre avec les messages, vous pouvez éteindre avec $parseProvider.logPromiseWarnings(false) mais il est préférable d'être conscients qu'ils pourraient retirer de la fonctionnalité dans une prochaine version.

Soupir, 40 ans, Smalltalk eu l' become message qui vous a permis de basculer les références de l'objet. Des promesses qu'ils pourraient l'avoir été ...

Mise à JOUR:

Après changement de mon application, j'ai trouvé un modèle général qui a fonctionné assez bien.

En supposant que j'ai besoin de l'objet 'x', et c'est un moyen d'obtenir cet objet à distance. Je vais donc d'abord vérifier un cache pour 'x'. Si il y a un objet, je le retourner. Si aucun objet n'existe, j'ai créer un véritable objet vide. Malheureusement, cela vous oblige à savoir si ce sera un Tableau ou une table de hachage/objet. J'ai mis cet objet dans le cache afin que les futurs appels de pouvoir l'utiliser. Je puis commencer à l'appel distant et sur le rappel je copie les données obtenues à partir du système à distance à l'objet créé. Le cache s'assure que les appels répétés à la méthode get ne sont pas la création de beaucoup d'appels à distance pour le même objet.

 function getX() {
   var x = cache.get('x');
   if ( x == undefined) {
      cache.put('x', x={});
      remote.getX().then( function(d) { angular.copy(d,x); } );
   }
   return x;
 }

Pourtant, une autre alternative est de fournir la méthode get avec la destination de l'objet:

 function getX(scope,name) {
   remote.getX().then( function(d) { 
       scope[name] = d;
   } );
 }       

2voto

pwhe23 Points 420

Vous pouvez toujours créer un service angulaire commun et y insérer une méthode de déballage qui rappelle en quelque sorte le fonctionnement des anciennes promesses. Voici un exemple de méthode:

 var shared = angular.module("shared");

shared.service("Common", [
    function () {

        // [Unwrap] will return a value to the scope which is automatially updated. For example,
        //      you can pass the second argument an ng-resource call or promise, and when the result comes back
        //      it will update the first argument. You can also pass a function that returns an ng-resource or
        //      promise and it will extend the first argument to contain a new "load()" method which can make the
        //      call again. The first argument should either be an object (like {}) or an array (like []) based on
        //      the expected return value of the promise.
        // Usage: $scope.reminders = Common.unwrap([], Reminders.query().$promise);
        // Usage: $scope.reminders = Common.unwrap([], Reminders.query());
        // Usage: $scope.reminders = Common.unwrap([], function() { return Reminders.query(); });
        // Usage: $scope.reminders.load();
        this.unwrap = function(result, func) {
            if (!result || !func) return result;

            var then = function(promise) {
                //see if they sent a resource
                if ('$promise' in promise) {
                    promise.$promise.then(update);
                }
                //see if they sent a promise directly
                else if ('then' in promise) {
                    promise.then(update);
                }
            };

            var update = function(data) {
                if ($.isArray(result)) {
                    //clear result list
                    result.length = 0;
                    //populate result list with data
                    $.each(data, function(i, item) {
                        result.push(item);
                    });
                } else {
                    //clear result object
                    for (var prop in result) {
                        if (prop !== 'load') delete result[prop];
                    }
                    //deep populate result object from data
                    $.extend(true, result, data);
                }
            };

            //see if they sent a function that returns a promise, or a promise itself
            if ($.isFunction(func)) {
                // create load event for reuse
                result.load = function() {
                    then(func());
                };
                result.load();
            } else {
                then(func);
            }

            return result;
        };
    }
]);
 

Cela fonctionne fondamentalement comme le faisaient les anciennes promesses et la résolution automatique. Toutefois, si le deuxième argument est une fonction, il présente l’avantage supplémentaire d’ajouter une méthode ".load ()" qui permet de recharger la valeur dans la portée.

 angular.module('site').controller("homeController", function(Common) {
    $scope.reminders = Common.unwrap([], Reminders.query().$promise);
    $scope.reminders = Common.unwrap([], Reminders.query());
    $scope.reminders = Common.unwrap([], function() { return Reminders.query(); });
    function refresh() {
        $scope.reminders.load();
    }
});
 

0voto

James Eby Points 311

C'étaient de bonnes réponses et m'ont aidé à trouver mon problème lorsque j'ai mis à jour angular et que le déroulement automatique de mes promesses a cessé de fonctionner.

Au risque d’être redondant avec Peter Kriens, j’ai trouvé ce modèle qui fonctionnait pour moi (c’est un exemple simple qui consiste simplement à mettre plusieurs citations de personnes célèbres sur une page).

Mon contrôleur:

 angular.module('myModuleName').controller('welcomeController',
function ($scope, myDataServiceUsingResourceOrHttp) {

    myDataServiceUsingResourceOrHttp.getQuotes(3).then(function (quotes) { $scope.quotes = quotes; });
}
);
 

Ma page:

 ...
<div class="main-content" ng-controller="welcomeController">
...
<div class="widget-main">
    <div class="row" ng-repeat="quote in quotes">
        <div class="col-xs-12">
            <blockquote class="pull-right">
                <p>{{quote.text}}</p>
                <small>{{quote.source}}</small>
            </blockquote>
                </div>
    </div>
</div>
...
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X