Ritardare il cambio di rotta AngularJS fino al caricamento del modello per evitare lo sfarfallio


321

Mi chiedo se c'è un modo (simile a Gmail) per AngularJS di ritardare la visualizzazione di una nuova rotta fino a quando ogni modello e i suoi dati sono stati recuperati utilizzando i rispettivi servizi.

Ad esempio, se ce ne fosse uno ProjectsControllerche elenca tutti i progetti e project_index.htmlche era il modello che mostrava questi progetti, Project.query()sarebbe stato recuperato completamente prima di mostrare la nuova pagina.

Fino ad allora, la vecchia pagina continuava a essere visualizzata (ad esempio, se stavo sfogliando un'altra pagina e decidessi di vedere questo indice del progetto).

Risposte:


374

La proprietà di risoluzione $ routeProvider consente di ritardare la modifica del percorso fino al caricamento dei dati.

Per prima cosa definisci una rotta con un resolveattributo come questo.

angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/phones', {
        templateUrl: 'partials/phone-list.html', 
        controller: PhoneListCtrl, 
        resolve: PhoneListCtrl.resolve}).
      when('/phones/:phoneId', {
        templateUrl: 'partials/phone-detail.html', 
        controller: PhoneDetailCtrl, 
        resolve: PhoneDetailCtrl.resolve}).
      otherwise({redirectTo: '/phones'});
}]);

notare che la resolveproprietà è definita sul percorso.

function PhoneListCtrl($scope, phones) {
  $scope.phones = phones;
  $scope.orderProp = 'age';
}

PhoneListCtrl.resolve = {
  phones: function(Phone, $q) {
    // see: https://groups.google.com/forum/?fromgroups=#!topic/angular/DGf7yyD4Oc4
    var deferred = $q.defer();
    Phone.query(function(successData) {
            deferred.resolve(successData); 
    }, function(errorData) {
            deferred.reject(); // you could optionally pass error data here
    });
    return deferred.promise;
  },
  delay: function($q, $defer) {
    var delay = $q.defer();
    $defer(delay.resolve, 1000);
    return delay.promise;
  }
}

Si noti che la definizione del controller contiene un oggetto di risoluzione che dichiara cose che dovrebbero essere disponibili al costruttore del controller. Qui phonesviene iniettato nel controller ed è definito nella resolveproprietà.

La resolve.phonesfunzione è responsabile per la restituzione di una promessa. Tutte le promesse vengono raccolte e il cambio di rotta viene ritardato fino a quando tutte le promesse non vengono risolte.

Demo funzionante: http://mhevery.github.com/angular-phonecat/app/#/phones Fonte: https://github.com/mhevery/angular-phonecat/commit/ba33d3ec2d01b70eb5d3d531619bf90153496831


10
@MiskoHevery - cosa succede se i controller si trovano all'interno di un modulo e sono definiti come una stringa anziché come una funzione. Come hai potuto impostare l'attributo di risoluzione come fai tu?
aar0n

53
Come viene utilizzato nelle angular.controller()definizioni dei controller di tipo? Nella $routeProviderroba, ho pensato che dovevi usare i nomi di stringa dei controller.
Ben Lesh,

6
Qualche esempio usando angular.controller () e con l'ultima versione di AngularJS?
Laurent

22
@blesh, quando si utilizza angular.controller(), è possibile assegnare il risultato di questa funzione a una variabile ( var MyCtrl = angular.controller(...)) e quindi lavorare ulteriormente ( MyCtrl.loadData = function(){..}). Guarda il video di egghead, il codice è mostrato immediatamente lì: egghead.io/video/0uvAseNXDr0
petrkotek

17
Mi piacerebbe comunque avere un bel modo di fare senza avere il controller in una posizione globale. Non voglio sporcare di globuli dappertutto. Puoi farlo con una costante, ma sarebbe bello poter mettere la funzione di risoluzione sul / nel controller, non altrove.
Erik Honn,

51

Ecco un esempio minimo di lavoro che funziona con Angular 1.0.2

Modello:

<script type="text/ng-template" id="/editor-tpl.html">
    Editor Template {{datasets}}
</script>

<div ng-view>

</div>

JavaScript:

function MyCtrl($scope, datasets) {    
    $scope.datasets = datasets;
}

MyCtrl.resolve = {
    datasets : function($q, $http) {
        var deferred = $q.defer();

        $http({method: 'GET', url: '/someUrl'})
            .success(function(data) {
                deferred.resolve(data)
            })
            .error(function(data){
                //actually you'd want deffered.reject(data) here
                //but to show what would happen on success..
                deferred.resolve("error value");
            });

        return deferred.promise;
    }
};

