Using Backbone.js to handle browser history - javascript

I'm trying to use Backbone.js to handle the browser history. I'm not setting up Views / Models because I don't want it to handle this, and probably because of this I'm not getting it to work properly.
At this point my page is changing urls. Like:
domain.com/services
domain.com/products
domain.com/contact
domain.com/gallery
domain.com/gallery/photo1
The problem is: if I try to reload the page at domain.com/gallery/photo1. I get the error Uncaught SyntaxError: Unexpected token <
All other pages with just one level permalink works properly on reload. Am I missing something on Backbone?
I'm just using Backbone.Router and Backbone.history.
Is there any simple tutorial on how to set up a site with backbone.js? Just the history thing?
Here's my script:
var Router;
var myRouter;
$(document).ready(function(){
Router = Backbone.Router.extend({
initialize : function(options) {
//
},
routes: {
'' : 'home',
'*actions' : 'pages'
},
home : function() {
this.render('/');
},
pages : function(actions) {
this.render(actions);
},
render : function(path) {
var fullLine = '';
path = (path === '/' || path === '')? '/' : path;
console.log('path: ' + path);
}
});
myRouter = new Router();
Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;
Backbone.history.start({pushState: true, root: "/backbone_teste/"});
// MENU CLICK
$('.menu').children('li').each(function(){
$(this).click(function(){
myRouter.navigate($(this).attr('data-id'), true, true);
});
});
});
Thanks for your help!

Problem Solved:
I just added to my index.php file the following code at the head section:
<base href="http://localhost/backbone_teste/" />
And it works.
Anyway I would like to know why this happens and why Backbone.js documentation don't mention this.
I found the solution at this link: HTML5 History / pushState URLs, .htaccess and You
Thanks

Related

BackboneJs Browser refresh should load the same page

I'm new to backboneJs.
Currently when i do browser refresh, it takes back me to login page.
var AppRouter = Backbone.Router.extend({
routes : {
// Pages
'startup' : 'LoginScreen',
'Home' : 'HomeScreen',
'AssetDetail':'AssetScreen',
'*actions' : 'LoginScreen'
},
...
});
var initialize = function(options) {
var appView = options.appView;
var router = new AppRouter(options);
router.on('route:LoginScreen', function(actions) {
require([ 'login/LoginView' ], function(StartView) {
console.log(" --route login");
var startView = new StartView();
});
});
router.on('route:HomeScreen', function(actions) {
require([ 'home/HomeView' ], function(HomeScreenView) {
console.log(" --route home");
var homeScreenView = new HomeScreenView();
});
});
router.on('route:AssetDetailScreen', function(actions) {
require([ 'views/AssetDetailView' ], function(AssetDetailScreenView) {
var assetdetailScreenView = new AssetDetailScreenView();
});
});
Backbone.history.start({pushState: true});
};
So lets say my current url is http://localhost:8080/myapp/# , and when i do browser refresh (F5 may be) , I want to load the same page.
How do I do it ?, Help me!
Not me who originally wrote this answer but I think it's the best solution.
*"You can call Backbone.history.loadUrl.
To refresh the current page:
*`Backbone.history.loadUrl(Backbone.history.fragment);`*
Or as a link handler:
// Backbone.history.navigate is sufficient for all Routers and will trigger the
// correct events. The Router's internal navigate method calls this anyways.
var ret = Backbone.history.navigate(href, true);
// Typically Backbone's history/router will do nothing when trying to load the same URL.
// But since we want it to re-fire the same route, we can detect
// when Backbone.history.navigate did nothing, and force the route.
if (ret === undefined) {
Backbone.history.loadUrl(href);
}"*
Backbone: Refresh the same route path for twice

Reload the page using sammy.js

