How to prevent navigating to another page in meteor iron router - meteor

I have a form page and I want to alert user if he leaves it without saving the form.
Typically I can achieve this purpose by stating a function window.onBeforeUnload.
window.onBeforeUnload = function(){return 'Please save the form before navigating';}
But it seems doesn't work in my project using Meteor and Iron Router.
Any suggestion?

This is maybe a hacky version, but it works:
isUnsaved = ->
return unless #ready()
unless confirm 'Do you really want to leave the page?'
Router.go(#url)
Router.onStop isUnsaved,
only: [
'editPost'
]

Old post, but just solved it. Here is my solution :
Router.route('/myPath', {
unload: function (e, obj) {
if(Session.get("hasChanged")){
if (confirm("Are you sure you want to navigate away ?")) {
// Go and do some action
}else{
// Redirect to itself : nothing happend
this.redirect('/myPath');
}
}
}
}

Related

Meteor AccountTemplates/UserAccounts - how to run code on email verify?

I've got some code I want to run after the user verifies their email.
Where would I put that?
The only place I can think is a redirected route, but that's a bit hacky, and relies on the user waiting for the redirect to happen. I'm using iron-router.
This was my first attempt, but the recalculate function is server-side.
AccountsTemplates.configureRoute('verifyEmail', {
redirect: function(){
var user = Meteor.user();
if (user) {
user.recalculateSignUpReputation();
Router.go('home');
}
}
});
Here's a solution observing a cursor but that seems like overkill. I'd prefer an event. Solution #1 didn't work for me.
thanks for the comments. I ended up doing this.
AccountsTemplates.configureRoute('verifyEmail', {
redirect: function(){
var user = Meteor.user();
if (user) {
Meteor.call('recalculateSignUpReputation');
Router.go('home');
}
}
});
It works client side, and makes a call to the server-side code. Not awesome, but works. If you have a different/better way, I'll mark it the correct answer.

First Sign-in after Signup Show Config Page Once Effectively

I'm trying to show a popup or a template page if user has signed in for the first time after sign up basically allowing them configure some stuff on that page before going to dashboard home, It's only needed for convenience and here is what I got (telescope code)
Router.onBeforeAction(hasCompletedChannels);
hasCompletedChannels: function() {
if(!this.ready()) return;
var user = Meteor.user();
if (user && ! userCompletedChannels(user)){
this.render('connectChannels');
} else {
this.next();
}
}
Which I don't really like because this will always run every time, I want it to run just once, And don't even execute the check function. Is it possible to detect first sign in? (After signup)
I think you could just tie it to the specific route. Right now you're tying it to the Router object (every render forces that check as you point out). So if you define your login function to send someone to a specific route after sign-in, you could just verify on that route.
The function Accounts.onLogin gives you a way to do stuff after the login.
Something like
Router.route('profile', {
path: '/profile',
onBeforeAction: function() {
// Check some stoof
// If first time logged in
// render first time template
// else
// this.next() will render the profile page
},
waitOn: function() {
return [
// some subs
];
},
data: function() {
// some data
}
});
I'm assuming that its going to get routed to a page called profile (seems to make sense). You could check for first time logged in by some attribute you use in the user object and the fields you want filled out and force a render of a different template, or a subtemplate. Check out the Iron Router guide for more ideas on ways to configure it.
Best of luck

Framework7 starter page "pageInit" NOT WORKING

anyone using framework7 to create mobile website? I found it was great and tried to learn it by myself, now I meet this problem, after I create my App, I want to do something on the starter page initialization, here, my starter page is index.html, and I set data-page="index", now I write this below:
$$(document).on('pageInit', function (e) {
var page = e.detail.page;
// in my browser console, no "index page" logged
if (page.name === 'index') {
console.log("index page");
});
// but I changed to any other page other than index, it works
// my browser logged "another page"
if(page.name === 'login') {
console.log('another page');
}
});
Anyone can help? Thank you so much.
I have also encountered with the same problem before.
PageInit event doesn't work for initial page, only for pages that you navigate to, it will only work for index page if you navigate to some other page and then go back to index page.
So I see two options here:
Just not use pageInit event for index page - make its initialization just once (just make sure you put this javascript after all its html is ready, or e.g. use jquery's on document ready event)
Leave index page empty initially and load it dynamically via Framework7's mainView.loadContent method, then pageInit event would work for it (that was a good option for me as I had different index page each time, and I already loaded all other pages dynamically from underscore templates)
I am facing same issue and tried all solutions in various forums.. nothing actually worked. But after lot of RnD i stumbled upon following solution ...
var $$ = Dom7;
$$(document).on('page:init', function (e) {
if(e.detail.page.name === "index"){
//do whatever.. remember "page" is now e.detail.page..
$$(e.detail.page.container).find('#latest').html("my html here..");
}
});
var me = new Framework7({material: true});
var mainview = me.addView('.view-main', {});
.... and whatever else JS here..
this works perfectly..
surprisingly you can use "me" before initializing it..
for using for first page u better use document ready event. and for reloading page event you better use Reinit event.
if jquery has used.
$(document).on('ready', function (e) {
// ... mainView.activePage.name = "index"
});
$(document).on('pageReinit', function (e) {
//... this event occur on reloading anypage.
});

Durandal: How to route away from current view within that view's activate() function?

I have the following:
function activate(routeData) {
// make dataservice call, evaluate results here. If condition is met, reroute:
if (true){
router.navigateTo("#/someRoute");
}
alert ("should not be shown");
}
The alert is getting hit however, and then the view changes.
How do I fully navigate away from the current item and prevent any further code in that vm from being hit?
Update:
I tried using guardroute but I have to activate the viewModel to call the dataservice that returns the data that determines whether or not I should re-route. Using guardroute totally prevents the dataservice from getting called (since nothing in the activate function will get hit).
I also tried returning from the if block but this still loads the view / viewAttached / etc so the UX is glitchy.
The following worked for me in Durandal 2.0:
canActivate: function() {
if(condition)
return {redirect: 'otherRoute'};
return true;
}
activate: // Do your stuff
It's mentioned in the documentation: http://durandaljs.com/documentation/Using-The-Router.html
Here's #EisenbergEffect answer to a quite similar discussion in google groups.
Implement canActivate on your view model. Return a promise of false,
then chain with a redirect.
You might want to give #JosepfGabriel's example (discussion) a try in Durandal 1.2. Check the correct router syntax for your Durandal version, you might have to substitute it with something like router.navigateTo("#/YourHash", 'replace').
canActivate: function () {
return system.defer(function (dfd) {
//if step 2 has a problem
dfd.resolve(false);
})
.promise()
.then(function () { router.navigate("wizard/step1", { trigger: true, replace: true }); });
}
However this is NOT working in Durandal 2.0 and there's a feature request https://github.com/BlueSpire/Durandal/issues/203 for it.
You can't call redirect into the active method.
You can override the guardRoute method from router, to implement redirections.
You can do somehting like that:
router.guardRoute= function(routeInfo, params, instance){
if(someConditios){
return '#/someRoute'
}
}
You can return a promise, true, false, the route to redirect... You can find more information about that in the next link: http://durandaljs.com/documentation/Router/
Rainer's answer was pretty good and works for me adding this small fix.
Inside the then() block simply call the navigation like this
setTimeout(function() { router.navigateTo('#/YOUR DESTINATION'); }, 200);
that should fix your problem. The setTimeout does the trick. Without it the newly navigated page catches the old NavigationCancel from the previous one.
Adding a return in your if (true) block should fix this.
function activate(routeData) {
if (true){
router.navigateTo("#/someRoute");
return;
}
alert ("should not be shown");
}

Meteor: redirect a user if already logged in

I'm using meteor-router, and I'd like to redirect a user to /user if he requests / and he is already logged in.
As expected, this just renders the user_index template rather than changing the URL:
Meteor.Router.add
'/': -> if Meteor.userId() then 'user_index' else 'index'
I want to do something like this:
Meteor.Router.add
'/': -> if Meteor.userId() then Meteor.Router.to '/user' else 'index'
update 6/4/14:
This question is no longer relevant, and iron-router should be used instead.
meteor-router is now deprecated. Instead use iron-router which can redirect based on logged in status using:
Router.configure({layoutTemplate: 'mainLayout'});
Router.map(function() {
this.route('splash', {path: '/'});
this.route('home');
});
var mustBeSignedIn = function(pause) {
if (!(Meteor.user() || Meteor.loggingIn())) {
Router.go('splash');
pause();
}
};
var goToDashboard = function(pause) {
if (Meteor.user()) {
Router.go('home');
pause();
}
};
Router.onBeforeAction(mustBeSignedIn, {except: ['splash']});
Router.onBeforeAction(goToDashboard, {only: ['splash']});
Example taken from: Meteor.js - Check logged in status before render
--OR--
Use the accounts-entry package. From their site:
Ensuring signed in users for routes
Use AccountsEntry.signInRequired(this) to require signed in users for
a route. Stick that in your before hook function and it will redirect
to sign in and stop any rendering. Accounts Entry also tracks where
the user was trying to go and will route them back after sign in.
You're looking for a filter -- here is a sample from the docs:
Meteor.Router.filters({
'checkLoggedIn': function(page) {
if (Meteor.loggingIn()) {
return 'loading';
} else if (Meteor.user()) {
return page;
} else {
return 'signin';
}
}
});
// applies to all pages
Meteor.Router.filter('checkLoggedIn');
According to this issue it looks like redirects are not part of meteor-router, and may not be. For now I ended up working around the issue. If the project changes to accommodate redirects I'll update my answer, or someone else can post another answer.
update 1/23/13:
I switched to using mini-pages, which correctly deals with this case and includes a lot of great functionality like layouts.
Meteor Router lets you directly access the response object, so you can just do a 302 redirect. Something like the following will work:
Meteor.Router.add("/test/:_id", (id) ->
this.response.writeHead '302', {'Location': '/blah/' + id}
)
You can do this by using a standard filter and wrapping the redirect in a defer object.
Meteor.Router.filters({
requireLogin: function(page) {
if(! (Meteor.loggingIn()|| Meteor.user()) ){
Meteor.defer(function () {
Meteor.Router.to('/login');
});
}
return page;
}
Meteor.Router.filter('requireLogin', {except: 'login'});

Resources