var myApp = angular.module('myApp', [], function($routeProvider) {
    $routeProvider.when('/', {
        templateUrl: '/editor-tpl.html',
        controller: MyCtrl,
        resolve: MyCtrl.resolve
    });
});​

http://jsfiddle.net/dTJ9N/3/

Versione ottimizzata:

Poiché $ http () restituisce già una promessa (nota anche come differita), in realtà non è necessario crearne una nostra. Quindi possiamo semplificare MyCtrl. risolvere a:

MyCtrl.resolve = {
    datasets : function($http) {
        return $http({
            method: 'GET', 
            url: 'http://fiddle.jshell.net/'
        });
    }
};

Il risultato di $ http () contiene dati , stato , intestazioni e oggetti di configurazione , quindi dobbiamo cambiare il corpo di MyCtrl in:

$scope.datasets = datasets.data;

http://jsfiddle.net/dTJ9N/5/


Sto provando a fare qualcosa del genere ma ho problemi con l'iniezione di "set di dati" in quanto non definito. qualche idea?
Rob Bygrave,

Ehi MB21, penso che si potrebbe essere in grado di aiutarmi con questa domanda: stackoverflow.com/questions/14271713/...
winduptoy

Qualcuno potrebbe aiutarmi a convertire questa risposta nel formato app.controller ('MyCtrl')? jsfiddle.net/5usya/1 non ha funzionato per me.
user1071182,

ricevo un errore:Unknown provider: datasetsProvider <- datasets
chovy

Puoi rendere la tua risposta più semplice sostituendo i set di dati con questo:function($http) { return $http({method: 'GET', url: '/someUrl'}) .then( function(data){ return data;}, function(reason){return 'error value';} ); }
Morteza Tourani,

32

Vedo alcune persone che chiedono come farlo usando il metodo angular.controller con l'iniezione di dipendenza amichevole di minimizzazione. Da quando ho appena funzionato mi sono sentito in dovere di tornare e aiutare. Ecco la mia soluzione (adottata dalla domanda originale e dalla risposta di Misko):

angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/phones', {
        templateUrl: 'partials/phone-list.html', 
        controller: PhoneListCtrl, 
        resolve: { 
            phones: ["Phone", "$q", function(Phone, $q) {
                var deferred = $q.defer();
                Phone.query(function(successData) {
                  deferred.resolve(successData); 
                }, function(errorData) {
                  deferred.reject(); // you could optionally pass error data here
                });
                return deferred.promise;
             ]
            },
            delay: ["$q","$defer", function($q, $defer) {
               var delay = $q.defer();
               $defer(delay.resolve, 1000);
               return delay.promise;
              }
            ]
        },

        }).
      when('/phones/:phoneId', {
        templateUrl: 'partials/phone-detail.html', 
        controller: PhoneDetailCtrl, 
        resolve: PhoneDetailCtrl.resolve}).
      otherwise({redirectTo: '/phones'});
}]);

angular.controller("PhoneListCtrl", [ "$scope", "phones", ($scope, phones) {
  $scope.phones = phones;
  $scope.orderProp = 'age';
}]);

Poiché questo codice deriva dalla domanda / risposta più popolare, non è testato, ma dovrebbe inviarti nella giusta direzione se hai già capito come rendere il codice angolare adatto alla minificazione. L'unica parte che il mio codice non ha richiesto è stata l'iniezione di "Telefono" nella funzione di risoluzione per "telefoni", né ho usato alcun oggetto "ritardo".

Consiglio anche questo video di YouTube http://www.youtube.com/watch?v=P6KITGRQujQ&list=UUKW92i7iQFuNILqQOUOCrFw&index=4&feature=plcp , che mi ha aiutato molto

Se ti interessa, ho deciso di incollare anche il mio codice (scritto in coffeescript) in modo da poter vedere come l'ho fatto funzionare.

Cordiali saluti, in anticipo uso un controller generico che mi aiuta a fare CRUD su diversi modelli:

