web-dev-qa-db-fra.com

JS angulaire: comment lier aux promesses

J'essaie de lier une promesse à une vue. Je ne sais pas si vous pouvez le faire directement, mais c'est ce que je tente de faire. Des idées que je fais mal?

Remarque: la source est un peu artificielle avec le délai d'attente et utilise des données statiques, mais cela facilite le diagnostic du code.

EDIT: JSFiddle Page: http://jsfiddle.net/YQwaf/27/

EDIT: SOLUTION: Il s’est avéré que vous pouvez lier directement des promesses. J'ai eu deux problèmes avec mon code d'origine:

  1. L'utilisation de setTimeout () au lieu de $ timeout de angular posait un problème. Angular ne sait pas qu'il doit actualiser l'interface utilisateur lorsque le délai d'attente est déclenché (vous pouvez résoudre ce problème avec $ scope. $ S'applique dans setTimeout, ou vous pouvez simplement utiliser $ timeout)
  2. La liaison à une fonction qui renvoyait une promesse posait problème. Si on l'appelle une seconde fois, cela fait encore une autre promesse. Mieux vaut définir une variable d'étendue à la promesse et créer une nouvelle promesse uniquement si nécessaire. (Dans mon cas, cela s'appelait $ scope. $ Watch sur le code pays)

HTML:

<div ng:controller="addressValidationController">
    Region Code <select ng:model="regionCode" ng:options="r.code as r.name for r in getRegions()"/>
    Country Code<select ng:model="countryCode"><option value="US">United States</option><option value="CA">Canada</option></select>
</div>

JS:

function addressValidationController($scope, $q) {
    var regions = {
        US: [{code: 'WI',name: 'Wisconsin'}, {code: 'MN',name: 'Minnesota'}], 
        CA: [{code: 'ON',name: 'Ontario'}]
    };
    $scope.getRegions = function () {
        var deferred = $q.defer();
        setTimeout(function () {
            var countryRegions = regions[$scope.countryCode];
            console.log(countryRegions);
            if(countryRegions === undefined) {
                deferred.resolve([]);
            } else {
                deferred.resolve(countryRegions);
            }
        }, 1000);
        return deferred.promise;
    };
}
64
Adam Tegen

WARNING: cette réponse était exacte au moment de sa rédaction, mais à partir de la version 1.2, le moteur de gabarit angulaire ne gère pas les promesses de manière transparente! - @Malvolio

Oui, le moteur de gabarit (et les expressions) traitent les promesses de manière transparente, mais j'attribuerais la promesse à une propriété d'étendue dans le contrôleur et n'appellerais pas à chaque fois une fonction qui renvoie une nouvelle promesse (je pense que c'est votre problème, la promesse résolue est perdue, la promesse est retournée à chaque fois).

JSFiddle: http://jsfiddle.net/YQwaf/36/

HTML:

<div ng:controller="addressValidationController">
    Region Code <select ng:model="regionCode" ng:options="r.code as r.name for r in regions"/>
    Country Code<select ng:model="countryCode"><option value="US">United States</option><option value="CA">Canada</option></select>
</div>

JS:

function addressValidationController($scope, $q, $timeout) {
    var regions = {
        US: [{
            code: 'WI',
            name: 'Wisconsin'},
        {
            code: 'MN',
            name: 'Minnesota'}],
        CA: [{
            code: 'ON',
            name: 'Ontario'}]
    };

    function getRegions(countryCode) {
        console.log('getRegions: ' + countryCode);
        var deferred = $q.defer();
        $timeout(function() {
            var countryRegions = regions[countryCode];
            if (countryRegions === undefined) {
                console.log('resolve empty');
                deferred.resolve([]);
            } else {
                console.log('resolve');
                deferred.resolve(countryRegions);
            }
        }, 1000);
        return deferred.promise;
    };

    $scope.regions = [];

    // Manage country changes:
    $scope.$watch('countryCode', function(countryCode) {
        if (angular.isDefined(countryCode)) {
            $scope.regions = getRegions(countryCode);
        }
        else {
            $scope.regions = [];
        }
    });
}​
29
Guillaume86

Depuis Angular 1.2, vous ne pouvez plus utiliser directement les promesses dans les modèles .
Au lieu de cela, vous devez placer le résultat dans $scope dans then, comme vous le feriez normalement - pas de magie.

Pour contourner temporairement l’ancien comportement, vous pouvez appeler

$parseProvider.unwrapPromises(true)

mais cette fonctionnalité sera supprimée plus tard, alors ne comptez pas dessus.

71
Dan Abramov

À partir de la version angulaire 1.3 - $parseProvider.unwrapPromises(true)ne fonctionnera plus .

Au lieu de cela, vous devriez ouvrir les promesses directement:

myApiMethod().then(function(value){
    $scope.item = value; 
});

Notez que le déballage des promesses fonctionnera toujours avec ngResource comme d’habitude.

27
Benjamin Gruenbaum

renvoyer une référence à la variable scope contenant la liste devrait suffire.

function addressValidationController($scope,$timeout) {
    var regions = {
        US: [{code: 'WI',name: 'Wisconsin'}, {code: 'MN',name: 'Minnesota'}], 
        CA: [{code: 'ON',name: 'Ontario'}]
    };

    $scope._regions = [];

    $scope.getRegions = function () {

        $timeout(function () {
            var countryRegions = regions[$scope.countryCode];
            console.log(countryRegions);
            if(countryRegions === undefined) {
                $scope._regions = []
            } else {
                $scope._regions = countryRegions
            }
        }, 1000);

        return $scope._regions;
    };
}
0
David Fulgham