2012-09-14 17 views
38

La mia applicazione a pagina singola carica una pagina iniziale e voglio visualizzare una serie di idee. Ciascuna delle idee viene visualizzata in un contenitore flash animato, con animazioni visualizzate per scorrere tra le idee.

idee vengono caricati mediante $ http:

$scope.flash = new FlashInterface scope:$scope,location:$location 

$http.get("/competition.json") 
    .success (data) -> 
    $scope.flash._init data 

Tuttavia, per beneficiare di navigazione storia e UX desidero aggiornare la barra degli indirizzi per visualizzare l'URL corretto per ogni idea con $ location:

$location.path "/i/#{idea.code}" 
$scope.$apply() 

Sto chiamando $ apply qui perché questo evento proviene da fuori contesto AngularJS cioè Flash. Vorrei che rimanesse il controller/vista corrente e che la vista non venga ricaricata. Questo è pessimo perché ricaricare la vista determina il lancio dell'intero oggetto flash e il ciclo del preloader che ricomincia.

Ho provato ad ascoltare a $ routeChangeStart fare un preventDefault:

$scope.$on "$routeChangeStart", (ev,next,current) -> 
    ev.preventDefault() 
$scope.$on "$routeChangeSuccess", (ev,current) -> 
    ev.preventDefault() 

ma senza alcun risultato. L'intera cosa sarebbe hunky dory se potessi immaginare un modo per sovrascrivere la vista ricaricare quando cambio $ location.path.

Mi sento ancora molto a mio agio con AngularJS quindi sarei lieto di qualsiasi suggerimento su come strutturare l'app per raggiungere il mio obiettivo!

+0

Sono in ritardo ma ho appena riscontrato un problema simile. C'è una ragione per cui non potresti mettere le 'idee' al di fuori della direttiva' ng-view' e dare loro il proprio controller, che interagisce con i controller all'interno di 'ng-view' tramite l'ereditarietà dell'ambito? Per lo più mi sto chiedendo perché è così che ho risolto il mio problema e mi chiedo se ha qualche difetto, o se dovrei passare alla risposta accettata. – jclancy

+1

Se oggi risolvessi questo problema, sarei molto tentato di usare ui-router con la sua capacità di visualizzazione gerarchica. Non sono sicuro che risolverebbe il problema specifico dell'URL che avevo qui, ma avrei bisogno di più ricerche per un po '...! – chrisbateskeegan

+0

OK, grazie per avermi indicato in quella direzione e grazie per aver risposto a un commento così tardivo! – jclancy

risposta

92

Invece di aggiornare il percorso, è sufficiente aggiornare la query param con un numero di pagina.

impostare il percorso per ignorare le modifiche di query param:

.... 
$routeProvider.when('/foo', {..., reloadOnSearch: false}) 
.... 

e nel vostro aggiornamento app $location con:

... 
$location.search('page', pageNumber); 
... 
+10

Grazie per il suggerimento, Igor. Avevo notato e scontato questo approccio in precedenza perché preferirei URL come "/ idea/Acas" piuttosto che "/ foo? Idea = Acas". Tuttavia, ha la virtù di lavorare e nel mondo dei pragmatici che lavorano alla perfezione! – chrisbateskeegan

+5