I am using sammy.js for single page application in asp.net mvc. Everything is fine, but I am facing one problem which is that I can not reload the page. For example When I am in the dashboard my URL is
http://localhost:1834/#/Home/Index?lblbreadcum=Dashboard
layout.cshtml
<script>
$(function () {
var routing = new Routing('#Url.Content("~/")', '#page', 'welcome');
routing.init();
});
</script>
routing.js
var Routing = function (appRoot, contentSelector, defaultRoute) {
function getUrlFromHash(hash) {
var url = hash.replace('#/', '');
if (url === appRoot)
url = defaultRoute;
return url;
}
return {
init: function () {
Sammy(contentSelector, function () {
this.get(/\#\/(.*)/, function (context) {
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
}).run('#/');
}
};
}
I want to reload the page by clicking the dashboard menu/link. But click event not firing because link is not changing. But if I want to go another page then it is fine. Please help me out. Thanks.
I think you have to append the same partial again. You can't "update" the partial in that meaning.
As you say in your post, when you click another link and then back again it works.
That's what you'll have to do. Append the same page/partial again, by doing that you clear all variables and recreate them, by that simulating a refresh.
EDIT: Added example
Observe that I didn't copy your code straight off but I think you'll understand :)
And I don't use hash (#) in my example.
var app = Sammy(function () {
this.get('/', function (context) {
// context is equalient to data.app in the custom bind example
// currentComponent('home'); I use components in my code but you should be able to swith to your implementation
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
this.bind('mycustom-trigger', function (e, data) {
this.redirect('/'); // force redirect
});
this.get('/about', function (evt) {
// currentComponent('about'); I use components in my code but you should be able to swith to your implementation
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
}).run();
// I did an easy example trigger here but I think you will need a trigger on your link-element. Mayby with a conditional check wheter or not to trigger the manually binding or not
$('.navbar-collapse').click(function () {
app.trigger('mycustom-trigger', app);
});
Please read more about events and routing in sammy.js
Good luck :)
An easier and cleaner way to force the route to reload is to call the Sammy.Application refresh() method:
import { sammyApp } from '../mySammyApp';
const url = `${mySearchRoute}/${encodeURIComponent(this.state.searchText)}`;
if (window.location.hash === url) {
sammyApp.refresh();
else {
window.location.hash = url;
}

pushState in backbone.js

I'm trying to get pushState to work in my backbone app. It works fine when just clicking the link. But if i refresh a page i get 404.
Router
Router = Backbone.Router.extend({
routes: {
'home': 'home'
},
home: function() {
new HomeView({el:'#main-view'})
}
});
When a-tag gets clicked:
event.preventDefault();
App.navigate(event.target.pathname, { trigger: true });
start history:
Backbone.history.start({pushState:true});
and html:
<li>
home
</li>
Whats wrong here?
The problem is you use a real HTML link, so it refreshes the page, it's the normal behaviour.
But you would like to change only the current route, not to reload the page.
For that, you can handle the links to say to Backbone : "handle my links !".
Here is an example of the JS that I use to handle links that have "innerlink" CSS class as a route.
'use strict';
var Backbone = require('backbone');
var $ = require('jquery');
Backbone.$ = $;
module.exports = function() {
// Use absolute URLs to navigate to anything not in your Router.
var openLinkInTab = false;
// Only need this for pushState enabled browsers
if (Backbone.history._hasPushState) {
// console.log('YES you have push state !');
$(document).keydown(function(event) {
if (event.ctrlKey || event.keyCode === 91) {
openLinkInTab = true;
}
});
$(document).keyup(function() {
openLinkInTab = false;
});
// Use delegation to avoid initial DOM selection and allow all matching elements to bubble
$(document).on('click', 'a.innerlink', function(evt) {
// Get the anchor href and protcol
var href = $(this).attr('href');
var protocol = this.protocol + '//';
console.log('backbone_pushstate_router:', href, protocol);
evt.preventDefault();
// Ensure the protocol is not part of URL, meaning its relative.
// Stop the event bubbling to ensure the link will not cause a page refresh.
if (!openLinkInTab && href.slice(protocol.length) !== protocol) {
evt.preventDefault();
// Note by using Backbone.history.navigate, router events will not be
// triggered. If this is a problem, change this to navigate on your
// router.
Backbone.history.navigate(href, true);
}
});
} else {
console.warn('no push state');
}
};
Enjoy :)

Multiple routes not working correctly in backbone.js

I'm trying to create a basic webapp that displays images when a specific URL is reached. In this case, I'm using backbone.js's hash system.
I'm trying to make it so that when "www.website.com/index.html#1" is reached, the first image is displayed using some JavaScript that I have. I also need it so that if "www.website.com/index.html#1/#3/#5" is reached, the first, third, and fifth image is displayed. I know that I have to use multiple routes to do this, but I'm not sure how.
I have one working route for the first image that works awesomely. I just don't know how to adapt it so that it works with multiple routes.
Here's the working hash -
<script>
$(function(){
var hideOne = function () {
//alert("hideOne");
var elem = document.getElementById("one");
elem.className = "hide";
};
var Workspace = Backbone.Router.extend({
routes: {
"test":"test",// #test
},
test: hideOne
});
var router = new Workspace();
Backbone.history.start();
});
</script>
It's awesome, it works, it doesn't even refresh the page. But when I try to add another route to that, it all fails. Like, if I added a "test1":"test1" under the "test":"test", the original "test":"test" won't work anymore(neither will the new one, of course).
I've even tried copying+pasting that entire block of code and trying to make a whole new route block of code. That doesn't work either. I'm really stumped here.
Any suggestions would be awesome.
Thanks
You should limit the scope of your first use case. Don't depend on external functions for now. Do something like
routes: {
"test":function(){
alert("test");
},
"test2":function(){
alert("test2");
}
},
Then change to
routes: {
"test":"test",
"test2":"test2"
},
{
test: function(){
alert("test");
},
test2: function(){
alert("test2");
}
}
Read more: http://mrbool.com/backbone-js-router/28001#ixzz3ANyS0hkR
Once you have that working, then start working on DOM manipulation.
routes: {
"?*:queryString": 'showImages'
},
showImages: function(queryString) {
console.log(queryString); // #1#3#5
}
You can use the route "?*:queryString" to match this URL "www.website.com/index.html#?#1#3#5".
The functions "showImages" will be called and passing the value #1#3#5 in the queryString param.
So from other questions posted on StackOverflow, and some that I posted myself, some great users have helped me out and I've solved it.
Here's the code that I have to use -
<script>
$(function(){
var hideMany = function () {
var toHide = [].slice.call(arguments);
toHide.forEach(function (id) {
if(id === null) { return }
var elem = document.getElementById(id);
if(elem) {
elem.className = "hide";
}
});
};
var Workspace = Backbone.Router.extend({
routes: {
"hide(/:a)(/:b)(/:c)" : "test"
},
test: hideMany
});
var router = new Workspace();
Backbone.history.start();
});
</script>
So when you type "www.website.com/index.html#hide/ID1/ID2/ID3", it'll hide the elements with the IDs that you typed in.
I don't fully understand it, but I'm working on breaking it down and figuring out how it works. Thanks for all the help, guys!

Detect path name changes in ember.js

I have some functionality that i need to change whenever the path changes. Often you would solve that problem with the following.
myProp: ( ->
# .. Do something here
).property('currentPath')
The problem with currentPath, is that it only detect route changes, so the following transition is not detected.
/blog/my-awesome-blog-post -> /blog/new-awesome-post
Because they are working on the same route, but i need to detect when a transition like that happens, as i need to update my social media sharing links.
I have tried something like the following with no luck.
App = Ember.Application.create({
conf: config,
currentPathName: '',
});
App.initializer({
name: 'Path name observer',
initialize: function(container, application) {
var router = container.lookup('router:main');
router.addObserver('url', function() {
var lastUrl = undefined;
return function() {
Ember.run.next(function() {
var url = router.get('url');
if (url !== lastUrl) {
App.set('currentPathName', url);
lastUrl = url;
}
});
};
}());
}
});
And then observe 'App.currentPathName', but this somehow messes the router up, as the url's suddenly doesn't change on click.
Any suggestions?
This is the solution i got from a friendly soul # github. This is not currently documented, but works quiet nicely.
Ember.Router.reopen({
doSomethingOnUrlChange: function() {
console.log(this.get('url'));
}.on('didTransition')
});

Categories