Backbone differentiate client side rendering from server side rendering - javascript

I want to allow users to request webpages of my website both directly from the server or using links, which will be handled by Backbone's router.
When a user requests a webpage directly from the server, a full page is served (with html, head, body, stylesheets and scripts).
On the other hand when a user requests a webpage by clicking on a link, only the relevant part of the page is requested and then inserted in the correct place, and other elements of the webpage remain untouched.
By inserting in the correct place I mean creating a View once a particular route is reached. The view is then initialized and calls its render method to fetch the relevant part of the webpage and inserts it into DOM using $el.html(content).
But I do not want to call the view's render method when a webpage was fetched directly from the server, because all needed content has already been rendered, and re-rendering it only causes some ui-flickering effects.
Is there some common way to let Views know that they shouldn't render themselves, because the fully rendered webpage has been fetched from the server?
I could pass a flag like clientSideNavigation = true to the router, everytime a link is clicked, which then will be passed to views by the router so that they know whether to render the content or not.
But it does not work when user uses aa back/foward buttons.
I could also check in a view if within its $el there is some particular element that should be present on this webpage - for instance if I had a view called CatsView I could check if #cats-box is within its $el element. But it involves some more DOM manipulations, which I would prefer to avoid.

Have a root view and have place holder for child views. First time render the complete page from the server.
For rendering parts of the view on link clicks, you can define corresponding events hash on the root view.
Let the event handler callbacks call a controller(custom js object) which does the job of loading the data ,constructing the view and passing the data to it.
Finally also update the url with Router navigate(http://backbonejs.org/#Router-navigate) method with {trigger:false} to the corresponding url, so then when refresh is hit, the user comes back to the same view.
In the router callback for the specified url call the same method on controller object by passing a flag so that the functionality is in sync and also using the flag you can prevent calling router navigate method since its not required.

Related

Integrating HotJar in SPA with same URL

I'm trying to integrate Hotjar with an admin panel.
The way it currently works is some sort of SPA without page loads and neither URL changes.
It all happens under /index.php and then when we need to change a page, just send an AJAX request to load it's content.
From checking the documentation, Hotjar seems compatible with SPA's but only when there's a change in the URL (either query string or hash).
Is there a way to trigger in JS a page change to a page name (i.e. Main Page) ?
I've tried
hj('vpv', 'Main Page')
But the output seems weird
url: "http://mydomain.comTest Page"
Thanks.
You can track your changes manually by adding additional JavaScript after your AJAX calls.
Documentation:
To Manually Issue a State Change
hj('stateChange', 'some/relative/path');
Example:
Imaging that you have a SPA with base URL http://example.com/ and you want to track the main page and a page that gets dynamically loaded with AJAX once you click some button.
In order to do that, you would need to:
1) In your Hotjar account, create two heatmaps. For the main page, you can use the base URL http://example.com/. For the page that is going to be loaded dynamically, you can put a virtual URL, e.g. http://example.com/my-dynamic-page, which will be used only for recording and will not need to exist in your SPA.
2) In the JavaScript of your application, add the state change code after the AJAX call that will dynamically load the page.
You need to use the virtual URL that you defined in the previous step to let Hotjar know that this is a new page and you want to track it separately:
hj('stateChange', 'http://example.com/my-dynamic-page');

How to refresh a page once it's opened from a previous link?

I have a table with live data in it (meaning it is stored on the server and people who has access can view the data in their machine as well). I have a Create data page and View data page that contains the table. Once I have finished creating a new data and click a link going to the View page. The data should be there already.
I have tried the location.load() internal script in the View.html page that is triggered by the attribute onLoad="" but it's not working. However, when I create a button that has a function to refresh, it does work but I want it to be an auto refresh.
To make it easy and simple, use location.reload(). You can also use location.reload(true) if you want to grab something from the server.
You can simply use an jQuery Ajax call to make call to your backend API and fetch data, which you can add to your html table. This process you can handle in page/document ready or load events. I don't think you need to reload the page just to achieve this.
If you are working with AngularJs SPA (mentioning this as you added the tag), these two HTMLs/Pages can be rendered into the same layout based on the route and follow the above mentioned approach (using $http.get of Angular) to get view data and bind it to the respective view. As it is SPA, no concept of page reload.

