2014-06-23 12 views
7

Ich habe eine (Client-Seite) Router in einer Meteor App und Links mit der {{pathFor}} Helfer.Abbrechen der Navigation mit Meteor Eisen-Router

ich eine dirty Flagge in der Session bin Einstellung, wenn der Benutzer ein Formularfeld ändert, und ich möchte eine Warnung auszulösen und ermöglichen dem Benutzer, von der Seite verlassen zu stoppen, wenn das Flag gesetzt ist, im Grunde wie ein onunload Handler .

Ich habe versucht, dies zu tun mit:

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(); 
     } 
    } 
}); 

jedoch während ich die Aufforderung bekommen, bin ich immer noch weg navigiert wird. Das heißt, die pause() scheint die nachfolgende Router-Aktion nicht zu stoppen, was auch immer es ist.

Was mache ich falsch?

Antwort

0

Ist es irgendwo spezifisch Sie wollen gehen? Es gibt auch Router.go (routeName), wodurch die Seite auf den angegebenen routeName verweist. Was ich wollte, ist vielleicht, dass Sie den Router nur zwingen können, auf die aktuelle Seite zu gehen und die Rückwärtsaktion zu vernachlässigen.

+0

Ich möchte, dass der Benutzer die Seite nicht verlässt, d. H. Ich möchte die Route abbrechen. – optilude

6

Von dem, was ich sagen kann, ist dies nicht mit der Eisen-Router-API möglich. Was könnte man jedoch tun, ist die Router.go Methode überschreibt, wie so (irgendwo in Ihrem Client-Code):

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

Sie, Sir, sind ein Genie. :) Es wäre toll, wenn es einen etwas weniger hacky Weg gäbe, aber das funktioniert definitiv. – optilude

0

Das neue Verhalten für Eisen Router soll dies einfacher machen, weil es einen Aufruf an this.next() im onBeforeAction Haken erfordert (siehe iron router guide), so dass nur nennen, wenn die Sitzung nicht verschmutzt ist oder der Benutzer die Warnung bestätigt:

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

ich fand, dass in stop Werken rediecting, und funktioniert auch, wenn Sie nicht Strecken über Router.go Wechsel (wie zB durch Links in meiner Bewerbung).

Hier ist eine Implementierung Coffee eine Klasse mit geerbt von 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

The Iron Router API nicht eine einfache Möglichkeit bieten, dies zu erreichen. Es gibt keine Möglichkeit, einen laufenden Übergang von einem onBeforeAction Hook abzubrechen. Es muss umgangen werden, indem auf die vorherige Route umgeleitet wird.

/* 
* 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 
    } 
}) 

Eine up-to-date-Version kann in this gist finden.