I'm building an AJAX 'web application' where, once the UI is loaded, calls to the server are for 'data exchange' only. As a result a lot of UI manipulation will be done using Javascript. Lets say the Javascript retrieves some data consisting of multiple fields from the server using AJAX. To put it on the screen I can think of multiple approaches -
Call methods like createElement() and appendChild() to build an interface to display the retrieved data
Populate the .innerHTML for the container element then for every data field lookup a container in the newly added HTML and populate it. The data that goes into .innerHTML could be stored in a JS variable or contained in a hidden node, or fetched using a seperate AJAX call.
Have the interface stored in a hidden node. Clone it (using cloneNode()) and put it in the actual container (using appendChild()) and then populate it with fields like in method 2.
and there are probably more ways.
Could you share pros, cons and possible gotachas in these approaches from cross-browser support, performance and coding complexity point of views?
Somewhat related question: Is client-side UI rendering via Javascript a good idea?
Thanks.
ok, let's start off:
Use toolkits
First you would want to invest time learning a JS toolkit. While others suggest native JS is good (which it really is), but you would not want to waste time on building apps that don't work cross-browser or spend too much time testing it. People in the community have invested their time in doing that for you. Show some love to the open community and use their product. I personally use jQuery, but there are others like Dojo and YUI.
But still use native JS whenever possible. It's still faster.
Structure your code
After a toolkit, you need some structure. BackboneJS will take care of that. It's to structure your code so that your code is reusable and well.. won't end up as spaghetti on your screen. Other tools like RequireJS are also useful for those scripts that need other scripts to run.
Templates: From strings to elements
Then, with that, you now have a toolkit but you still need to build the interface. It's better if you use a templating engine like Mustache or Handlebars. These render templates for your UI from strings (yes, plain strings of HTML). Just send over your template data from the server, store it in your app (in a variable or browser localstorage), and reuse it as necessary. No need for cloning hidden nodes!
Don't touch that DOM
As for approaching the DOM, you should touch the DOM only when necessary. DOM is slow, manipulating it is he** slow! that means you should avoid unnecessary animations, avoid excessive element append and remove, as well as changing styles. Check this article about avoiding too much reflow and repaints. Face it, the user won't event notice the round corners of your boxes, or the gradient background and don't even care if you did a slide animation or a fade-out. What they want is to get the job done and not adore the fireworks display.
Also, remove anything that isn't on screen. You might end up having 20% content on screen, and 80% off screen - a waste of memory.
Cache: fetch once, store, use infinitely for later
Now, your app is getting heavy and you want to shave off some HTTP requests. You can do this by caching. I usually use caching mostly on the templates so that every new UI, you don't need to load again from the server. You can do this by storing stuff in an object. you can go a little further and use the browser's localStorage when available.
Caching isn't all for the network. Let's say you have some complex calculations you want to use later, or some text from an unfinished form, use the cache for that too.
Avoid HTTP requests (or at least lighten them up)
While lightening up your app by using AJAX, you will inevitably be tempted to use AJAX just about anywhere - don't abuse it. Often times i see people who aggressively poll the server (every half-second or less). This not only strains the server (too many requests), but also the browser (wasting processing cycles) and the network (bandwidth). There are several practices done these days to avoid added HTTP requests:
Image Spriting - The art of placing a lot of images into one image and using background-position to change the image. Surely beats 100 individual HTTP requests
Use JSON for textual data - AJAX was meant to use XML.. then came along JSON that was a fat-free, platform-independent format of strucured data.
Do not return HTML-formatted data - With exemption of templates, which are HTML strings, you should never return HTML-formatted data over the wire. Have JS do JSON+templates on the client-side instead.
I'm building a similar app (Lightweight CMS)
In my view the approach you take will be dependent on the complexity of data that you are sending from the server > manipulating on the client side > and returning back to the server and db.
The cms that I'm working on is very basic and does not require heavy-duty manupulation on the client side. TinyMCE is as far as it will go.
Initially I was building the client admin area by echoing <input> from php and then collecting the data by parsing the DOM, converting to JSON and AJAX it back to the server (I found this code very helpful)
That of course required the user to hit "save" after editing or adding new data.
I later on decided that I needed something even more responsive and simpler than that so I'm now re-implementing everything for Jeditable which AJAXes the data as soon as the client hits "OK" on that particular field. No "main save" required.
To conclude it's really an area that is pretty uncharted. I mean, it appears to me that people in the industry do not like to blur that line between back-end and front-end and find "one solution" that will do the entire DB>SERVER>CLIENT>SERVER>DB operation.
I'd love to see how you solved your problem.
Just my 2 cents.
Related
I would like to refresh a Bootstrap v4 table (https://getbootstrap.com/docs/4.0/content/tables) based on the values fetched from the server side, for example a REST API resource.
I am currently struggling with the different approaches below:
Websockets
Webworker
Recursive setTimeout + ajax polling
Any other and better solution?
My main requirement would be something that is refreshed every 500 ms or less (e.g. stock prices).
Also I am wondering how to handle the most efficiently possible the DOM rendering of the table.
Web Workers can't directly interact with the DOM and your task is not that intensive.
I'd say WebSockets + DOM manipulation via (data) attributes and separate node insertion instead of a huge chunk of nodes inserted at once. It may be a bit slower, but there's not much of a difference and you might not even notice it. See Fastest DOM insertion
I'd update things separately because:
1) It's tidier and maintainable,
2) You don't need to worry about event delegation or reinitialization of particular stuff
3) The flow feels more natural instead of just getting a huge chunk of mark-up and "pasting" it in the DOM.
If you won't be adding new nodes and you will just listen for data changes on existing nodes, then I'd clearly suggest going for attribute-based changes.
In Backbone.js, model loading and saving is done via ajax calls. However, are there any best practices to loading the initial collection on page load without having to pull this down via ajax? I'm trying to do as much server side rendering as possible up front.
In the past, I've seeded the html with a javascript variable containing a json string of the initial data state so it can be rendered server side, but I'm not sure if this is a good practice.
Don't know if it's necessarily the best practice, but this method of seeding the html with a json object (not a json string as you described it, right?) is certainly my preferred way of doing initial loading. Not only for the (obvious) reason that it removes the delay of waiting for the initial AJAX call to return, but also because the one less open connection frees the browser to load something else instead (like an img src or whatnot), getting you to document.onLoad slightly sooner.
It's recommended that, when using this method, you put the said variable in a script tag at the bottom of the body (i.e. not in the head section), in order to give the static html elements on the page a chance to load and render first. The json data is ready when document.onLoad fires.
From Backbone docs, initialising models in script tag is not a bad practice. In my current project I decided to set only plain objects inside window.projectData, to be able to init Backbone models in external javascripts.
<script>
;(window.projectData || (window.projectData = {})).modelName = {/* value */};
</script>
The approach you select will probably depend on how much data you're planning to load and how that data will be used within the page.
If most of the required data will not ultimately end up rendered on the page, bootstrapping the initial state into a javascript variable might not be a bad route.
If the data is directly related to the presentation of the page, however, you might prefer to parse a pre-rendered DOM for the initial state of the backbone application. The obligatory word of caution is that this kind of parsing will be somewhat slower, especially for large data sets.
If you do end up opting to parse pre-rendered content, I put together a small jQuery DOM parser a while back that might prove useful for mapping the presented content into a Backbone-ready form.
I am writing my first Rails app using the twitter gem. I'm simply retrieving search results and trying to cycle through them individually every 5 seconds or so.
My thought was to create a variable and have this variable represent the array index and simply update this variable dynamically with Javascript (every 5 seconds or so). What's the best way to achieve this on the client-side? AJAX? Javascript?
Does this make sense? I will be glad to provide more context if helpful. Thanks.
Sounds you're trying to build a "recent tweets" marquee of some sort. Without knowing your requirements, you could try simply loading the ten most recent tweets in Rails, putting them in ten hidden divs, and then using jQuery just to cycle through the different tweets on the page.
If it is a requirement to "update" the most recent tweets without the user refreshing the page, then yes, you'd probably need an AJAX call.
It's hard to tell what you think you're asking: by the time your JavaScript is executing the server is no longer involved.
If you want to update some sort of count on the server side and persist it in a meaningful way, you can do so via Ajax.
What are you actually trying to do, though?
Ruby runs on the server while JavaScript (usually) runs on the client.
The Ruby generates an HTML document (perhaps with embedded JS) and the server delivers it to the client.
At that stage the Ruby has finished executing. The only way to do anything further with Ruby would be to make a new HTTP request to the server. This could be done by following a link, submitting a form, setting location.href, using XMLHttpRequest or numerous other techniques.
This would cause the Ruby program to be executed again (or a different one to be executed) which would do whatever it did with the input data.
You cannot simply "set a variable" on the server from the client.
In my particular case, I used ruby's .to_json method to convert the data and then manipulated it with javascript. This gave me the flexibility to loop through the data pretty seamlessly. Atleast it seemed to work for my particular situation. Thanks for the help guys!
After reading this Micro templates are dead article. I've become curious:
Whether Using the DOM on the server results in cleaner more maintainable code then templating.
Whether it's more efficient to use jsdom instead of a templating engine.
How to factor jsdom into the View of a standard MVC setup.
And generally in what situations would it be better to use a server-side DOM abstraction, like jsdom rather then a templating engine, like EJS or jade.
The question is specific to node.js and other SSJS
Well, I actually needed JSDom for a small project I built over the weekend in node.js. So, on my server, I had to accept a URL to fetch, grab all of the HTML from the given URL, parse it, and display images to the user so that the user could select a thumbnail from that URL. (Kind of like when you drop a link into the Facebook input box) So, I used a module called Request which allows me to fetch HTML on the server-side. However, when that HTML reached my program, I had no way to traverse it like you do with client-side javascript. Because there was no actual DOM, I couldn't say document.getElementById('someId'). Therefore, JSDom came in handy by giving me a "makeshift" DOM that allowed me to traverse the returned HTML. Now, even though I was still on the server side, JSDOM created a window object very similar to the window object in the browser, and created a DOM out of the returned HTML. Now, even on the server, I was able to get all images by calling window.$('img'). I could target and parse the elements like normal. So, this is just one problem where JSDom turned out to be the solution, but it worked amazingly well. Hope this helps some!
Its a nice abstraction that matches a client side engineers take on how the dom is built and modified. In that respect it is 'cleaner' because there is one mental model. Its also nice because we don't have to mix a kluge of disparate syntaxes from a templating language on top of otherwise clean declarative markup as is the case with even the 'stupidest' templating system, such as mustache.
I would NOT say its more efficient to use jsdom for templating. Go take a gander at google wrt to 'memory leaks with jsdom' for instance. jsdom is rad, and is super useful for tasks like weekend projects for crawling sites, doing non-server related tasks, but I think its slow as shit from a high performance web server perspective.
There are a billion ways to factor this. No method has emerged as a 'standard' way. One way that I've seen is to send down an empty 'template', i.e. a block of html that represents a model in some way, and then use that to bootstrap building your end view from a model. From that article, for example:
<li class="contact" id="contact-template">
<span class="name"></span>
<p class="title"></p>
</li>
This is the 'view' in the classic respect. In the typical web application, it might look something more like:
<li class="contact">
<span class="name"><?= $name ?></span>
<p class="title"><?= $title ?></p>
</li>
To use mvc, one sets up a controller that is vaguely aware of the semantics of the above view and the model it represents. This view is parsed into the/a DOM and accessed via your favorite selector engine. Each time the model this represents changes, you might use change events or callbacks to update the view. For instance:
Lets imagine that 'model' fires a 'change' event every time a property changes.
controller = new Controller({
view: $('#contact-template').clone(), // Assume jquery or whatever
model: aContact
});
// Assume some initialization that sets the view up for the first time
// and appends it to the appropriate place. A la:
// this.view.find('.name').text(model.name);
// this.view.find('.title').text(model.title);
// this.view.appendTo('#contacts')
controller.on('model.name.change', function(name){
this.view.find('.name').text(name);
});
These are what systems like Weld and Backbone.js do for you. They all have varying degrees of assumptions about where this work is taking place (server-side, client-side), what framework you're using (jquery, mootools, etc), and how your changes are being distributed (REST, socket.io, etc).
Edit
Some really useful things you can do with jsdom revolve around integration testing and spidering:
https://github.com/mikeal/spider - general purpose web spider that makes use of node's event based processing and gives you jsdom/jquery to help you easily access the DOM in a programatic way
https://github.com/assaf/zombie - headless browser testing using jsdom/jquery for integration tests
https://github.com/LearnBoost/tobi - similar headless browser testing
Personally, I'd like to see a project that took tobi's approach, but mapped it on top of something like https://github.com/LearnBoost/soda such that we can do cloud based selenium testing without selenese (since imo, it sucks).
A few come to mind:
Sharing views/controllers between server and browser
Data mining / crawling / processing
Transformation for fragments of HTML used in AJAX/realtime stuff
Absolute separation of logic and content by avoiding template tags
And to answer your questions:
maybe. A lot of things affect code quality, but it's a step in the right direction
nope, templating engines will always be faster, since they can pre-compile templates
this probably warrants a new question?
point 2 of your question can be answered by this templating testcase:
go http://jsperf.com/dom-vs-innerhtml-based-templating/300
click the button "Run tests".
be patient, it compares weld vs. a lot of other template engines and gives you the current benchmarks ...
Hey all, I'm looking at building an ajax-heavy site, and I'm trying to spend some time upfront thinking through the architecture.
I'm using Code Igniter and jquery. My initial thought process was to figure out how to replicate MVC on the javascript side, but it seems the M and the C don't really have much of a place.
A lot of the JS would be ajax calls BUT I can see it growing beyond that, with plenty of DOM manipulation, as well as exploring the HTML5 clientside database. How should I think about architecting these files? Does it make sense to pursue MVC? Should I go the jquery plugin route somehow? I'm lost as to how to proceed and I'd love some tips. Thanks all!
I've made an MVC style Javascript program. Complete with M and C. Maybe I made a wrong move, but I ended up authoring my own event dispatcher library. I made sure that the different tiers only communicate using a message protocol that can be translated into pure JSON objects (even though I don't actually do that translation step).
So jquery lives primarily in the V part of the MVC architecture. In the M, and C side, I have primarily code which could run in the stand alone CLI version of spidermonkey, or in the serverside rhino implementation of javascript, if necessary. In this way, if requirements change later, I can have my M and C layers run on the serverside, communicating via those json messages to the V side in the browser. It would only require some modifications to my message dispatcher to change this though. In the future, if browsers get some peer to peer style technologies, I could get the different teirs running in different browsers for instance.
However, at the moment, all three tiers run in a single browser. The event dispatcher I authored allows multicast messages, so implementing an undo feature now will be as simple as creating a new object that simply listens to the messages that need to be undone. Autosaving state to the server is a similar maneuver. I'm able to do full detailed debugging and profiling inside the event dispatcher. I'm able to define exactly how the code runs, and how quickly, when, and where, all from that central bit of code.
Of course the main drawback I've encountered is I haven't done a very good job of managing the complexity of the thing. For that, if I had it all to do over, I would study very very carefully the "Functional Reactive" paradigm. There is one existing implementation of that paradigm in javascript called flapjax. I would ensure that the view layer followed that model of execution, if not used specifically the flapjax library. (i'm not sure flapjax itself is such a great execution of the idea, but the idea itself is important).
The other big implementation of functional reactive, is quartz composer, which comes free with apple's developer tools, (which are free with the purchase of any mac). If that is available to you, have a close look at that, and how it works. (it even has a javascript patch so you can prototype your application with a prebuilt view layer)
The main takaway from the functional reactive paradigm, is to make sure that the view doesn't appear to maintain any kind of state except the one you've just given it to display. To put it in more concrete terms, I started out with "Add an object to the screen" "remove an object from the screen" type messages, and I'm now tending more towards "display this list of objects, and I'll let you figure out the most efficient way to get from the current display, to what I now want you to display". This has eliminated a whole host of bugs having to do with sloppily managed state.
This also gets around another problem I've been having with bugs caused by messages arriving in the wrong order. That's a big one to solve, but you can sidestep it by just sending in one big package the final desired state, rather than a sequence of steps to get there.
Anyways, that's my little rant. Let me know if you have any additional questions about my wartime experience.
At the risk of being flamed I would suggest another framework besides JQuery or else you'll risk hitting its performance ceiling. Its ala-mode plugins will also present a bit of a problem in trying to separate you M, V and C.
Dojo is well known for its Data Stores for binding to server-side data with different transport protocols, and its object oriented, lighting fast widget system that can be easily extended and customized. It has a style that helps guide you into clean, well-divisioned code – though it's not strictly MVC. That would require a little extra planning.
Dojo has a steeper learning curve than JQuery though.
More to your question, The AJAX calls and object (or Data Store) that holds and queries this data would be your Model. The widgets and CSS would be your View. And the Controller would basically be your application code that wires it all together.
In order to keep them separate, I'd recommend a loosely-coupled event-driven system. Try to directly access objects as little as possible, keeping them "black boxed" and get data via custom events or pub/sub topics.
JavaScriptMVC (javascriptmvc.com) is an excellent choice for organizing and developing a large scale JS application.
The architecture design is very practical. There are 4 things you will ever do with JavaScript:
Respond to an event
Request Data / Manipulate Services (Ajax)
Add domain specific information to the ajax response.
Update the DOM
JMVC splits these into the Model, View, Controller pattern.
First, and probably the most important advantage, is the Controller. Controllers use event delegation, so instead of attaching events, you simply create rules for your page. They also use the name of the Controller to limit the scope of what the controller works on. This makes your code deterministic, meaning if you see an event happen in a '#todos' element you know there has to be a todos controller.
$.Controller.extend('TodosController',{
'click' : function(el, ev){ ... },
'.delete mouseover': function(el, ev){ ...}
'.drag draginit' : function(el, ev, drag){ ...}
})
Next comes the model. JMVC provides a powerful Class and basic model that lets you quickly organize Ajax functionality (#2) and wrap the data with domain specific functionality (#3). When complete, you can use models from your controller like:
Todo.findAll({after: new Date()}, myCallbackFunction);
Finally, once your todos come back, you have to display them (#4). This is where you use JMVC's view.
'.show click' : function(el, ev){
Todo.findAll({after: new Date()}, this.callback('list'));
},
list : function(todos){
$('#todos').html( this.view(todos));
}
In 'views/todos/list.ejs'
<% for(var i =0; i < this.length; i++){ %>
<label><%= this[i].description %></label>
<%}%>
JMVC provides a lot more than architecture. It helps you in ever part of the development cycle with:
Code generators
Integrated Browser, Selenium, and Rhino Testing
Documentation
Script compression
Error reporting
I think there is definitely a place for "M" and "C" in JavaScript.
Check out AngularJS.
It helps you with your app structure and strict separation between "view" and "logic".
Designed to work well together with other libs, especially jQuery.
Full testing environment (unit, e2e) + dependency injection included, so testing is piece of cake with AngularJS.
There are a few JavaScript MVC frameworks out there, this one has the obvious name:
http://javascriptmvc.com/