I have a working website build on top of Google App Engine (Python + Jinja2 template engine). I would like to start redesigning it to be single page application using Backbone.js and Underscore.js. The goal is to use progressive enhancement strategy.
The site will still be rendered using backend on the first visit. And then if the browser supports JavaScript the Backbone.js will take over.
I decided to do it this way for two reasons. First all the links I already have will stay intact and second the Google indexing bot will be able to crawl the site content.
I have two problems with this approach:
I need to have two templates for almost everything on my site one on the backend (Jinja2) and one on the frontend (Underscore.js). I was wondering what are the best practices in cases like this? Is there anything you can suggest to avoid having two templates for everything?
How do I load the templates for the frontend to use Backbone.js + Underscore.js? I can load them all in the initial request or request them asynchronously when they are needed.
I appreciate any thoughts!
Thanks.
Some resources:
http://ricostacruz.com/backbone-patterns/
This one describes how to bind Backbone.js to existing HTML:
http://lostechies.com/derickbailey/2011/09/26/seo-and-accessibility-with-html5-pushstate-part-2-progressive-enhancement-with-backbone-js/
So I recently(this year) went through a similar situation. I'll let you know a head of time that #1 is an incredibly tough thing to deal with. Keep in mind, that you not only would have to duplicate your templates, but ALL business logic surrounding your site. For example, let's say you allow users to add comments on a particular page. Using the method you described, you would have to both have a comment template on the server-side and the client-side, and additionally, duplicate the logic required to add/delete/edit a comment on both the client and the server(to accommodate users with and without javascript). Duplication of the templates is easy using Jinja2 function blocks, but the duplication of the logic is where it gets interesting. I attempted to do just that, and ended up doing a full re-write a few months later.
So the advice I would give to you is ditch the idea that you can support both javascript and non-javascript users. Make your site for one or the other. I personally chose to go the javascript route myself. This leaves you with two options. Make a single page app, or make an app that largely leverages javascript for functionality, but renders everything server-side. There are probably a number of other options, but those are the two most popular that I have seen. I went with the second option. So what I do, is the initial page load is done by the server. Backbone.js then consumes each element and makes models and views out of them. This is largely done leveraging data attributes. So for example to create a comment view I would have an element like this:
<div class="comment" data-id="1" data-body="You Suck"></div>
I would then consume said comment, and create a model out of it like so:
var CommentModel = Backbone.Model.extend();
var comment_el = $('.comment');
var comment_model = new CommentModel($(comment_el).data());
Finally, I would back a view with that created model, which can then add functionality to the site:
var CommentView = Backbone.View.extend({
initialize: function() {},
edit: function() {},
delete: function() {}
});
var comment_view = new CommentView({
model: comment_model
});
Then you might be asking, "What if I need to re-render something, don't I need client-side templates for that?" Nope. Client-side templates are a pretty new thing. I personally try to avoid them as I don't think we're quite there yet, and I have always felt that single-page apps are just not responsive enough for my tastes. I'm sure there are plenty of people who would disagree with me on that, but that's the stance I took with my most recent project. So that being said, I render everything on the server and send the html to the client in the form of JSON, which I then inject into the DOM. So I have a ton of api endpoints, which return JSON to my Backbone.js code. This is what is currently working out for me, but this problem is largely situational usually. You have to really look at what your needs are. For it's worth, I largely based my current system off of what Twitter eventually decided to do after trying the whole single-page app thing. You can read about it here.
Related
I want to design a blog which will contain several articles. In the home page several tiles will provide links to the articles and when a user clicks on a particular tile with an article's title on it, he will be redirected to a new page having that complete article.
I understand that making a single page application will be of little help in this case.
Will it make sense if I design the whole website using Angular JS? If yes, how should I proceed if I want to design it using Angular JS? Should I avoid using routing since I've learnt that it is primarily used for SPAs, and shall I use $location or something for this instead? Or shall drop the idea of designing using Angular JS at all? Has anyone of you ever designed a multi-page application using Angular JS?
Your guidance will be helpful.
Before identifying the language to use for designing an app, it is important to understand what your app would be doing. In your case, a blog.
and if you analyze the app's functionality, the below three items (there are/could be more but for this use case, these three are sufficient) gain prominence:
Flow
Data
UX
The 1. Flow says that you may not have a SPA but a MPA, which means considering the resources that go into making of the pages, the user experience, it being a blog, a user may not have all that commitment (or patience) to remain with the blog if each click results in a request sent to the server and a heavy duty page served for the user to read through. This means that routes (Express or Angular) are ideal to navigate the user through the blog.
Data
A blog typically contains text and users may perform text search, which means that you need to figure out the right data store for your data ie., text.
This leads you to select the most optimally suited database that is also economical - SQL Server provides for Full text search at a cost of some hefty dollars; MySql does, too, and obviously with no or lesser cost; MongoDb, a document db, gives you the same and with no additional cost (unless you opt for the cloud model). So, SQL Server is not ideal since the app is not (most likely not, being a blog) meant to generate any profits; MySQL is ideal if you use a PHP server and PHP dev; MongoDb is ideal because it enables wrapping the model with the request object thereby, eliminating extensive coding to read the DB and write to the view.
Eg.
(in the router page of the landing Blog page)
var router = express.Router();
var posts = mongoose.model('BlogPosts');
router.get('/get, function(req, res) {
res.json(req.posts); // As simple as this
});
(in the view)
<div ng-repeat="post in infiniteitems">...</div>
(in the controller)
$.ajax({
url: '<url to your route>',
type: 'GET',
dataType: 'json',
success: function(data) {
$scope.infiniteitems=data; // Binds to the controller item in the view
$scope.$apply();
},
error: function() { },
beforeSend: setHeader
});
So, you have the navigation, the view, the data all taken care of with just a few lines of code. More importantly, no innodb or database engine
The code is meant only for explanatory purpose.
Because MongoDB returns a document as JSON and binding a view to a JSON is pretty simple than binding an object or XML values!
Obviously, this means a MVC framework and so AngularJs is the right choice.
UX - Angular Material, when used in conjunction with AngularJS, provides some scintillating designs, colors and animations and the simplicity adds to performance, enhances the UX and renders a freshness to the View (for the user) that is not easily creatable with other technologies.
So, go for Angular.
And also, because MongoDB works pretty well with NodeJS, the whole thing works together which is why they call it the MEAN stack - MongoDB, Express, AngularJS, NodeJS!
When I first looked at Play and went through all the samples, I was pretty excited by the zentasks sample and the fluid, clean, effortless Javascript routing that left the work of rendering things to Play. But we decided instead to go with Angular.
Upon going down that road, I thought that Angular would control all aspects of rendering.
However, we have a page that has to get a socket. We were having the socket made on the server, so for now, we still have a Play (Scala) template doing that. We have pared it down to pretty much nothing: create the socket and then inject it into the Angular context.
But we are also trying to do Protractor tests and that is made uglier by having to figure out how to accommodate the Scala template.
Question: should we just ditch the scala template and have the Angular controller call the server and get the socket? That was my favored approach to begin with.
I'm currently working on two Play apps with Angular and in both we decided to have one single main.scala.html file that load all the necessary controllers,services,directives, etc from angular using of require.js.
The goal with Angular is to create a single page app and therefore you should avoid to mix it with server side templates.
You must see your main.scala.html template as the entry point of your single page application. There you generate and load all the pieces you need and give the hand to angular to manage the rest.
I agree with Renato. It's probably better to have a single controller and template that sets up the single page app with angular. Then use AJAX to send requests from the browser to other controllers (see http://www.playframework.com/documentation/2.2.x/JavaJsonRequests).
If want to to avoid Scala templates completely, you can put your web pages and javascript in the public directory and only use AJAX.
I have Backbone working with pushState. It's very nice, but now I understand that I should support loading the app from any route that backbone uses. For example, if somebody enters a backboen route manually to their browser, the server should respond to that and render the page and then let backbone take over.
What I am wondering, is what is the most efficient way to handle it? Backbone recommends also bootstrapping data on initial page load to reduce ajax requests. Should I only try to bootstrap data that is necessary for that particular view or should I try to bootstrap basic collections (for example: users, settings, documents, etc)?
For the first part of your question, you could just specify a callback route (which matches everything and gives the homepage) so the user never gets a 404 (don't use that when developing the app though, it could give you some hard times debugging it if you have a real 404 when making a call to the server).
For the second one, I'd say it depends on the amounts of data you need. I'm personally developing a modular application, and unfortunately can't really bootstrap anything. I'd say it's just some advice.
I am new to backbone.js so this may be an easy question.
The router seems to use semantically sensible urls, but they aren't very user friendly.
In the examples I've seen they use:
local.com/post/id/1
But in wordpress I would opt to rewrite this as:
local.com/2012-11-03-backbone-js-router-question.html
This would be run through a big rewrite table and translated to the right controller/action. I don't want to expose the router to the user that prominently.
My final application for this question is with e-commerce in mind:
cms page local.com/about-us.html
product page local.com/blue-tooth-headset.html
category page local.com/phones.html
product via category page local.com/phones/blue-tooth-headset.html
So my question is, how would one get pretty urls while using backbone.js?
My thoughts on options are:
You don't get seo friendly urls
You have some enormous map, and it has to sit on the client :(
Everytime you are about to change the url you have a quick ajax lookup up for the pretty-url, and you need to wait for the pretty-url to come back before you pushState.
sections are prefixed with a letter ie local.com/p/product-name.html and p actually serves to distinguis which router, another could be c for category
Backbone routes can be mostly anything. About e-commerce, you'd just need to use wordy urls:
<category>/<product-name>
television/samsung-i178
But, that's not really what you should matter about regarding SEO. Google mostly added way less value in URLs keyword after last year "panda" update.
What you should really consider is getting fallback and content served on the page even if javascript isn't enabled. But the trouble there is that you probably don't want to code your site twice: frontend templating/paging engine + plus same thing on the backend.
There's upcoming technologies who'll help leverage this problem using node.js (Mojito, Meteor, etc), but right now they're not the most stable projects out there. And, I think it may be a little early to use these in production; if you don't have a really competent team to get you server going and debug those projects if needed.
Anyway, what I mean is that if SEO weight a lot in your project, just don't use backbone.
Edit :
About what you add to your question, I think that's pretty easy to conceptualize.
In Backbone, you use a variable router, like so:
routes: {
"product/:url" : "product"
}
product: function( prettyUrl ) {
console.log( prettyUrl );
// Then you fetch your server
server.fetch( prettyUrl );
}
Then on your server database, you just fetch your database by the product pretty url, like SELECT * FROM product WHERE prettyurl=$prettyURL (Or something similar to this, been a long time since I used mySQL).
This way, you don't have to keep a map on the client side, you only use the pretty url the server gave you to fetch full product.
So when on your collection you call fetch, the server should return to you:
{
id: 1,
name: "Product XYZ",
prettyUrl: "product-xyz"
},
{
id: 2,
name: "Mac Book Pro",
prettyUrl: "mac-book-pro"
}
This way, every pretty url is managed with his model, not in the router. And that's definitely the way to go to manage such URLs. And that's mostly how does it any Wordpress or Drupal out there. Only they do it on the backend side.
There is an HTML5-only solution which allows you to keep urls pretty within Backbone.
Initialize Backbone.history with pushState set.
http://documentcloud.github.com/backbone/#History-start
Beware:
If your application is not being served from the root url / of your domain, be sure to tell
History where the root really is, as an option:
Backbone.history.start({pushState: true, root: "/public/search/"})
Then call history.navigate like this:
navigateToTodo () {
Backbone.history.navigate('/todos/' + this.model.toJSON().id, {trigger: true});
return this;
},
Or just use conventional href linking throughout your app.
Example and explanation here:
From Hashbangs to HTML5 PushState
Fallback for IE:
Fallback for IE
EDIT: So after a while and getting my head around similar problems now I think I understand your question. What you want is not related to Backbone it is to converting a text like this:
"Marissa Mayer can't stop acquiring things" to this "marissa-mayer-can-t-stop-acquiring..."
**Your question is missleading as you supposed Backbone was doing this for you, which it does not.
So the answer is:
What you need is Urlify (there are others, but not quite as good in my experience).
https://github.com/aliem/urlify
-I'll leave the old answer as it seems to have helped people who searched for this-
To start off this might not be the right approach and I'm open to other suggestions but please hear me out......
I'm quite new to Backbone JS and was wondering if its possible to use this to build a portfolio/cv site where content would be loaded via AJAX to a container.
To start off simply, i was thinking along the lines of converting my online CV to be more dynamic where sections such as Profile ,Key Technical Skills, Experience and Career History
can someone please offer a few pointers as what the best approach would be?
Would every view need to have a model?
Given the small amount of content, relatively static nature of the data in a CV, and simplicity of what you would need to accomplish, I'm not sure I would recommend using Backbone for this project. It seems that some simple jQuery click event handlers and transition animations would be sufficient to do what you're looking for.
If you're intent on using Backbone is purely for education and learning how to use it, then I would suggest looking for a project that has a more dynamic nature to it's data, with more content to be manipulated.
FWIW, though, you could use Backbone views to help organize your jQuery code for your CV. However, you'll end up writing more code to do this than if you just used jQuery.
For example, if you wanted to show / hide a section when someone clicks on it... here it is in jQuery:
$(function(){
$(".cv-section").click(function(e){
$(e.currentTarget).toggle("fast");
})
});
and here is the same code in Backbone (which uses jQuery for it's DOM manipulation):
CVView = Backbone.View.extend({
events: {
"click .cv-section": "showHide"
},
showHide: function(e){
$(e.currentTarget).toggle("fast");
}
});
$(function(){
var el = $("#cv");
new CVView({
el: el
});
});
These two examples are functionally the same, and they both use jQuery to manipulate the DOM.
Using Backbone might be overkill for your needs if you're just showing different content based upon what the user clicks on.
Backbone benefits data driven websites where users are creating, editing and deleting data.
The core jQuery library should provide the functionality you need. Checkout jQuery's load method.