Is there a way to make it so Sammy.JS does not automatically call runRoute when you call app.run()?
My code currently initializes Sammy on the first load, but does not want it to actually call any sammy routes until the user actually clicks a link.
You could try passing in a non-operational route to the run method. It might ignore any route in the hash in that case.
Otherwise, you could set a listener on the document root to listen for clicks in the document and run the application then. But this solution seems "less clean."
(assuming jQuery)
$(function () {
var app = Sammy();
$("a").live(function () {
if (!app.isRunning()) {
app.run();
}
});
});
Question is old but I used the following solution that I find a little cleaner.
The page is loaded normally and Sammy doesn't call the current route when using .run().
http://sammyjs.org/docs/api/0.7.4/Sammy.Application.methods.before
var appIsRunning = false;
var app = Sammy(function() {
this.before('.*', function() {
if (this.path == document.location.pathname && appIsRunning == false) {
return false;
}
});
// The routes...
...
}
// start the application
app.run();
if (app.isRunning()) { appIsRunning = true; }
Related
using Meteor JS, I would like to start a basic jQuery function (wich will resize some elements) everytime a template is loaded.
I tried to call this function inside Meteor.startup() but this doesn't work.
I also tried to launch my function on Router.onBeforeAction() with no more results (im using ironRouter).
Is there any way to do something like :
Template.someTemplate.created = function(){
myUpdateFunction();
};
But instead of loading this on a specific template, i would like to automaticly load this on every templates in my app.
Is there a way to simply achieve this ?
Thanks.
This will log every Template's name after it is created:
Template.prototype.created = function() {
console.log(this.view.name);
}
However your jquery will require the template to be rendered, so this will probably work better:
Template.prototype.rendered = function() {
console.log(this.view.name);
}
I have managed to achieve it by wrapping Blaze._fireCallbacks :
Blaze._fireCallbacks = (function(_fireCallbacks) {
return function(view, which) {
_fireCallbacks(view, which)
if(which === 'rendered') {
//Add your logic here
}
}
})(Blaze._fireCallbacks)
Might not be the most simple solution. See a demo on this pad.
I’m utilizing crossroadsJS and hasherJS on an SPA powered by handlebarsJS. In retrospect I probably should have built the whole thing on Ember, but this late in it’s not wise to start over.
I have hash routes set up that switch my handlebars templates in and out based on whatever was clicked. I’m able to move backwards and forwards between the routes with no problem. However, if I refresh the page, I’m always brought back to my #/home view. I’ve done some research into window.onhashchange and window.onbeforeunload, but none of these seem to be solving the issue.
I have a very specific way of how I’m handling my views. I have a global views object constructed like so:
views.procedures = function (template) {
this.initialize = function () {
this.el = $('<div/>');
this.el.attr('id', 'procedures');
this.el.on('click', '.returned-list li a', this.toResults); // list of API objects by name
};
this.render = function () {
var parts = {
title: 'Procedures View',
};
this.el.html(template(parts));
return this;
};
this.toResults = function () {
cache.justClicked = $(this).attr('data-id');
crossroads.addRoute('procedures/{name}', function () {
api.endpoints.procedure(cache.justClicked); // constructed elsewhere
});
};
this.initialize();
};
I mention this because I can’t simply add in JQuery listeners for any type of hash changes in a $(document).ready() or $(window).onhashchange
I’ve read through both the hasherJS and crossroadsJS documentations multiple times, but I’m not able to think of anything to solve the refresh issue. Thanks in advance for any help.
I would need more information from you, but I'm assuming you're doing
var DEFAULT_HASH = 'home';
if (! hasher.getHash()) {
hasher.setHash(DEFAULT_HASH);
}
This is basically saying your default route is always going to be your home route, which is why you're seeing it when you refresh your current route. Try the following:
var DEFAULT_HASH = 'home', url = hasher.getBaseURL();
if (hasher.getURL() === url) {
hasher.setHash(DEFAULT_HASH);
}
This will check to see what your base URL is (the one that's loaded when you first visit the page) and append a #/home route to the base URL, allowing you to refresh your currently viewed route.
Hope this helps.
I have built an app with SammyJs. It currently works perfectly in the browser. However, when I package it to Android using PhoneGap, the routes does not work anymore.
I have found this SO question. However, the solution given does not work :
(function($) {
var app = $.sammy('[role=main]', function() {
this.disable_push_state = true;
...
});
}
Has anyone ever experienced the same issue?
EDIT
I am also using jquery mobile with the following script to disable its routing :
<script type="text/javascript">
// DISABLE JQM ROUTER
$(document).bind("mobileinit", function () {
$.mobile.ajaxEnabled = false;
$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.pushStateEnabled = false;
$.mobile.changePage.defaults.changeHash = false;
});
</script>
I created a gist with my app sammy javascript (including routes).
I think the problem is with this around clause:
this.around(function(callback) {
var context = this;
url = 'http://localhost:3000/api.json?school=' + localStorage.school
this.load(url)
.then(function(data) {
parsed = JSON.parse(data);
//if (parsed.meta != undefined) {
// alert(parsed.meta.message);
//}
context.products = parsed.products;
context.places = parsed.places;
context.school = parsed.school;
context.title = $('[data-role=header] h1');
})
.then(callback); // *** this won't get called if load() rejects promise
});
As I understand it, the around clause is called with a callback(), which will continue loading the route when it is called.
I think there is a problem with your promise chain. If load() returns a rejected promise (which probably does, as there is no localhost:3000 on your phone), then neither of your then() functions will load. As such, callback() isn't called and the app "stops". I would advise (a) adding some error handling there, so you can see what it happening, and definitely (b) executing callback no matter the result of load(). Also - JSON.parse(data) will throw an error if data is not a proper JSON-encoded string - you want a try/catch around that, too.
I would try this:
this.load(url)
.then(function(data) {
try {
parsed = JSON.parse(data);
} catch(e) {
console.log('error decoding json!: '+errorMsg);
}
//if (parsed.meta != undefined) {
// alert(parsed.meta.message);
//}
context.products = parsed.products;
context.places = parsed.places;
context.school = parsed.school;
context.title = $('[data-role=header] h1');
},function(errorMsg){
console.log('error loading json!: '+errorMsg);
})
.fin(callback); // *** fin() is meant to execute on both success and error, like a "finally".
If your promises implementation does not support fin(), look up what it is calling its equivalent. It is essentially shorthand for: .then(callback).otherwise(callback)
Long story short - you want to make sure that the callback passed to around will be executed no matter what, or you app will not continue loading the route, which is what your unexpected behaviour seems to be.
As for the point about not being able to see the console, I am not sure what your environment looks like, but I have had success with Eclipse and ADT in the past - I can see console logs and errors just fine.
I am new to Javascript and backbone.js, so hopefully I am missing something simple here. I am experimenting with some sample code I found which is supposed to check for unsaved changes before allowing a user to navigate away to another page. I have created a JSfiddle here:
http://jsfiddle.net/U43T5/4/
The code subscribes to the hashchange event like this:
$(window).on("hashchange", router.hashChange);
And the router.hashChange function checks a "dirty" flag to determine whether or not to allow the navigation, like this:
hashChange: function (evt) {
if (this.cancelNavigate) { // cancel out if just reverting the URL
evt.stopImmediatePropagation();
this.cancelNavigate = false;
return;
}
if (this.view && this.view.dirty) {
var dialog = confirm("You have unsaved changes. To stay on the page, press cancel. To discard changes and leave the page, press OK");
if (dialog == true) return;
else {
evt.stopImmediatePropagation();
this.cancelNavigate = true;
window.location.href = evt.originalEvent.oldURL;
}
}
},
The problem is that the code is not working because this.view is undefined, so the 2nd if block is never entered.
I would like the sample program to always ask for confirmation before navigating away from the page (in my sample program, I have set this.view.dirty to always be true, which is why it should always ask for confirmation). Or if there is a better approach, I am open to alternatives.
The main issue is the this context in the methods , this corresponds to the Window Object and not the Router. So it always remains undefined as you are defining view on the router. Declare a initialize method which binds the context inside the methods to router.
initialize: function() {
_.bindAll(this, 'loadView', 'hashChange');
},
Check Fiddle
I spent a lot of time to make at least something decent.
I ended up writing a wrapper for Backbone function:
var ignore = false;
Backbone.history.checkUrl = function() {
if (ignore) {
ignore = false;
return;
}
app.dirtyModelHandler.confirm(this, function () {
Backbone.History.prototype.checkUrl.call(Backbone.history);
},
function() {
ignore = true;
window.history.forward();
});
};
app.dirtyModelHandler.confirm is a function which shows confirmation (Ok, Cancel) view and takes success and cancel functions as arguments.
I don't have enough experience with javascript and jQuery development so I was wondering if someone could tell me how to create a function that uses sammy.js and HTML templating.
This is the working code I have right now:
<script>
;(function($) {
var app = $.sammy(function() {
this.get('#/', function() { $('#content').text(''); });
this.get('#/home', function() { $('#content').load('main.html'); });
});
$(function() { app.run() });
})(jQuery);
</script>
This code puts the main.html's content when I go to or click on ...html#/home but I am looking for a javascript function that just figures out the end point of the URL (the word after ..#/ ) and gets the html page of that same name.
In pseudo-code:
if( somethingWasClicked and uses sammy.js )
loadContent();
function loadContent() {
endpoint = figureOutEndPoint();
$('#content').load(endpoint.html);
}
Thanks for the help
You just need a route with a parameter in it:
this.get('#/:page', function() {
$('#content').load(this.params['page'] + '.html');
});
Make sure that's after your other routes or it will get called for almost everything (such as #/home which you're already handling).
You can, of course, put other parameters in the routes:
this.get('#/:where/:is/:pancakes/:house', function() {
// Do things with this.params['where'], this.params['is'],
// this.params['pancakes'], and this.params['house'].
});
You just need to make sure you get the order right or the routes can fight each other. Routes are matched in the same order that they're added in so the more general catch-all routes usually go at the bottom.