i have a situation here that i can't seem to figure out. Please if anybody knows how to resolve this i would love to hear suggestions.Thanks
I have a "global view" that is visible on a subnavbar in the app, that is a calendar, this calendar serves as a global calendar throughout the application, so almost all the views use the calendar view & model to set show data according to the date selected.
This calendar view/model should have some way to store in history each time the date is changed, this (i think) is done using a single URL or query string parameters each time the date is changed, something like
webapp/view1?date=20120301
and when the date is changed, so its the query string.
I would like to use query string parameters for this so i don't have to specify on each route the (/:date) optional parameter.
THE THING IS backbone stopped firing a route change or a history event when query strings are changed, they simply ignore query strings on the Backbone.History implementation, this is breaking all my implementation cause i can't track each time the querystring is changed, so the "back" button will not fire a change event and therefore i can't change the date on the model that would change the date on the calendar.
I know a simple solution to this would be just using "pretty URL" and adding that date parameter to each view, but im trying to avoid that.
Any suggestions? Thanks in advance
UPDATE
I ended up using "pretty URLs" like the Backbone documentation suggests, cause using query strings would bring me a lot of trouble for tracking the URL change and history, also wouldn't work as expected when using hashchange instead of pushState.
So, my code ended up like this:
Attaching somewhere in your router, view, controller, something, to the "route" event of your router, to check the URI for the date and set this date to the calendar picker:
this.listenTo(myRouter, "route", this.routeChanged);
Then, this method would do something like:
checkURIdateParameter: function (route, arr) {
var found = false;
for (var i = 0; i < arr.length ; i++) {
if (arr && arr[i] && arr[i].indexOf("date=") != -1) {
if (app.models.dateControl) {
var dateFromParameter = new Date(arr[i].substring("date=".length).replace(/\$/g, ":"));
dateFromParameter = (isNaN(dateFromParameter.getTime())) ? app.models.dateControl.defaults.date : dateFromParameter;
app.models.dateControl.set("date", dateFromParameter);
found = true;
}
}
}
if (!found) app.models.dateControl.set("date", app.models.dateControl.defaults.date, {changeURI:false});
}
This serves as the function that will read params from the URI and reflect those changes on the dateControl.
There should be another method that will be the one in charge of updating the URI to a new one each time the date is changed (so that the params are in sync with the view) and the link can be copied and pasted with no problems.
Somewhere on your router, view, controller:
this.listenTo(app.models.dateControl, "change:date", this.updateURIdateParameter);
This is a method that is attached to a model that has the current date, this model is updated by the calendar picker (the UI control) or the method that was linked with the route event (routeChanged, look above).
This method should do something like this:
, updateURIdateParameter: function (a, b, c) {
if (c && c.changeURI == false) return; //this is in case i don't want to refresh the URI case the default date is set.
var currentFragment = Backbone.history.fragment;
var newFragment = "";
var dateEncoded = app.models.dateControl.get("date").toJSON().replace(/\:/g, "$");
newFragment = currentFragment.replace(/\/date=([^/]+)/, "") + "/date=" + dateEncoded;
if (newFragment != currentFragment) {
app.router.navigate(newFragment, false);
}
}
This method gets the currentDate selected from the corresponding model, parses it, then takes the URL from the Backbone.history.fragment, execs a nice regexp against it that will replace the old date parameter (if exists) and then appends the new encoded date. Then navigates to this route in silent mode so that the method that checks the route is not called (this prevents annoying loops).
I hope this helps.