appModule.config ['$routeProvider', ($routeProvider) ->
  genericControllers = ["boards","teachers","classrooms","students"]
  for controllerName in genericControllers
    $routeProvider
      .when "/#{controllerName}/",
        action: 'confirmLogin'
        controller: 'GenericController'
        controllerName: controllerName
        templateUrl: "/static/templates/#{controllerName}.html"
        resolve:
          items : ["$q", "$route", "$http", ($q, $route, $http) ->
             deferred = $q.defer()
             controllerName = $route.current.controllerName
             $http(
               method: "GET"
               url: "/api/#{controllerName}/"
             )
             .success (response) ->
               deferred.resolve(response.payload)
             .error (response) ->
               deferred.reject(response.message)

             return deferred.promise
          ]

  $routeProvider
    .otherwise
      redirectTo: '/'
      action: 'checkStatus'
]

appModule.controller "GenericController", ["$scope", "$route", "$http", "$cookies", "items", ($scope, $route, $http, $cookies, items) ->

  $scope.items = items
      #etc ....
    ]

Devo dedurre correttamente dal tuo esempio e dai miei tentativi falliti che ora è impossibile fare riferimento a una resolvefunzione nel controller, nelle ultime versioni di Angular? Quindi deve essere dichiarato proprio nella configurazione come è qui?
XML

@XMLilley Sono abbastanza sicuro che sia così. Questo esempio era della 1.1.2 quando l'ho scritto, credo. Non ho visto alcuna documentazione su come mettere risoluzione all'interno di un controller
bitwit

2
Figo, grazie. Ci sono molti esempi di farlo su SO (come i primi due qui), ma sono tutti del 2012 e all'inizio del 2013. È un approccio elegante, ma sembra essere deprecato. L'alternativa più pulita ora sembra scrivere singoli servizi che sono oggetti promettenti.
XML

Grazie ha funzionato per me. Per chiunque abbia errori sul $deferservizio indefinito , tenere presente che nella versione 1.5.7 di AngularJS si desidera utilizzare $timeoutinvece.
racl101,

18

Questo commit , che fa parte della versione 1.1.5 e successive, espone l' $promiseoggetto di $resource. Le versioni di ngResource incluso questo commit consentono di risolvere risorse come questa:

$ routeProvider

resolve: {
    data: function(Resource) {
        return Resource.get().$promise;
    }
}

controllore

app.controller('ResourceCtrl', ['$scope', 'data', function($scope, data) {

    $scope.data = data;

}]);

Quali versioni includono quel commit, per favore?
XML

L'ultima versione instabile (1.1.5) include questo commit. ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js
Maximilian Hoffmann

Mi piace questo approccio meno prolisso. Sarebbe bello creare una promessa dall'oggetto dati reale e passarlo direttamente, ma questo codice è così piccolo che funziona bene.
Sam Barnum,

1
In che modo la risorsa potrebbe accedere a $ routeParams? Ad esempio: in GET '/api/1/apps/:appId'-> App.get({id: $routeParams.appId}).$promise();Non posso usare così
zeronone il

2
@zeronone ti inietti $routeper la tua decisione e il tuo utilizzo $route.current.params. Fai attenzione, $routeParamssta ancora indicando il vecchio percorso.
Brice Stacey,

16

Questo frammento è compatibile con l' iniezione di dipendenza (lo uso persino in combinazione con ngmin e uglify ) ed è una soluzione basata su dominio più elegante .

L'esempio seguente registra una risorsa del telefono e una costante phoneRoutes , che contiene tutte le informazioni di routing per quel dominio (telefono). Qualcosa che non mi è piaciuto nella risposta fornita era la posizione della logica di risoluzione : il modulo principale non dovrebbe sapere nulla o essere disturbato dal modo in cui gli argomenti delle risorse sono forniti al controller. In questo modo la logica rimane nello stesso dominio.

Nota: se stai usando ngmin (e se non lo sei: dovresti) devi solo scrivere le funzioni di risoluzione con la convenzione di array DI.

angular.module('myApp').factory('Phone',function ($resource) {
  return $resource('/api/phone/:id', {id: '@id'});
}).constant('phoneRoutes', {
    '/phone': {
      templateUrl: 'app/phone/index.tmpl.html',
      controller: 'PhoneIndexController'
    },
    '/phone/create': {
      templateUrl: 'app/phone/edit.tmpl.html',
      controller: 'PhoneEditController',
      resolve: {
        phone: ['$route', 'Phone', function ($route, Phone) {
          return new Phone();
        }]
      }
    },
    '/phone/edit/:id': {
      templateUrl: 'app/phone/edit.tmpl.html',
      controller: 'PhoneEditController',
      resolve: {
        form: ['$route', 'Phone', function ($route, Phone) {
          return Phone.get({ id: $route.current.params.id }).$promise;
        }]
      }
    }
  });

