For the past few years I have always used a client-side hidden <input> field to store a server-side value and use it in Javascript land.
For example, let's say I need an Ajax timeout value from my app configuration.
I'd probably store it like this in my JSP:
<input type="hidden" id="ajaxTimeout" value="${serverValue}" />
and then use it like this where my AJAX call lived in an external file:
$("#ajaxTimeout").val()
I was having a discussion about this today and it was suggested that it is best practice to store values which are only going to be used by Javascript within HTML <meta> tags.
Does this matter? Is there a preferred way to obtain server-side information which is solely to be used in Javascript?
My understanding is that if the hidden input field is not part of a form then it is safe enough to use to store value as it won't be attached to any requests. Having said that, I've always thought this was indeed a bit of a hack.
Thoughts?
::EDIT::
Two fantastic answers:
Use objects literals for general in-page data that is not tied to any particular DOM element.
Use data attributes to store custom data tied to DOM elements: http://www.w3.org/TR/2010/WD-html5-20101019/elements.html#attr-data
In addition to the plain old object literal method given in other answers, if the value you want to pass to the client is about a specific DOM element (or there is a DOM element that represents the logical object that the value is about), you can put the value in a data attribute:
<div id="videoplayer" data-startplayingat="1:02">HTML Content</div>
This is accessible as an entire attribute, data-startplayingat, or in modern browsers there is the dataset attribute. jQuery syntax is $('#videoplayer').data('startplayingat').
The official W3C spec on data attributes explains all this.
Here are a few interesting highlights:
The name must not use upper case letters, and must be XML compatible.
The dataset attribute converts dashes, such that a name like start-playing will become startPlaying.
One potential drawback for the object literal method (which I like and have used myself) is that if you want the object in a .js file, then normally static javascript files have to be run through your dynamic parser--which will cause a potentially small (but still present) performance loss. Putting the object declaration into a <script> tag in an HTML file works around this, but then you can have script load order issues to deal with.
We personally do something like this:
var options = {
selector: '#divId',
serverSideVariableHere: <%=AspNetProperty %>,
anotherServerSideVariableHere: <%=AspNetPropertyTwo %>
}
var viewModel = new KnockoutViewModel(options);
ko.applyBindings(viewModel, $(options.selector)[0]);
This is simply an example using KnockOut JS, but this idea can be expanded to any JavaScript library you choose to use (or not ;))
We then pass these options to whatever use them, such as Knockout ViewModels, or whatever. That way our JavaScript remains testable and we can pass in whatever values we want to our tests.
Using meta tag for something other than browser meta-"instructions" is no less of a hack IMO.
I would consider storing JavaScript data where it belongs - in JavaScript, using JavaScript object literals.
I strongly prefer JSON snippets in data- attributes. This lets you scope them to the related HTML element, and you don't pollute your Javascript global namespace, or have to generate additional code to handle namespacing otherwise. Coupled with a JSON serialiser on the server side this minimises having to manually escape anything in your values.
(Also I have a Thing™ against <script> tags with content in general. View and logic separation and all that.)
Related
I'm wondering which of the following would be the best way to pass server data and use it in a function, especially if the function is to be used by a component
Method 1
function doSomething(elm, serverTime) {
// Do something
}
<script>
doSomething('foo', '<% php server time %>');
</script>
vs
Method 2
<div id="foo" data-server-time="<% php server time %>"></div>
function doSomething(foo) {
var serverTime = getElementById("server-time").dataset.servertime;
// Do something
}
<script>
doSomething('foo');
</script>
Method 3
Other suggestions?
Would like to do something like the following but not sure how?
document.getElementById("foo").doSomething() ?
For me, case 1 would be better.
code would have less coupling
code would not use global vars (document.getElementById)
you could reuse your function in other places that do not have DOM, like in the server.
I would argue in this case the 1st is better in this simple example because sever time isn't really attached to any specific div element.
Just make sure no matter what you do that there are no XSS security holes.
You are at a crossroads looking for common practice, to which one isn't more prevalent over another. Any great sage may tell you, which you choose isn't as important as making the same choice again; that is, be consistent.
Depending on the type of information, I would either pass it in the:
HTTP header (e.g., via HTTP Cookie)
Querystring (if redirection is used)
External JSON file (e.g., server.json), loaded via JS
Embedded JSON object (e.g., window.SERVER = {'server_time': <%php ...%>};)
In your case, keeping it closer to the JavaScript makes more sense and is easier to maintain, if the JS is the main place you're working. Therefore, Method 1 is both cleaner and easier to make changes in the future. Method 2, would require sifting through the HTML and making sure you are modifying the correct line.
Though, I'm somewhat partial to keeping server data as an external JSON, or embedded JSON object. So if you needed to track other server data/metadata, it's easy to add to it.
I would argue that all of them are the same and depending on your coding manner, they woulh have the same performance performand.
Let's not forget that nowadays, the most common way is to attach event listeners to elements (jQuery, Angular and .., use heavily event listeners).
I need to keep the state of my Html control (I've a multi select list and I need to keep the info about selected items), for which I'm using a custom attribute like:
// put
$("#element").attr("selectionState", "value");
// get
alert($("#element").attr("selectionState"));
While it works, I wonder if it's a safe approach and if not, how would you solve the problem?
The only risk I can see is - another script creating custom attributes with the same names, which is something I can manage.
I suggest using .data() instead.
$('#element').data('selectionState', 'value');
It's definitely safer, as it keeps the data completely in JavaScript instead of the "attributes" maps in the DOM elements. Sins ".data()" is all JavaScript, you can store anything there, including functions and closures. (I guess you could do that with ".attr()" too but it's pretty risky in IE, which, in old versions at least, had quite different storage management internally for DOM and for JScript.)
The namespace problem you allude to is of course the same, as would be the possible ways of managing it.
I have a particular scenario where I need a file name, not once but twice, because I pass the variable to an ASP.NET MVC controller. Is it a good idea to either store the file name in a DOM element like a span or div, and getting the value by using jQuery's .text() function? Or would a better approach be to work with JSON-like objects that are initialized and then continuously manipulated?
The question however remains. Is it a good or bad idea to store variables in HTML DOM elements?
As #Atticus said, it's fine to do it either way, and I'll do both depending on what I need the data for: If it's specifically tied to the element, I'll store it on the element; if it's more general to the page, I'll pass back an object using JSON notation.
When storing data on DOM elements, you don't need to store them as text within the element. You can use data-* attributes instead. These are valid as of HTML5 and work in all browsers right now. The only downside is that if you're using validation as part of your workflow, and you're not yet using HTML5 to validate (and that wouldn't be surprising, the validator isn't quite ready, what with the spec still being rather in flux!), they don't validate in HTML 4.01 or below. But browsers are fine with them, this is one of the areas where HTML5 is codifying (and reigning in) current practice, rather than innovating.
Either one works, and it's fine to store data in a DOM. It more so depends on the complexity of the operation you are trying complete, which sounds simple -- storing file names. I think you should be fine doing it this way. Storing in JSON object works too, I would go with whatever fits your structure best and which ever works easier with your client/server handshake.
Is it considered good practice to use DOM Element's getAttribute/setAttribute calls to associate additional information about contents of the element ?
For example I want to call setAttribute("MY_ATTRIBUTE_VALUE", "..."), where MY_ATTRIBUTE_VALUE isn't anything applicable to <div>.
Thanks !
You should definitely go with data attributes. Here's an article on them. HTML5 Custom Data Attributes.
It is very good practise as long as you're setting custom data attributes, whose purpose is holding meta data about those elements. Data attributes take the form data-name where name can be any valid descriptor.
Traditionally people would add classes, and in some cases this is still appropriate (e.g. when a class describes the state of an attribute and also denotes a style class, for which class is primarily used).
If you believe that markup is about presentation, then associating data with HTML elements is inconsistent with that philosophy. If you think that it doesn't matter, then use data- attributes introduced in HTML5. Note however that HTML5 is not a standard and is not yet that widely supported (if the term "supported" has any meaning in the context of a "living specification" that is constantly changing). However data- attributes likely won't upset most browsers but you must use get/setAttribute to access them reliably in a browser independant way.
It is considered good practice to keep data separate from presentation so that you can change the presentation to provide multiple views of the same data. If you bind data to the presentation, you reduce your ability to do that. It also means that changing the data model may well affect presentation unnecessarily.
Storing data in an object and relating it to the element (say by the element's id) will likely provie much faster access to the data (direct property access is much faster than function calls passing strings) and allow for a more flexible UI and data model.
Well, I admit: I've extensively used jQuery.attr to store custom data in DOM elements in many, many scripts. I'm wondering if convert all my script to use jQuery.data instead of jQuery.attr. As far as I understand, the advantages of jQuery.data are:
produce neat and valid HTML code
can store any type of data (objects, array,...) on elements
The main advantage of custom attributes are:
If WEB pages are not strict HTML, I can produce HTML code with custom attributes on the server
In firebug it's easy to inspect my HTML code in search of my custom attributes
Can someone tell me if I miss something or if exists issues that makes use of jQuery.data highly preferable?
You pretty much got it. But do you know every HTML attribute? There are a lot of attributes that are used by screen-readers and other usability tools that are not standard (yet). What happens when you accidentally use the role attribute and a screen-reader picks that up? Using $.data isn't only neater, it's safer for you and makes more sense.
EDIT: I learned something last night that is pertinent to this question. In HTML5, you ca specify custom attributes for storing data. These custom attributes must be specified using the prefix "data-". See the spec for more detailed information.
What this means, is that you do not have to go back and change all of your old code, because you will never have to worry about overlapping with other attributes if you prefix with "data-". However, if you need to store more complicated data types than strings, use $.data.
I think that you don't miss anything but storing data on dom elements attributes is always a bad practice so i think you should use the $.data function.