2014-06-23 18 views
7

Ho un router (lato client) in un'app Meteore e collegamenti utilizzando l'helper {{pathFor}}.Interruzione della navigazione con il ferro-router Meteor

Sto installando una bandiera dirty nel Session quando l'utente modifica un campo di modulo, e voglio far scattare un avvertimento e consentire all'utente di interrompere la navigazione dalla pagina se è impostato il flag, fondamentalmente come un onunload gestore .

Ho provato a fare questo con:

Router.onBeforeAction(function(pause) { 
    var self = this; 

    if (!this.ready()) { 
     return; 
    } 

    if(Session.get('dirty')) { 
     if(!confirm("Are you sure you want to navigate away?")) { 
      pause(); 
     } 
    } 
}); 

Tuttavia, mentre ricevo la richiesta, sto ancora navigato via. Cioè, il pause() non sembra fermare la successiva azione del router, qualunque essa sia.

Cosa sto sbagliando?

risposta

0

È specifico che vuoi andare? C'è anche Router.go (routeName) che farà in modo che la pagina punti al nome percorso specificato. Quello che stavo cercando è che puoi semplicemente forzare il Router ad andare alla pagina corrente trascurando quindi l'azione posteriore.

+0

Desidero che l'utente non lasci la pagina, ovvero voglio interrompere il percorso. – optilude

6

Da quello che posso dire questo non è possibile con l'API ferro-router. Che cosa si potrebbe fare, tuttavia, è l'override del metodo Router.go in questo modo (da qualche parte nel codice cliente):

var go = Router.go; // cache the original Router.go method 
Router.go = function() { 
    if(Session.get('dirty')) { 
    if (confirm("Are you sure you want to navigate away?")) { 
     go.apply(this, arguments); 
    } 
    } else { 
    go.apply(this, arguments); 
    } 
}; 
+0

Signore, sei un genio. :) Sarebbe bello se ci fosse un modo leggermente meno hacky per farlo, ma questo funziona sicuramente. – optilude

0

Il nuovo comportamento per i router di ferro dovrebbe rendere questo più facile perché richiede una chiamata al this.next() nel gancio onBeforeAction (vedi iron router guide), in modo che solo chiamata che quando la sessione non è sporco o l'utente conferma l'avvertimento:

if(Session.get('dirty')) { 
    if(confirm("Are you sure you want to navigate away?")) { 
     this.next(); 
    } 
} else { 
    this.next(); 
} 
0

ho scoperto che rediecting in stop opere, e funziona anche quando non sta modificando le rotte via Router.go (ad esempio tramite collegamenti nella mia applicazione).

Ecco un'implementazione CoffeeScript utilizzando una classe ereditata da RouteController

class MyRouteController extends RouteController 
    stop: -> 
    # Save whether you data/form is dirty or whatever state you have in 
    # a Session variable. 
    if Session.get('formIsDirty') 
     if !confirm('You have unsaved data. Are you sure you want to leave?') 
     # Redirecting to the current route stops the current navigation. 
     # Although, it does rerun the route, so it isn't a perfect solution. 
     Router.go '/my_route' 
     # Return here so we don't perform any more of the stop operation. 
     return 
    # Otherwise do as normal. 
    super 
0

L'API router di ferro non offre un modo semplice per raggiungere questo obiettivo. Non è possibile annullare una transizione in corso da un hook onBeforeAction. Deve essere risolto spostando il percorso precedente.

/* 
* Adds a confirmation dialogue when the current route contains unsaved changes. 
* 
* This is tricky because Iron Router doesn't support this out of the box, and 
* the reactivity gets in the way. 
* In this solution, redirecting to the current route is abused 
* as a mechanism to stop the current transition, which Iron Router has no API 
* for. Because the redirect would trigger the onStop hook, we keep track of 
* whether to run the onStop hook or not ourselves in 
* `skipConfirmationForNextTransition`. 
* 
* When `Session.get('formIsDirty')` returns `true`, the user will be asked 
* whether he really wants to leave the route or not. 
* 
* Further, another confirmation is added in case the browser window is closed 
* with unsaved data. 
* 
* This gist shows the basics of how to achieve a navigation confirmation, 
* also known as canceling a route transition. 
* This approach may fail if other route hooks trigger reruns of hooks reactively. 
* Maybe setting `skipConfirmationForNextTransition` to `true` could help in those 
* cases. 
*/ 
Session.setDefault('formIsDirty', false) 
const confirmationMessage = 'You have unsaved data. Are you sure you want to leave?' 

// whether the user should confirm the navigation or not, 
// set to `true` before redirecting programmatically to skip confirmation 
let skipConfirmationForNextTransition = false 
Router.onStop(function() { 
    // register dependencies immediately 
    const formIsDirty = Session.equals('formIsDirty', true) 
    // prevent duplicate execution of onStop route, because it would run again 
    // after the redirect 
    if (skipConfirmationForNextTransition) { 
    skipConfirmationForNextTransition = false 
    return 
    } 
    if (formIsDirty) { 
    const shouldLeave = confirm(confirmationMessage) 
    if (shouldLeave) { 
     Session.set('formIsDirty', false) 
     return 
    } 
    // obtain a non-reactive reference to the current route 
    let currentRoute 
    Tracker.nonreactive(function() { 
     currentRoute = Router.current() 
    }) 
    skipConfirmationForNextTransition = true 
    // "cancel" the transition by redirecting to the same route 
    // this had to be used because Iron Router doesn't support cancling the 
    // current transition. `url` contains the query params and hash. 
    this.redirect(currentRoute.url) 
    return 
    } 
}) 

// Bonus: confirm closing of browser window 
window.addEventListener('beforeunload', event => { 
    if (Session.get('formIsDirty')) { 
    // cross-browser requries returnValue to be set, as well as an actual 
    // return value 
    event.returnValue = confirmationMessage // eslint-disable-line no-param-reassign 
    return confirmationMessage 
    } 
}) 

Una versione up-to-date si possono trovare in this gist.

Problemi correlati