Marionette app 2 way navigation with history api - javascript

I have node.js server application (rest API service).
I also have Backbone + Marionette(for my serverside RESTful app) multiple page app at the client side.
I currently have Marionette navigation which is work pretty good with links like domain.com/#feedbacks (pages are render on client side with ajax data). But I also want to add serverside navigation e.g. domain.com/feedbacks (for google and other seach engines).
The question is: How can I match serverside and clientside navigations?
Mb I should try to add event handler for all links on page, which is will do something like Backbone.history.navigate("/feedbacks")? But I have a lot different hash links(#feedbacks)... Mb there is a more elegant solution? Thank you.
My current marionette router:
var AppRouter = Backbone.Blazer.Router.extend({
routes: {
'': new HomeRoute(),
'sell': new SellRoute(),
'login': new LoginRoute(),
'feedbacks': new FeedbacksRouter(),
'product/:id': new ProductRoute(),
'profile/:id': new UserRoute()
}
})

I just had to use:
Backbone.history.start({pushState: true})
instead of:
Backbone.history.start();
It make backbone routing work without # symbols

Related

SignalR only available in the active SILO

Im developing a real time application using SignalR, im using MVC and Angularjs (SILO). Each cshtml page is a SPA. i have an angularjs common service which contains generic operations like delete, post etc.. Also in my common service i introduced signalR. The problem im having is that since the Serivice is only loaded when a SPA loads, so signalR only works in that SPA. What i want is my signalR to be available in my entire application.. what can i do to achieve this?
My Common Service Code
self.hub = $.connection.MyHub;
var initializeSignalR = function () {
self.hub.client.addIssue = function (issue) {
alert(JSON.stringify(issue));
};
$.connection.hub.url = "https://sitename.azurewebsites.net/signalr";
$.connection.hub.logging = true;
$.connection.hub.start().done(function () {
var tenant = sessionStorage.getItem("tenantName");
if (tenant !== "") {
self.hub.server.subscribe(tenant);
} else {
console.log("Error occured");
}
});
};
initializeSignalR();
And on my SILO i have this
viewModelHelper.hub.on('addIssue', function (issueItem) {
issues.push(issueItem);
});
viewModelHelper is my service, lets say if im in SPA Home, signalR methods in SPA Contacts are not excecuted, i understand why, Its because my service is not initialized in that SPA. How can i achieve signalR availability throughtout my app even when the SPA is not loaded.
I think you will have two options:
Load it again in every SILO by placing your SignalR service reference in shared layout. This can keep your current application structure.
Change your app to become real Single Page App(SPA) then you can load and reuse just one SignalR connection in entire app. But this will changed so much of your current system. In that way, you can not use cshtml as current, all view layer and some part of logic will be pushed to client side.

Backbone router with no hashbangs

I've set up a super simple Backbone app with just a router and two views to try and nail down the correct way to handle routing with no hashbangs.
var Router = Backbone.Router.extend({
routes: {
'': 'index',
'episodes': 'episodes'
},
index: function () {
var view = new IndexView();
view.render();
},
episodes: function () {
var view = new EpisodesView();
view.render();
}
});
var IndexView = Backbone.View.extend({
el: $('#primary'),
render: function () {
console.log('index view');
}
});
var EpisodesView = Backbone.View.extend({
el: $('#primary'),
render: function () {
console.log('episodes view');
}
});
var router = new Router;
Backbone.history.start({pushState: true});
I realize that the history object allows forward and backward navigation between pages, which is great. However, the way it's actually implemented seems a little messed up to me.
For instance, I created a simple MAMP server to serve an index.html file and the JS file. Navigating to http://backbone:8888/, the console logs index view like I'm telling it to. However, navigating to http://backbone:8888/episodes (by typing it into the address bar) returns a 404. BUT, if I navigate to http://backbone:8888/#episodes, the URL redirects to http://backbone:8888/episodes (without the hashbang) and I get episodes view logged to the console, which obviously means it's hitting that EpisodesView view.
From here, I can go back and forth between the index and episodes views. (back hits /, forward hits /episodes). That's all fine and dandy until I hit refresh while on /episodes again. 404...
So my question is this: how can Backbone be set up to handle URLs without relying on hashbangs? Everything I've found on the topic says "oh just pushState!". Well, I'm using pushState and, like I described above, you can't hit a URL like /episodes directly without getting a 404.
When you use push state, pages are served from the back end, which means that you have to define a corresponding route in your back end that corresponds to a front end route.
If the back end doesn't find the requested route, then it will deliver a 404 message, because it won't know what to serve. In your case, the episodes view gets triggered at the front end level, but the browser doesn't have a DOM to render the view when the page gets refreshed because nothing was served.
By default, the route http://backbone:8888/ will serve the index file because this is how the webserver is configured.
I'm not sure what back end technology you are using, but for serving a file from http://backbone:8888/episodes, just make sure that your back end has a router set up that serves the requested route and it should work.

S3 web hosting for backbone.js application with pushState

I'm hosting a Backbone application on Amazon S3 using a custom domain name. The Backbone application router handles all routes under the root ('/'). I would like to use pushState, so there's no need for the # prefix on my application routes.
Basically, i want all sub-routes to be routed by S3 to the domain root and let Backbone do the rest.
I added the following rule:
<RoutingRules>
<RoutingRule>
<Condition>
<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals >
</Condition>
<Redirect>
<HostName>mydomain.com</HostName>
<ReplaceKeyPrefixWith>#</ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
</RoutingRules>
But this just adds the # sign prefix to all my sub-routes. I want to avoid that.
How do I set the redirection rules on my S3 bucket to route everything to the indexed document without having to add the #?
Use bucket URL instead of your domain URL:
<HostName>BUCKET_NAME.s3-website-ap-northeast-1.amazonaws.com</HostName>
Also check you anchor links dont have # in url Home instead have links like this:
Home
About
Then using jQuery you can navigate the link to router
$(document).on('click', 'a[href^="/"]', function (e) {
e.preventDefault();
var href = $(e.currentTarget).attr('href');
Backbone.history.navigate(href, { trigger: true });
});

Converting Backbone.js App to communicate with parse.com

I am an IT student and I'm learning how to use Backbone.js. I read all the documentation but I find it easier to learn when I use example apps,because I never have been programming this type of apps,so it was hard and confusing to think of a way to build my own app, so I used https://github.com/dperrymorrow/example-backbone-app to make similar edited app. The example app doesn't have a server side.
Now I need to connect the app to use parse.com as a backend(server-side) instead to use local collection.
If someone could please tell me what should I change and transform in the code so it connects example app to parse.com app with REST API so when I edit something in the app to be syncronized with parse.com.
I will be really grateful if someone is willing to explain this in a more descriptive way than saying :"you should read documentatin" because I did,and I still don't get the point :)
Have a nice day.
It's just about having the right backbone models and collections and settings the right url on the collection and urlRoot on the model. Then you can just can just call backbone methods like sync, save or delete.
Best detailled answer covering also the REST explanation probably is this one.
Cant you just swap the backbone collection and model to Parse's ones?
Parse.com is a webservice providing REST interfaces for anything you like, Lets connect that to our Backbone models.
First of all Lets create a new app on Parse.com, mine is called FunkyAppartments.
Insert the script tag for loading Parse javascript lib into index.html or whathever:
<script src="http://www.parsecdn.com/js/parse-1.5.0.min.js"></script>
Switch the backbone model and collection to use parse types instead (and rename the fetch method if you have extended backbones, since we do not want to overide the one of parse):
//var Appartment = Backbone.Model.extend(); Backbone wo. Parse.com
var Appartment = Parse.Object.extend("Appartment");
//var Appartments = Backbone.Collection.extend({ Backbone wo. Parse.com
var Appartments = Parse.Collection.extend({
model: Appartment,
initializeData: function(){
var self = this;
var callback = function (data){console.log(data); self.reset(data)};
S.Appartments.loadAppartments(callback);
},
loadAppartments: function(callback){
debugger;
this.query = new Parse.Query(Appartment);
var result = this.fetch();
callback(result);
return result;
}
});
I added a debugger tag in the load appartments so that developer tools breaks in the middle of the controller, here I have access to the Appartment private type of the controller, hence i can store some data on the parse server and verify by pasting the below in the developer tools console.
var testAppartment = new Appartment();
testAppartment.save({name: "foobars"}).then(function(object) {
alert("yay! it worked");
});
Yei, the data shows up in the parse.com UI for the app we just added there. And more importantly it shows up in our frontend. That was easy!

Backbone Routing with Static HTML files

I'm working on a website where we are using 3rd Party web services to return dynamic content and using javascript to parse and display that data from to the page. We are already using backbone in a couple places on the site to post data to web services so I had the thought of trying to use Backbone's router to run specific functions based on the page url and grabbing the query because we are hashing the queries to the url of the page.
For example: global-site-search.html#query
This is the router code I have to this point:
var Router = Backbone.Router.extend({
routes : {
'' : 'indexRoute',
'global-site-search.html(:query)' : 'getSearchResults'
},
indexRoute: function(query) {
console.log("indexRoute");
},
getSearchResults: function(query) {
console.log("getSearchResults with query", query);
}
});
var WaRouter = new Router();
Backbone.history.start({
pushState: true,
root: '/'
});
But when I hit the page with a url like global-site-search.html#query the query value returns null. Has anyone tried this before or am I trying to extend Backbone's router to far in handling this?
Is global-site-search.html from your server?, if yes then the config for router should be
':query' : 'getSearchResults'
If no, then you can't do that, because Backbone.Router uses the hash part of the current page URL to track pages. And since global-site-search.html is not containing any backbone code, it can't do anything. It is possible only if you somehow can inject your router code into global-site-search.html which is illegal in this case
Updated: this should allow you to search with this route ':query' : 'getSearchResults'
Backbone.history.start({
pushState: true,
root: window.location.pathname
});
When using router, you need to set the correct root, so using window.location.pathname is the easiest way to do that. Also, according to Backbone documentation
and if a hash URL is visited by a pushState-capable browser, it will be transparently upgraded to the true URL. Note that using real URLs requires your web server to be able to correctly render those pages, so back-end changes are required as well. For example, if you have a route of /documents/100`
Since you are not having any real back-end to handle pushState, I suggest that you turn it off

Categories