Il prossimo pezzo sta iniettando i dati di routing quando il modulo è nello stato di configurazione e applicandolo a $ routeProvider .

angular.module('myApp').config(function ($routeProvider, 
                                         phoneRoutes, 
                                         /* ... otherRoutes ... */) {

  $routeProvider.when('/', { templateUrl: 'app/main/index.tmpl.html' });

  // Loop through all paths provided by the injected route data.

  angular.forEach(phoneRoutes, function(routeData, path) {
    $routeProvider.when(path, routeData);
  });

  $routeProvider.otherwise({ redirectTo: '/' });

});

Anche testare la configurazione del percorso con questa configurazione è abbastanza semplice:

describe('phoneRoutes', function() {

  it('should match route configuration', function() {

    module('myApp');

    // Mock the Phone resource
    function PhoneMock() {}
    PhoneMock.get = function() { return {}; };

    module(function($provide) {
      $provide.value('Phone', FormMock);
    });

    inject(function($route, $location, $rootScope, phoneRoutes) {
      angular.forEach(phoneRoutes, function (routeData, path) {

        $location.path(path);
        $rootScope.$digest();

        expect($route.current.templateUrl).toBe(routeData.templateUrl);
        expect($route.current.controller).toBe(routeData.controller);
      });
    });
  });
});

Puoi vederlo in piena gloria nel mio ultimo (imminente) esperimento . Sebbene questo metodo funzioni bene per me, mi chiedo davvero perché l'iniettore $ non stia ritardando la costruzione di qualcosa quando rileva l'iniezione di qualcosa che è un oggetto promesso ; renderebbe le cose soooOOOOOooOOOOO molto più facili.

Modifica: usato Angular v1.2 (rc2)


2
Questa eccellente risposta sembra molto più in linea con la filosofia "angolare" (incapsulamento, ecc.). Dovremmo tutti fare uno sforzo consapevole per impedire alla logica di insinuarsi su tutto il codice come kudzu.
zakdances,

I really wonder why the $injector isn't delaying construction of anything when it detects injection of anything that is a promise objectImmagino che abbiano omesso questa funzionalità perché potrebbe incoraggiare modelli di progettazione che incidono negativamente sulla reattività delle app. L'app ideale nella loro mente è davvero asincrona, quindi la risoluzione dovrebbe essere un caso limite.
zakdances,

11

Ritardare la visualizzazione del percorso porterà sicuramente a un groviglio asincrono ... perché non tenere semplicemente traccia dello stato di caricamento dell'entità principale e utilizzarlo nella vista. Ad esempio nel controller è possibile utilizzare sia i callback di successo che quelli di errore su ngResource:

$scope.httpStatus = 0; // in progress
$scope.projects = $resource.query('/projects', function() {
    $scope.httpStatus = 200;
  }, function(response) {
    $scope.httpStatus = response.status;
  });

Quindi nella vista potresti fare qualunque cosa:

<div ng-show="httpStatus == 0">
    Loading
</div>
<div ng-show="httpStatus == 200">
    Real stuff
    <div ng-repeat="project in projects">
         ...
    </div>
</div>
<div ng-show="httpStatus >= 400">
    Error, not found, etc. Could distinguish 4xx not found from 
    5xx server error even.
</div>

6
Forse esporre lo stato HTTP alla vista non è corretto, più che gestire le classi CSS e gli elementi DOM appartengono al controller. Probabilmente userei la stessa idea ma lo stato astratto in isValid () e isLoaded ().
jpsimons,

1
Questa non è in effetti la migliore separazione delle preoccupazioni, inoltre si bloccherà se si hanno controller nidificati che dipendono dall'oggetto specifico.
null

Questo è abbastanza intelligente .. per quanto riguarda l'esposizione dei codici di stato alla vista, potresti semplicemente attaccare la logica http nelle proprietà dell'ambito all'interno del controller, quindi associarli a loro. Inoltre, se effettui più chiamate Ajax che si verificano in background, ti consigliamo di farlo comunque.
KingOf Hypocrites,

Questo andrebbe bene se il problema fosse semplicemente ritardare una visione. Ma la risoluzione è meglio usata se devi ritardare l' istanza di un controller, non solo la vista. (Es .: se devi essere sicuro che il tuo JSON sia caricato perché il tuo controller lo passa a una direttiva prima che sia cablato.) Dai documenti: "il router attenderà che tutti vengano risolti o che uno venga rifiutato prima che il controller sia istanziato ".
Dan,