Perfetto, grazie mille di questo suggerimento. Anche io voglio notare che se si vuole scoprire il parametro che cambia si può fare con:. $ portata $ su ("$ routeUpdate", function() {// Il param di ricerca ha cambiato }) – Unitech

+0

Questa è la risposta! Tutte queste altre risposte che trovo risolvono il problema con $ route e $ state, questo è semplice e porta a termine il lavoro! –

30

Da this blog post:

di default tutti i cambiamenti di localizzazione passare attraverso il processo di routing, che aggiorna la vista angolare.

C'è un modo semplice per cortocircuitare questo, tuttavia. Orologi angolari per un cambio di posizione (indipendentemente dal fatto che sia stato eseguito digitando nella barra di posizione , facendo clic su un collegamento o impostando la posizione tramite $location.path()). Quando rileva questa modifica, trasmette un evento , $locationChangeSuccess e avvia il processo di instradamento. Quello che facciamo è catturare l'evento e reimpostare il percorso su ciò che era in precedenza.

function MyCtrl($route, $scope) { 
    var lastRoute = $route.current; 
    $scope.$on('$locationChangeSuccess', function(event) { 
     $route.current = lastRoute; 
    }); 
} 
+0

Grazie per questo, sembra esattamente la soluzione che stavo cercando. Ho letto l'articolo del blog e ho avuto una buona interpretazione. Sfortunatamente non sembra funzionare. Ho provato a mettere il codice in '$ routeChangeStart' per vedere se questo avrebbe fatto la differenza ma senza successo. C'è forse qualche stregoneria che mi manca? – chrisbateskeegan

+0

Un'altra idea: prova a impostare reloadOnSearch = false, http://docs.angularjs.org/api/ng.$routeProvider Vedi anche https://github.com/angular/angular.js/pull/1151 –

+2

Questo è un terribile, terribile hack ... ma funziona.E fino a quando Angular non fornisce un modo per disaccoppiare l'evento di aggiornamento della posizione da una ricarica (purtroppo impedendo il default impedisce il cambiamento dell'URL a titolo definitivo) è quello che stiamo usando. E sì, fwow, reloadOnSearch = false funziona alla grande se ciò che è necessario modificare è limitato ai parametri di ricerca. Il nostro problema era con l'hash per le schede segnalabili. – zapnap

1

Si dovrebbe essere caricata tramite $location Dependency Injection e utilizzando il seguente:

$scope.apply(function() { 
    $location.path("yourPath"); 
} 

Tenete a mente che si dovrebbe non uso hashtag (#) durante l'utilizzo $location.path. Questo è per la compatibilità per la modalità HTML5.

+1

Grazie per il suggerimento. I _think_ Sto caricando $ posizione correttamente 'IndexController = ($ scope, $ http, $ location, $ route) ->' e ho aggiornato il codice dell'applicazione come da te suggerito. Non sono esattamente sicuro di quale sia la differenza, potresti approfondire un po '? – chrisbateskeegan

3

La mia soluzione era quella di utilizzare il $ routeChangeStart perché che ti dà la "prossima "e" ultimi "percorsi, puoi confrontarli senza la necessità di una variabile extra come su $ locationChangeSuccess.

Il vantaggio è quello di poter accedere ai "params" proprietà su entrambi i "next" e "ultimi" percorsi come next.params.yourproperty quando si utilizza la "proprietà/valore /" stile URL e, naturalmente, di utilizzare $location.url o $location.path per cambiare l'URL invece di $location.search() dipende dallo stile dell'URL "? property = value".

Nel mio caso ho usato non solo per questo, ma anche per evitare che il percorso per cambiare è il controller non è cambiata:

$scope.$on('$routeChangeStart',function(e,next,last){ 
    if(next.$$route.controller === last.$$route.controller){ 
    e.preventDefault(); 
    $route.current = last.$$route; 
    //do whatever you want in here! 
    } 
}); 

Personalmente mi sento come AngularJS dovrebbero fornire un modo per controllarlo, a destra ora assumono che ogni volta che si modifica la posizione del browser, si desidera modificare il percorso.

+1

Questo non funziona per me quando cerco di usarlo all'interno di un controller in AngularJS 1.2.6. Penso che sia correlato a $ routeChangeStart che è una trasmissione che non è prevenibile: http://stackoverflow.com/a/14895801/959140 –

0

evento Il $ locationChangeSuccess è un po 'di un approccio forza bruta, ma ho trovato che il controllo del percorso ci permette di evitare di pagina viene ricaricata quando il percorso percorso modello è invariato, ma ricarica la pagina quando si passa a un percorso diverso modello:

var lastRoute = $route.current; 
$scope.$on('$locationChangeSuccess', function (event) { 
    if (lastRoute.$$route.originalPath === $route.current.$$route.originalPath) { 
     $route.current = lastRoute; 
    } 
}); 

L'aggiunta di quel codice a un controller particolare rende il ricaricamento più intelligente.

Modifica: Anche se questo lo rende un po 'più semplice, alla fine non mi piaceva la complessità del codice che stavo scrivendo per mantenere URL dall'aspetto amichevole. Alla fine, sono passato a un parametro di ricerca e l'angolare lo gestisce molto meglio.

0

avevo bisogno di fare questo, ma dopo aver irritabili intorno cercando di ottenere i $locationChange~ eventi per farlo funzionare ho imparato che si può effettivamente fare questo sul route utilizzando resolve.

$routeProvider.when(
    '/page', 
    { 
     templateUrl : 'partial.html', 
     controller : 'PageCtrl', 
     resolve : { 
      load : ['$q', function($q) { 
       var defer = $q.defer(); 

       if (/*you only changed the idea thingo*/) 
        //dont reload the view 
        defer.reject(''); 
       //otherwise, load the view 
       else 
        defer.resolve(); 

       return defer.promise; 
      }] 
     } 
    } 
); 
Problemi correlati