Lately I've been writing more and more JavaScript for the websites I've been creating. And I can't help but think that I'm doing something wrong, or there has to be a better way.
I have a clean separation of concerns on the server side, but on the client side, I find myself having entire sections of JavaScript that are dependent on specific element id's and class names, etc. For example, on one page, that has a lot of form fields, I may have a section of code that looks like:
$(document).ready(function() {
$("#ButtonID1").button();
$("#Grid").someGridFunction();
$(".data-fields").datepicker();
$(".submit-links").click(function() { this.closest("form").submit(); });
});
What I'd almost prefer is some way for the HTML elements to request to obtain certain functionality. Something like:
<input type="text" data-make="datepicker" />
But even that is flawed, because customization of that would require more and more attributes on the HTML element to detail specifics. I had a similar setup done with KnockoutJS and I really wasn't happy with the HTML that was required.
Maybe something along the lines of this:
<input type="text" data-init="buildDefaultDatePicker" />
where "buildDefaultDatePicker" is a JavaScript function that handles the necessary work.
In the end, the question I have is two fold. Is there any value in separating the JavaScript from the UI in regards to specific element ids and class names. And if so, what patterns, and or methods have you used to achieve this?
(Note, I'm using jQuery syntax above, but I think this question is framework agnostic, so shouldn't matter for the answers)
It looks to me like you've got the right idea already (using classes to apply JavaScript enhancement to specific elements). Using a custom attribute such as data-make or data-init would be just another (more fiddly) way of doing the same thing. The way you have things already, specific classes can be used as the request to obtain certain functionality.
The method I'd advise is keeping a clean separation between your HTML and JavaScript. The JavaScript should always be in external files, and written to target page elements on $(document).ready to provide the requested functionality.
I'd just use a class to signify the elements you want to attach behavior to. It has a semantic meaning, and you aren't coupling the html IDs or their locations into the javascript.
In the likely event that you need some specifics, like say a minimum or maximum date on a date picker, a light sprinkling of data attributes I think is an elegant way to provide it. But anything that would require more than a few data attributes is probably, in reality, a whole new kind of thing that deserves its own class, thus removing the need for the data attributes. For example, you might have a datepicker class, and find yourself constantly providing a minimum date of today to force a future date selection. Well, just make a 'futuredatepicker' class instead.
Related
As a new web developer, I've been utilizing a lot of resources like StackOverflow to assist me in the learning and development process.
When using jQuery, all of the examples/responses that I've come across so far have only referenced classes, like so:
$('.yourClass')
as opposed to
$('#yourID')
Seeing that class referencing seems to be the trend (I honestly haven't found one author who writes a jQuery to an ID), are there any pitfalls I should be aware of for using ID's w/ jQuery or JS in general? Thanks!
EDIT 1: I'm aware that ID's are for single-items, classes are for accessing multiple items. I'm more interested in why I don't see any jQuery or JS examples referencing ID's. Thank you!
You would have to ask each author on a case-by-case basis, but generally when creating examples, the selector used doesn't matter; what's important is that you have a jQuery collection that you can call a method on.
By using a class selector in the example, you avoid newbie developers claiming that your plugin doesn't work when they try to use it on multiple elements with the same ID. Your example serves the purpose of showing how to use it on one or more elements, rather than just one.
People like to use classes because ids have to be unique across the whole page. When trying to make reusable, pluggable components, id's make this impossible to enforce.
Exception: the new web-components standard allows you to encapsulate ids to just your component.
An ID must be unique, you can have only one (like highlanders).
Classes are used to identify a "type" of object not a specific one.
An obligatory car analogy:
An ID is a license plate, unique to one specific thing #345-abc
The class relates to a whole category of things like .truck
Take note that a selector like $(".something") will actually be capable of producing a list of DOM elements; as it will select all DOM elements with the class of "something"
An ID selector $("#unique") will only ever return one element
Think of your HTML and CSS first.
Using Classes
If you have multiple HTML elements which all will look, feel and behave in the same way, then it is highly recommended to use a class to represent their style and behavior.
Example: rows or columns on a table, navigation buttons which animate in the exact same way, wrapper to images which have the same size throughout your website, etc.
Using ID's
However, if you have a unique HTML element which represents a particular thing or state or action in one of your pages, then that element should contain an id.
Example: pop up modal, a unique looking button, unique sections on your website which you can navigate to by their id, etc.
Then, you can use this behavior in your JavaScript and jQuery or whatever else you like to use.
Further reading
I know that you are fully aware of why we should use ID's or classes.
But the vast majority of answers that are given here, are thinking of a project context.
So, let's say editing a .js file that is linked to the scope of the entire project, the idea here is to be as reusable as possible, so that's why you'll see much more classes references than ID's. Is hard to maintain a project js file that makes reference to different ID's that are abroad the project.
Same thing will apply to css.
I hope the answer is enough, be free to post a comment or suggestions. :-)
I one day was thinking that I could remove duplication of id this way:
htmlElements = {
$tabs: jQuery('#tabs'),
$tabs1: jQuery('#tabs-1'),
};
and in javascript when need to acceess - use htmlElements.$tabs for example. I was thinking - if the design needs to be changed, it the designers might use different ids and we will need to change things either in design or in javascript code to replace all ids. And this way we would need to replace in one place.
Is it too hardcore or good thing? Cannot find on internet questions about this.
I think I decided to do this after I saw that backbone has $el in the object.
I'm making a html template generator sort of like this. It's going to have specific style and markup so all it really has to do is take the inputs from the form and place them in the "template" and output as text for easy copy/paste. I was wondering if there is an easier way to make this, like using jQuery. Open to all suggestions.
jQuery has a selection of methods for dealing with the DOM that could come in useful for creating HTML markup from a form. It also has a few methods specific to forms themselves, if that suits your purposes.
Check out the API for Manipulation. There are a variety of methods you may find useful.
Since you are constructing HTML with form values, the .wrap() method could be quite valuable to surround content with the inputted tags, ids, and classes, which could be styled with a externally linked CSS file. See also the .wrapAll() and .wrapInner().
You may find the .html() method interesting as well for grabbing the contents of any element. It is somewhat the reverse of what you need but it could come in handy.
I've had this happen to me three times now and I feel it's time I learned how to avoid this scenario.
Typically, I build the HTML. Once I'm content with the structure and visual design, I start using jQuery to wire up events and other things.
Thing is, sometimes the client wants a small change or even a medium change that requires me to change the HTML, and this causes my javascript code to break because it depends on HTML selectors that no longer exist.
How can I avoid digging myself into this hole every time I create a website? Any articles I should read?
Make your selectors less brittle.
Don't use a selector by index, next sibling, immediate child, or the like
Use classes so even if you have to change the tag name and the element's position in the HTML, the selector will still work
Don't use parent() or child() without specifying a selector. Make sure you look for a parent or child with a specific class
Sometimes, depending on the amount of rework, you'll have to update the script. Keep them as decoupled as possible, but there's always some coupling, it's the interface between script and HTML. It's like being able to change an implementation without having to change the interface. Sometimes you need new behavior that needs a new interface.
I think the best way to help you is for you to show a small sample of a change in the HTML that required a change to your jQuery code. We could then show you how to minimize changes to JS as you update the HTML
I have been tasked with improving the current mess that is our JavaScript "strategy"; we're an online shopping company and my boss has given me time to do this properly. He is very keen on keepin this modular and increase the reusability of the components.
Our HTML is being rendered with JSP and we have lots of custom tags writing out, for example, information about products without the web designers needing to worry about it.
Now, we want to do similar things with JavaScript. The web designers should be given a set of custom tags, like, say,
<foo:draggable>
... some HTML here ...
</foo:draggable>
that will wrap the HTML in a <div> with a drag bar at the top and a close button.
My idea is to mark the div with a unique namespaced CSS class name, like foo_draggable, and then put all my functions in a single JS file. That JS file then sees if there are elements with the CSS class foo_draggable in the DOM and if it finds any it will attach the required event handlers.
However, I am worried about scaling problems, and wondering whether it is a good idea to have lots of selector queries running when they quite often aren't going to be used.
The first alternative would be to initiate each draggable item explicitly but that would mean putting <script> tags all over the place. The second approach would be to not put all UI function in one file but rather just download the ones I need, but that would mean lots more HTTP requests and slower page load speed.
Has anyone got experience with this?
What about having two classnames?
<div class='foo fooDragable'></div>
<div class='foo fooSortable'></div>
You add the class 'foo' to all your elements that require javascript modification.
Your javascript has to check the dom only once for foo.
var $foo = $('.foo');
Afterwards you can search within this array which should be way smaller than the complete dom.
var $dragAble = $foo.filter('.fooDragable');
Have you considered or taken a look to JSF? I know it's a major change if you aren't using JSF yet. But there are lot of ready-to-use JSF component libaries with an ajaxical sauce, for example RichFaces, IceFaces, PrimeFaces, etc. It's almost a waste of time to create components/tags for it yourself.
Alternatively you can replace all Javascripts to use the great jQuery JS framework.
Depending on how many separate components you have, the extra overhead of running the selectors might not be a big deal. You can initialize all the components just the once, when the page is loaded. Anything that's not present on the page simply won't get initialized, and will incur no further overhead. In most JavaScript frameworks, selecting by classname (or tag name) is pretty fast. It's only the complex selectors, which aren't natively supported by the browser, that are slow.
If you have a few commonly used components, and then a set of less commonly used ones, it may be worth splitting those up. Keep the commonly used components in a single JavaScript file (minified, served with compression and aggressive caching), and load that in every page, regardless of whether it's needed or not. Caching will ensure it's only downloaded once, and it'll only be one small HTTP request. For the less common components, keep them in separate files (ideally, one per component), and add a script tag on pages that use them.
I'm not entirely familiar with how JSP works, but it might be possible to do this automatically - if a tag is included in the document, add a script tag for foo_widget.js in the document header, or something like that.