8

Ho lavorato dal codice di Misko sopra e questo è quello che ho fatto con esso. Questa è una soluzione più attuale da quando $deferè stata modificata $timeout. La sostituzione $timeouttuttavia attenderà il periodo di timeout (nel codice di Misko, 1 secondo), quindi restituirà i dati sperando che sia risolto in tempo. In questo modo, restituisce al più presto.

function PhoneListCtrl($scope, phones) {
  $scope.phones = phones;
  $scope.orderProp = 'age';
}

PhoneListCtrl.resolve = {

  phones: function($q, Phone) {
    var deferred = $q.defer();

    Phone.query(function(phones) {
        deferred.resolve(phones);
    });

    return deferred.promise;
  }
}

7

Utilizzo di AngularJS 1.1.5

Aggiornamento della funzione "telefoni" nella risposta di Justen utilizzando la sintassi AngularJS 1.1.5 .

Originale:

phones: function($q, Phone) {
    var deferred = $q.defer();

    Phone.query(function(phones) {
        deferred.resolve(phones);
    });

    return deferred.promise;
}

aggiornato:

phones: function(Phone) {
    return Phone.query().$promise;
}

Molto più breve grazie alla squadra angolare e ai collaboratori. :)

Questa è anche la risposta di Maximilian Hoffmann. Apparentemente quel commit lo ha trasformato in 1.1.5.


1
Non riesco a trovare nulla $promisenei documenti . Potrebbe essere stato rimosso dalla versione 2.0 +.
zakdances,

È disponibile solo in 1.2
Thomas,

5

È possibile utilizzare la proprietà di risoluzione $ routeProvider per ritardare la modifica del percorso fino al caricamento dei dati.

angular.module('app', ['ngRoute']).
  config(['$routeProvider', function($routeProvider, EntitiesCtrlResolve, EntityCtrlResolve) {
    $routeProvider.
      when('/entities', {
        templateUrl: 'entities.html', 
        controller: 'EntitiesCtrl', 
        resolve: EntitiesCtrlResolve
      }).
      when('/entity/:entityId', {
        templateUrl: 'entity.html', 
        controller: 'EntityCtrl', 
        resolve: EntityCtrlResolve
      }).
      otherwise({redirectTo: '/entities'});
}]);

Si noti che la resolveproprietà è definita sul percorso.

EntitiesCtrlResolveed EntityCtrlResolveè oggetti costanti definiti nello stesso file EntitiesCtrle EntityCtrlcontroller.

// EntitiesCtrl.js

angular.module('app').constant('EntitiesCtrlResolve', {
  Entities: function(EntitiesService) {
    return EntitiesService.getAll();
  }
});

angular.module('app').controller('EntitiesCtrl', function(Entities) {
  $scope.entities = Entities;

  // some code..
});

// EntityCtrl.js

angular.module('app').constant('EntityCtrlResolve', {
  Entity: function($route, EntitiesService) {
    return EntitiesService.getById($route.current.params.projectId);
  }
});

angular.module('app').controller('EntityCtrl', function(Entity) {
  $scope.entity = Entity;

  // some code..
});

3

Mi piace l'idea di Darkporter perché sarà facile per un team di sviluppo nuovo di AngularJS capire e lavorare immediatamente.

Ho creato questo adattamento che utilizza 2 div, uno per la barra di caricamento e un altro per il contenuto effettivo visualizzato dopo il caricamento dei dati. La gestione degli errori verrebbe eseguita altrove.

Aggiungi un flag "pronto" a $ scope:

$http({method: 'GET', url: '...'}).
    success(function(data, status, headers, config) {
        $scope.dataForView = data;      
        $scope.ready = true;  // <-- set true after loaded
    })
});

Nella vista HTML:

<div ng-show="!ready">

    <!-- Show loading graphic, e.g. Twitter Boostrap progress bar -->
    <div class="progress progress-striped active">
        <div class="bar" style="width: 100%;"></div>
    </div>

</div>

<div ng-show="ready">

    <!-- Real content goes here and will appear after loading -->

</div>

Vedi anche: Documenti della barra di avanzamento di Boostrap


Si stacca un po 'se stai caricando più pezzi di dati. Come fai a sapere se tutto è stato caricato?
toxaq,

Le cose sono andate avanti da quando ho aggiunto questa risposta a febbraio, con molta più attività su questa pagina. Sembra che ci sia un miglior supporto in Angular per risolvere questo problema ora rispetto a quanto suggerito qui. Saluti,
reggoodwin

