I would like to ask for more an opinion than a question:
What would the community recommend to do when you must do a webpage with lots of data, for example, a products listing, that should have some functionality like buy (adds to cart), sorting, etc. if you have to manipulate the data of the current product - price, title, image, link and other attributes? How you do it in your projects?
For example we have a page with dozens of products, each of them has attributes: price, title, description, image(URL), link(URL). How would you store the data to use it on some user interaction? Personally, I've done it by just inserting each of the attribute in tags, something like:
<div class="product" data-product_id="123">
<div class="pr_title">Title</div>
<div class="pr_body">Body</div>
<div class="pr_img"><img src="http://www.www.www/img.png"></div>
<div class="pr_link">Buy!</div>
</div>
This way I have my html structure for presentation and I worked with data in jQuery by something like:
var url = $('.product').find('.pr_link').find('a').attr('href');
But when the project got big and there were 10-15 more attributes added to each element, getting data from current product got pretty complicated and the code became mostly unreadable.
I thought of using same structure, but to keep data in some object like:
var products = {
1: {
title: "abc",
description: "lorem ipsum",
price: 25.19,
img: "http://www.www.www/img.png",
link: "http://www.stackoverflow.com"
}
}
and keep markup as simple as possible, only using elements and styles needed for design with css:
<div class="product" data-product_id="123">
<div class="title">Title</div>
<div>Body</div>
<img src="http://www.www.www/img.png">
Buy!
</div>
so onClick I would need to retrieve the id of the product and query it in our object "products":
var url = products[id].title;
While this is the most convenient way to work with it requires a new object.
Another idea was to keep all data in data- attributes of the parent div element like:
<div class="product" data-product_id="123" data-title="abc" data-body="Body">
but for much as I know jQuery doesn't work with data attributes well (natively).
So what are your suggestions? Maybe you have some even better ideas to share.
P.S. I tried to find some information on the subject, but most likely failed to find the way to formulate it well so I found nothing about it. If there are links or even similar questions on stack exchange sites, please feel free to post them. Thank you in advance!
You can use HTML5 data attribute to store products data, as you have several properties of products to associate with each product block, you can JSON encode the object and assign to the top element, and then can access that on user interaction on that element or any child element.
var product = {
title: "abc",
description: "lorem ipsum",
price: 25.19,
img: "http://www.www.www/img.png",
link: "http://www.stackoverflow.com"
};
$(selector).data('product',JSON.stringify(product));
then to retrieve the object you can do on any event's callback
$product = $.parseJSON($(elem).data('product'));
In fact both facebook and twitter used data attributes to store associated data with tweets and stories. For example here goes some html of a FB story
<li data-ft='{"qid":"5757245005920960301","mf_story_key":"7164261693049558180"}'
id="stream_story_4fe5d7d51bc415443080257">
You can see facebook is storing JSON encoded data into the data-ft attribute.
Similarly an example of a Twitter tweet html
<div data-tweet-id="216534496567230464" data-item-id="216534496567230464"
data-screen-name="onimitch" data-user-id="123682011" data-is-reply-to="">
So twitter is saving associated data for a tweet into different attributes like data-tweet-id, data-user-id.
So As they both handle's a lot amount of data, I think You can also use either of the method to save your data without any performance issue.
If you store data with individual keys then be aware of the automatic data conversion that .data() does as #nnnnnn has already mentioned in comment.
Demo With .data() : http://jsfiddle.net/joycse06/vcFYj/
Demo With .attr() : http://jsfiddle.net/joycse06/vcFYj/1/
No need to use ids or references within the DOM. Keep it clean.
Just use the data() function in jquery and bind it to the html elements. That way when you click on each element you will be able to get the object by calling this from within your click event.
//loop through your elements in the dom or build them dynamically.
$.each('div.products', function(){
$(this).data('product', <your data>);
};
//assign a handler to each element and grab the data object by using this. :)
$(container).delegate('.products', 'click' function(){
console.log($(this).data('product'))
});
I don't recommend you to keep your data in an object and fill HTML with it,
There are reasons for this:
Your data is open to all hackers to steal.
When your data is too big to fetch, your page can be initially loaded without data - and it's what any web developer do not want.
Again, when your data is too big, old computers -computers which has approx. 512M Ram- may come to a deadlock
Again and again, when your data is too big, traversing or sorting it may costs too much time.
I understand that your data is static for minimum about 5 min.. What I recommend is,
Place your data with Server-side languages(PHP,ASP(.NET),Python,etc.)
Fetch data with queries seperately when your script needs it.
Anything you do not need is cost for your user, user may have lots of page in his/her browser and it will be cause of deadlock too.
p.s. Any detail will help me to help you more.
You don't need to traverse the whole object tree.
How about putting IDs:
<div class="pr_link" id='id_link_123'>Buy!</div>
and retrive them as:
// ....
var id = 123;
// ....
var url = $("#id_title_" + id + " a").attr('href');
You should try AngularJS. It works great with jQuery and it is easy to learn. AngularJS contains two way data binding and extends HTML by new attributes and elements. Last but not least it is MVC framework by Google. See more at http://www.angularjs.com
Although there are many excellent clientside mvc frameworks, check out Backbone.js, which is a powerful-but-easy-to-use framework for managing the interface between your data source (usually an http server), and your DOM. In short, it keeps "your truth out of the DOM"
As a contrived example, if you are creating a simple address book app, you would probably have a clientside Contact Backbone model, which would roughly (or exactly) mirror the model you have on your server.
Backbone manages requesting and parsing the contact data (json, xml, etc) from the server (or localstorage, etc) into these Contact model objects, and you provide a js callback to update your DOM when changes occur. This also works in reverse: Backbone updates the server when the model objects change, either instantly, after some delay, or when you explicitly call the save function.
Backbone might not be the correct framework for you. But check them all out before you decide to roll your own solution. Even so, you could create your own clientside MVC layer, if you feel you:
Can do a better job than one of the many excellent existing javascript MVC frameworks,
Have such a unique problem that only a bespoke solution will work for you, or
Find clientside MVC, or javascript frameworks somehow scary or distasteful.
I have to agree to Enes, you shouldnt embed your data into the jquery code or, as you already mentioned, your code will quickly become so complex as to be unsupportable. An MVC framework will help with this.
There are a couple mentioned in the answers above such as http://angularjs.com and http://backbonejs.org although i cant vouch for either of them but you should have a look to see if they help solve your problems.
I am currently rewriting a scrumwall application i originally developed in jquery and raw php into the agile toolkit. With agiletoolkit (aka atk4 on stackoverflow), you define models which map to the database tables, html templates and views which have placeholders where you want the data to go and pages where you add models, forms and grids. It provides the links between javascript and php and has features including ajax refreshes of views.
You could use html5 features but only the latest browsers will support this so you may have problems if the users are not in a controlled environment (e.g. a single company where there is a standard web browser).
The combination of DOM and jQuery is one of the most powerful things the Web has. You are not taking all of them.
Make the DOM help you and work for you. Organize better the DOM. Take all of it. Your example can be optimized this way:
<div class="product" data-product_id="123">
<div class="pr_title">Title</div>
<div class="pr_body">Body</div>
<img class="prodcut-image" src="http://www.www.www/img.png">
<a class="product-link" href="http://www.stackoverflow.com/">Buy!</a>
</div>
To select with jQuery, simple write:
var url = $('.product .product-link').attr('href');
I believe that your problem is that your are forgetting the way CSS selectors work. It's not necessary to transverse into every level of the DOM.
You can take off some DIV's in your example. A link not necessary have to be in-line. A CSS rule can make them work like a DIV.
You can use (as you already are) the data- attributes in HTML through jQuery. When you create the DIV from the server data, you can do something like this:
$('.product').data(yourProduct); // yourProduct would be the JSON representation of the data
To retrieve:
var url = $('product').data('product-link'); // if the JSON object has a product-link property that is.
The caveat someone mentioned above that your data is exposed to the browser is of course still valid, so take care.
Related
If a website needs to have a page for every item, is it better to manually create pages with the same HTML code but different titles/images/descriptions or create only one but add content through javascrpit depending on a page a user followed, like that?
linkBtn.addEventListener('click', function() {
contentEl.innerHTML = `<div>
<div>
<h3>${title}</h3>
</div>
...etc
</div>`
})
or is there less horrible solution?
It is entirely up to you. Compare the stackoverflow website with the gmail one. Stackoverflow reloads the whole website as you navigate between pages. This means that your browser is requesting a new resource and the stackoverflow servers are returning that resource, possibly creating it dynamically with new question etc., but then just sending you raw HTML.
On the other hand, gmail loads once, but then fetches each different page entirely through javascript. This could involve asking the gmail server for new messages, but could also be just reworking the HTML to show a settings page, for instance.
There are obviously advantages and disadvantages to both ways of doing things.
As a side note, in javascript it is not a great idea to assign to innerHTML as this requires that the browser does a lot of work to re-parse the new markdown. Instead you should fully use the DOM model with functions such as document.createElement and Element.appendChild.
You need not create different pages for each product. Rather use HTML as template.
You can use something like handlebars to make templates.
I believe you should create one UI and fill it with data from some REST API. Look into creating dynamic websites, it is basic stuff.
Basically, if you have a purely JS app (that get info from socket.io, or from a server with ajax request), and you need to show this data after processing it, what technique are you using?
Currently i'm creating the elements manually with code like
var myDiv = new Element('div',{ /* options */);
And injecting it where I need making all the DOM structure. I find this hard to maintain and especially for those designers that can code html, but they can't code html from JS.
Is there any way that will improve this process? Is it better to get the html from ajax? or just make html code in a string?
I'm looking for the most optimal in terms of maintenance and resources.
What you're looking for is a "template".
You have an HTML template (some divs, etc) and you bind this with the datas you provide in JS. Then, with whatever template engine you're using, you can get the full HTML.
Here are some template engines out there:
https://github.com/flatiron/plates
http://embeddedjs.com/
And a code sample using plates:
var Plates = require('plates'); // specific to node.js, see for client-side use
var html = '<div id="test">Old Value</div>';
var data = { "test": "New Value" };
var output = Plates.bind(html, data);
console.log( output ); // '<div id="test">New Value</div>'
You can store your templates either in a single file ("templates.html") loaded through ajax, or by storing it in the HTML page (not really recommended for maintenance matters).
If you store them all in an external file, you can do something like this:
templates.html:
<!-- text/html isn't parsed by the browser so we can put anything in it -->
<script type="text/html" id="template1">
<!-- put your template in there
</script>
And you can get its content through getElementById( 'template1' ).
Easiest way for you if project is in late stage to add something like jQuery.template plugin and create templates in separate files. Then, use backend to combine those peaces in single page and on DOM Ready fire up your client side app.
If your project is in early stage use AngularJs or BackboneJS frameworks. Believe me it is worth every cent :)
I would recommend you take a look at Backbone.js.
Backbone.js gives structure to web applications by providing models
with key-value binding and custom events, collections with a rich API
of enumerable functions, views with declarative event handling, and
connects it all to your existing API over a RESTful JSON interface
I use backbone even if I am not over a RESTful interface. It's pretty easy to separate the structure from the behavior ... You can achieve the same using jQuery but it wont be as neat and clean. It's one of the MV* framework. You have:
Models containing the interactive data as well as a large part of the logic surrounding it: conversions, validations, computed properties, and access control.
Collections are ordered sets of models.
Views: The general idea is to organize your interface into logical views, backed by models, each of which can be updated independently when the model changes, without having to redraw the page
Routers provides methods for routing client-side pages, and connecting them to actions and events
It's getting attention recently. Apps that were created using Backbone include:
FourSquare
LinkedIn for Mobile
This is a great resource if you're starting to work with Backbone.
Distal Templates http://code.google.com/p/distal/ :
<table id="a">
<tr><th>OPINIONS</th></tr>
<tr data-qrepeat="m keywords"><td data-qtext="m.name"></td></tr>
</table>
Then call:
distal(document.getElementById("a"), {
keywords: [
{name:"Brilliant"}, {name:"Masterpiece"}, {name:"Witty"}
]
});
will become:
<table>
<tr><th>OPINIONS</th></tr>
<tr><td>Brilliant</td></tr>
<tr><td>Masterpiece</td></tr>
<tr><td>Witty</td></tr>
</table>
And injecting it where I need making all the DOM structure. I find this hard to maintain and especially for those designers that can code html, but they can't code html from JS.
Another option is modest. As you can see from the documentation, it obviates the need for HTML chunks in javascript. The designers can change the HTML structure without needing to look at the javascript, and javascript coders can use parameters defined by the designers to fill in the data (all in javascript).
This example is from the readme:
HTML:
<div>
<contact>
<name>Casey Jones</name>
<phone>123-456-7890</phone>
</contact>
</div>
Javascript:
var contact = {
name : "Casey Jones",
cell : "123-456-7890"
};
var out = modest.render('contact',contact);
Update: after another day of digging
into this issue, I have found that the
current jQuery template lib provides
no way to do this. this article
describes a good approach.
I would still like to hear of any
additional thoughts on doing this. The
article linked above requires that the
returned string of templates be
inserted into the DOM. Seems as though
leaving the DOM out of this would be
ideal, and less overhead on the
browser. Imagine a large page, with
multiple composite templates that may
not get used. Although, maybe because
the templates are wrapped in a script
tag, there is only a single DOM item per template? Come on, let's
hear some thoughts...
Using jQuery template libs, what's the best way to combine multiple, related, relatively small templates together? Do you need a single <script> tag for each individual template? What about in the case of dynamically pulling these templates via AJAX? Can I combine these templates somehow?
Consider the following:
<script id="movieTemplate" type="text/x-jquery-tmpl">
{{tmpl "#titleTemplate"}}
<tr class="detail"><td>Director: ${Director}</td></tr>
</script>
<script id="titleTemplate" type="text/x-jquery-tmpl">
<tr class="title"><td>${Name}</td></tr>
</script>
Now because these two templates are very closely related (and one depends on the other) it would make sense to consolidate these into a single AJAX call, and get them both at once. I have a few ideas, but I'd like to know if there is common/best way to do this? Currently I pull in a chunk of HTML, and then do a .find() to get the specific peice of HTML for a template... e.g.:
var templatePackage = fancyAjaxCalltoGetTemplates();
"templatePackage" might then look like this:
<div id="templatePkg">
<div id="movieTemplate">
{{tmpl "#titleTemplate"}}
<tr class="detail"><td>Director: ${Director}</td></tr>
</div>
<div id="titleTemplate">
<tr class="title"><td>${Name}</td></tr>
</div>
</div>
I could then do:
var titleTemplate = jQuery.template('titleTemplate', $(templatePackage).find('#titleTemplate') );
and
var movieTemplate = jQuery.template('movieTemplate', $(templatePackage).find('#movieTemplate') );
...let me know what you think... what would you do?
I like the referenced article in your update, except the assumption that you can't cache templates unless you insert them into the DOM. From the jQuery.tmpl documentation,
"To cache the template when using markup that is obtained from a string (rather than from inline markup in the page), use $.template( name, markup ) to create a named template for reuse. See jQuery.template()."
Using this, we can build a javascript template management system that allows us to load as many templates at a time as we need while keeping the DOM clean. On the client, keep a hash of template objects by name. You can use your favorite object based javascript pattern here, but I would think the structure could be like this:
templates[templateName] = {
templateMarkup: markupFromServer,
loadedAt: Date.now(),
compiledTemplateFunction: jQuery.template( templateName, markupFromServer )
}
Then use the templates to generate HTML like this:
templates['unique-name'].compiledTemplateFunction(inputData)
Then, build an unload mechanism to free up memory:
function unload(templateName) {
delete templates[templateName];
delete jquery.template[templateName];
}
Most importantly, you now have a method of storing multiple templates so you can make requests like: $.get('/TemplateManagement/Render', arrayOfTemplateNamesToLoad, loadManyTemplatesSuccess) to load multiple templates at a time. The only thing we need is a controller TemplateManagement that will take an array of template names as an input and return JSON that pairs a template name with its markup. There are a few ways to do this but it seems to me the most convenient is to define partial views for each template. In ASP.NET MVC 3, you can use this technique and RenderPartial to emit each template's markup into a JSON response. You can either name the partial views the same as the templates or map the names in some custom way.
OK, I read the article you reference in this post. As I see it, his way is probably one of the best ways to load up the template page(s). The only thing I don't like is the asynchronous problems that could crop up, esp. if you need to immediately do some templating before the async get returns... plus any binding issues that could happen before it returns something. In several projects I have done I use his "ancient" SSI (server side includes), but I just use something even easier like:
<% Response.WriteFile("this_page_template_file.html"); %>
You could put it anywhere where you'd place a tag. Like he says, just put in only the templates you need, or maybe include two templates: one is a "base" template with commonly-used items and the second one would have the page-specific ones with template references {{tmpl}}.
Is this even close to an answer? ;-)
[First off, great question. I love this topic]
I have no experience with the plugin "jquery-template-libs", but there is a particular lightweight javascript template plugins that are becoming almost a standard and plays very nicely with jQuery, which is probably better suited for the task than JTL, Mustache:
https://github.com/janl/mustache.js
It's got something that's called a "partial" which is essentially a way to include smaller templates within another one. Which sounds like it will help you out a lot.
On top of that there is a library called ICanHaz.js:
http://icanhazjs.com/
ICanHaz essentially extends Mustache to include built in functionality for templates and works incredibly well.
Mustache/ICanHaz allow you to add templates by variable, by a json call or by using tags. The choice is yours.
I know this is an old question but you might want to take a look at Closure-Templates. They provide the kind of functionality you're after with the added advantage of being compiled into JavaScript at compile-time instead of at run-time in each user's browser.
If you do decide to look into using them then I'd suggest using plovr for building them.
I have a big chunk of deeply-nested semi-structured JSON and would like to generate HTML from it. At the moment I'm using jQote2, but much of the code inside my templates deals with dynamically finding the next template to render and then calling it. What's a single <xsl:apply-templates> in XSLT takes several lines with JavaScript and jQuote. I dearly miss the pattern matching capabilities of XSLT. Is there any (templating) library in JavaScript that allows me to dynamically decide from the data which template to render?
Here is an example of what I want. Suppose I have a JSON structure like this:
{
items:[
{foo:1, bar:2},
{foo:7, baz:99},
{foo:8, quux:3}
],
curdate:'2010-07-07'
}
I'd like to have a "root" template that renders the curdate field and then renders the items. If an item contains a "bar" field, I want the item to be rendered with a template named "tpl-bar" (or something like that), otherwise a template named "tpl-foo" should be used. Filtering capabilities (like "do not render items that have a quux field") would be a nice-to-have.
I am aware of the JSONT library, however from what I see it's not dynamic enough to accomplish what I described.
If no such library exists, I'm on the verge of giving it a shot myself. But I'm not sure how to do it at the moment. Code examples or general descriptions would help me.
There's also JSLT, from what I remember reading it's a little more advanced than JSONT. I've never actually used it, though. The problem is that these libraries aren't hugely popular and so not a lot of work gets done to improve them and build upon them.
On the plus side, it's open source so if you don't find a feature you want you could attempt to add it yourself.
I need to implement a webform (JSP, struts) featuring loads of checkboxes and textfields. Basically I have a tree made of checkboxes which has to be extendable (like adding a new node). On another page the same data is used, but refined. So you add again child nodes to the mentioned data structure using textboxes etc. I can describe the datastructure in XML:
But contains about 100 rows in reality.
I found 3 approaches:
1. Do a webform in JSP which lowers the user experience because lots of postbacks are necessary (every time i add/edit/delete a node, subnode...)
2. do it in async fashion. -> loads of javascript to handle the structure of the data (keep the XML data in a hidden div and update ui)
3. go for a RIA like OpenLaszlo
What do you suggest?
If you already know OpenLaszlo, go for it. You will end up with a better user experience with less work.
You should target user interface and performance when developing an app. So IMO, plain JSP will be my last approach.
You can consider client side rendering.It allows to build very responsive web apps:
build your JSP pages to deliver JSON data, no HTML here
use a javascript templating engine in the browser to convert the data in HTML client side. I'm the author of PURE but there are plenty of others on the web that may suit better your style
when the user types or press submit, parse the form using a common technique found in many frameworks. i.e: the "name" attribute is the path to set the value in the JSON<input name="employee.name" type="text" ... />
When the form is parsed, post back the JSON to a JSP page that will read it and do the backend work.
You can use XML instead of JSON and XSLT instead of a JS templating engine, but if you target the web browser only, it adds an extra layer of complexity and trouble to parse the XML.