mithril avoiding to reload image

I am using mithril 0.2.2-rc.1. I saw in the routing documentation:
Routing is a system that allows creating Single-Page-Applications (SPA), i.e. applications that can go from one page to another without causing a full browser refresh.
Indeed when I am routing to the same page with different parameter only the part that I want to change is refresh expect this :
m("img[src='assets/images/logo.png'][alt=''][width='100']")
I can see in the network communication that the image is reloaded (another GET request).
Is there a way to avoid that?
route.js
m.route.mode = "pathname";
m.route(document.getElementById('app'), '/', {
'/': main,
'/modelling/:level': main
})
It's difficult to see how the two pieces of code fit together, but two things suggest themselves:
Every change of route (even if that change results in the same route entry, eg /modelling/x to /modelling/y) will result in the entire DOM being regenerated. You can prevent this behaviour by calling m.redraw.strategy( 'diff' ) in each route component's controller.
Repeatedly requesting the same resource does not lead to extra calls to the server: a multi page site with every page requesting the same JS and CSS will only load those resources once, and will hit browser cache on subsequent requests. Thus repeatedly asking for the same image resource will not generate any new calls to the server.
If you check the documentation of the m method you will see that the config attribute lets you retain elements across redraws. So this should work for you:
m('img', {config: function persist(el, isInit, context)}) {
context.retain = true;
}

backbone multiple views with the same model

I am doing an only front end project with backbone.
And at one point I want to do the following :
A basic form with some input
the user submit the form
Show some cool graph with d3 or google graph based on the inputs of the user.
The problem is that I don't have any backend so I never save the inputs of the user, How can I change the view and still have the data of the form?
I was thinking about storing it temporary into localstorage but it's not really a good solution for perfs...
Thanks
Router creates a model instance
Router passes that model instance to the form view constructor options
Router binds event listener view.on('formComplete', this.storeModel)
Router renders & attaches form view
User fills out form view
Form view sets the data from the form into the model
Form view triggers route or event (like this.emit('formComplete', this.model);)
Router's storeModel handler function takes the same model instance, stores it as this.model temporarily on the router, and then navigates to the graph view.
In the graph view route handler method, router passes this.model it to the graph view contsructor options, render, attach
This is sort of using your router as an in-memory data cache, but since you have no back end, you need to store data somewhere.
Im also doing an one view web app with backbone.
I think the point of your problem is you really has only one page but load different views into this page. Not change to another page.
I suppose your app url is http://xxx.xxx.xxx/#first_view. and use backbone Router to change views
If you just want keep the data until user refresh browser. Just save them into a Global js variable. Once you use something like
window.location = Global.getBaseURL() + "#second_view" to change your view. And you actually load the "second_view" by ajax and put html into current page. You never lose your js variable.
If you want keep data even user refresh or go to another page. You have to use sessionStorage. Save data into JSON format and convert them back to js variable once you finish loading the new page.

Calling router from backbonejs and nodejs

I have an web app. Basically its a single page application. The initial page is a flat html file called index.html, with a single script declaration pointing to require.js. From there I use backbonejs to handle the client side logic. The index.html is being served by nodejs.
My issue is that, any action within the page, for example, i click on a link, the backbone router is called. Which is the behavior I want being a single page application.
For example: www.testserver.com then i click on a link which shows a modal screen for registration www.testserver.com/register, via backbone router with push state on
The issue arrises when, instead of accessing a certain link within the app, i open the url straight in browser. For example I paste, www.testserver.com/register, in the browser. The request is then sent to my node router. I am assuming this is the correct behavior, since the page doesnt exist yet, meaning the backbone router doesnt exist as well.
I was wondering, on what the correct work around for this is. What am i supposed to do, when i access this link? How do i pass the correct behavior back to my backbone application.
Thank you very much.
The server should return always the index.html page. When you start the router in your Backbone than, the router handle the navigation and call the function you defined for the actual route.
Assuming you don't need to do any SEO type stuff such that each unique URL loads its own metadata, just always serve the same index.html as stated. However if you want to have different static head content based on the URL, you should do that within node based on the path (e.g. keep an array of metadata for each route that you slip into a slightly-more-dynamic initial view template, based on your existing flat index.html)

Categories