Arrivo un po 'in ritardo, ma occuparsi di più dati non è di grande preoccupazione. Devi solo usare variabili separate (booleane: isReadyData1, isReadyData2 ecc.) Per ogni richiesta e impostare $ scope.ready = isReadyData1 && isReadyData2 ...; funziona bene per me.
Guillaume:

1

Mi sono piaciute le risposte sopra e ho imparato molto da loro, ma manca qualcosa nella maggior parte delle risposte di cui sopra.

Ero bloccato in uno scenario simile in cui stavo risolvendo l'URL con alcuni dati recuperati nella prima richiesta dal server. Il problema che ho affrontato è stato se la promessa fosse rejected.

Stavo usando un provider personalizzato che era solito restituire un Promiseche era stato risolto da resolveof $routeProvideral momento della configurazione.

Quello che voglio sottolineare qui è il concetto whenche fa qualcosa del genere.

Vede l'URL nella barra dell'URL e quindi il rispettivo whenblocco nel controller chiamato e la vista è riferita finora così bene.

Diciamo che ho il seguente codice di fase di configurazione.

App.when('/', {
   templateUrl: '/assets/campaigns/index.html',
   controller: 'CampaignListCtr',
   resolve : {
      Auth : function(){
         return AuthServiceProvider.auth('campaign');
      }
   }
})
// Default route
.otherwise({
   redirectTo: '/segments'
});

Sull'URL di root nel browser otherwiseviene chiamato il primo blocco di esecuzione, altrimenti viene chiamato.

Immaginiamo che AuthServicePrivider.auth()venga chiamato uno scenario che ho colpito rootUrl nella funzione della barra degli indirizzi .

Diciamo che la promessa restituita è nello stato di rifiuto che cosa ???

Nulla viene reso affatto.

Otherwise il blocco non verrà eseguito come per qualsiasi URL che non è definito nel blocco di configurazione ed è sconosciuto alla fase di configurazione di angularJs.

Dovremo gestire l'evento che viene generato quando questa promessa non viene risolta. In caso di fallimento $routeChangeErorrviene attivato $rootScope.

Può essere catturato come mostrato nel codice seguente.

$rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
    // Use params in redirection logic.
    // event is the routeChangeEvent
    // current is the current url
    // previous is the previous url
    $location.path($rootScope.rootPath);
});

IMO In genere è una buona idea inserire il codice di monitoraggio degli eventi nel blocco di esecuzione dell'applicazione. Questo codice viene eseguito subito dopo la fase di configurazione dell'applicazione.

App.run(['$routeParams', '$rootScope', '$location', function($routeParams, $rootScope, $location){
   $rootScope.rootPath = "my custom path";
   // Event to listen to all the routeChangeErrors raised
   // by the resolve in config part of application
   $rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
       // I am redirecting to rootPath I have set above.
       $location.path($rootScope.rootPath);
   });
}]);

In questo modo possiamo gestire il fallimento promettente al momento della fase di configurazione.


0

Ho avuto una complessa interfaccia a pannelli scorrevoli multilivello, con livello dello schermo disabilitato. Creazione di una direttiva sul livello dello schermo disabilitato che creerebbe un evento click per eseguire lo stato come

$state.go('account.stream.social.view');

stavano producendo un effetto sfarfallio. history.back () invece ha funzionato bene, tuttavia nel mio caso non è sempre tornato alla storia. Quindi quello che scopro è che se creo semplicemente l'attributo href sulla mia schermata di disabilitazione invece di state.go, ha funzionato come un incantesimo.

<a class="disable-screen" back></a>

Direttiva "indietro"

app.directive('back', [ '$rootScope', function($rootScope) {

    return {
        restrict : 'A',
        link : function(scope, element, attrs) {
            element.attr('href', $rootScope.previousState.replace(/\./gi, '/'));
        }
    };

} ]);

app.js Ho appena salvato lo stato precedente

app.run(function($rootScope, $state) {      

    $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams) {         

        $rootScope.previousState = fromState.name;
        $rootScope.currentState = toState.name;


    });
});

-2

Una possibile soluzione potrebbe essere quella di utilizzare la direttiva ng-cloak con l'elemento in cui stiamo usando i modelli ad es

<div ng-cloak="">
  Value in  myModel is: {{myModel}}
</div>

Penso che questo richieda il minimo sforzo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.