我在Meteor应用程序中有一个(客户端)路由器,并使用{{pathFor}}
帮助器进行链接。
当用户更改表单字段时,我在dirty
中设置Session
标记,并且我想触发警告并允许用户停止导航离开页面,如果标记是设置,基本上像onunload
处理程序。
我试图这样做:
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();
}
}
});
然而,当我得到提示时,我仍然被导航了。也就是说,pause()
似乎不会阻止后续路由器操作,无论它是什么。
我做错了什么?
答案 0 :(得分:6)
据我所知,铁路由器API无法实现这一点。但你可以做的是覆盖Router.go方法,就像这样(在你的客户端代码中的某个地方):
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);
}
};
答案 1 :(得分:0)
这是某个你想去的地方吗?还有Router.go(routeName),它将使页面指向给定的routeName。我想要的是,也许你可以强迫路由器转到当前页面,因此忽略了后退动作。
答案 2 :(得分:0)
铁路由器的新行为应该使这更容易,因为它需要在onBeforeAction挂钩中调用this.next()
(请参阅iron router guide),因此只在会话不脏或用户时调用它确认警告:
if(Session.get('dirty')) {
if(confirm("Are you sure you want to navigate away?")) {
this.next();
}
} else {
this.next();
}
答案 3 :(得分:0)
我发现stop
中的重定位有效,即使您没有通过Router.go
更改路由(例如我的应用程序中的链接)也能正常工作。
以下是使用继承自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
答案 4 :(得分:0)
Iron Router API无法提供实现此目的的简便方法。无法取消onBeforeAction
挂钩的持续转换。它必须通过重定向到前一个路径来解决。
/*
* 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
}
})
可以找到最新版本in this gist。