2

So I feel like this should be a common question but I can't find the answer. Maybe I'm using the wrong terminology.

Assumptions:

  • IDs are supposed to be unique across the document.

  • Class attributes are meant for CSS and should not be used in JS selectors.

  • Name attributes are not appropriate ID replacements since they don't work the same on all elements and the html 5 spec changed them (removed from certain elements I think).

So given something like:

The page has multiple of the same widget. Each widget has a unique ID. I need to be able to reference widget sub-elements like $("#widgetID relativeID"). So that relative IDs are unique within widgets but may be duplicated outside this scope.

I had been using name for this but it seems this isn't the correct way

What is?

2

You first and third assumptions are solid. You middle assumption "class attributes are meant for CSS and should not be used in JS selectors" is completely, utterly wrong. Granted, there's some structural / separation-of-concerns purity about it. But it rejects the reality and common practice of almost all dynamic JavaScript modification of HTML documents.

If you only have one of a thing on a page, and you know that's not going to change, the id attribute works well for both CSS and JS. When there are possibly more than one of a thing, the class attribute is precisely the place to note this. jQuery and all other modern "higher level JavaScript" libraries bake this kind of usage right into their code, documentation, and examples, and everyone uses class selectors in this way.

Relative ids are not a standard part of either CSS or JS parlance, and they probably never will be. The very idea suggests taking something that is absolute and making it relative. Given the availability, success, and ubiquity of class selectors, what would be the point? If you want to simulate that kind of access, define unique class selectors and then use the relative (e.g. child, descendant, or adjacent sibling) notation that's already part-and-parcel of CSS and JS usage.

  • So to maintain separation between css and js, I imagine I shouldn't use the same class name for both styling and selecting. Instead I should use two classes if I need to style and select the element. ie: class="style1 select1" but with appropriate names. That make sense? – slicedtoad Jul 16 '14 at 16:06
  • If you need that kind of purity, yes. Typical practice uses the same class name when possible, for simplicity. Occam's Razor: "entia non sunt multiplicanda praeter necessitatem (entities must not be multiplied beyond necessity)." – Jonathan Eunice Jul 16 '14 at 17:10
  • okay, thanks. I'm going with this. Sometime I will try the html5 data-* but for this project classes should work. – slicedtoad Jul 16 '14 at 17:20
  • The problem with both ids and classes and names is that they result in namespace pollution. This causes all sorts of composition problems and results in anti-modular design of the traditional web stack. This is fine in the traditional interpretation of every document being its own island, but in today's SPA and dynamic websites, modularity is key, and we need better namespacing. – CMCDragonkai Sep 20 '16 at 11:46
  • @CMCDragonkai Be careful what you ask for. More granular namespacing sounds grand, but look at XML, which got its namespace wish. Even though XML arguably needs namespacing much more than HTML/CSS, it complexified parsing and using XML in so many ways. JS even has separate DOM APIs to deal with namespaced vs. non-namespaced elements. Yuck! In CSS, vendor prefixes are basically namespaces. Define your own if you like. But many would argue they too are a huge pain. – Jonathan Eunice Sep 21 '16 at 5:15
3

You are right that Class attributes [were originally] meant for CSS, but that doesn't necessarily mean that you cannot also use them as JavaScript hooks. (But some care is required.)

According to the HTML4 spec,

The class attribute has several roles in HTML:
    * As a style sheet selector (when an author wishes to assign style information to a set of elements).
    * For general purpose processing by user agents.

This doesn't explicitly say whether classes should be used as JS hooks or not (is that "general purpose processing"?).

In the HTML5 spec, all of this language regarding the role of classes is not there. It simply states that class is, "a set of space-separated tokens representing the various classes that the element belongs to". Then it reports that class can be used as a JS selector using getElementsByClassName()

That said... I do understand your hesitancy to use the class attribute for the dual purpose of controlling style and behavior. It is not a good thing to try to change how your page looks, only to realize that you also changed its functionality.

To get around this problem, I have seen a couple of different solutions.

(1) Name your JavaScript hook classes with a js- prefix. If you do this, it is clear which classes are meant as JS hooks, and which are not.

<input type="text" class="required js-typeahead" name="some-text" />

(2) Use data-* attributes instead of class for JS hooks. This also gives you the added benefit that you get a key-value pair for your JS code.

<input type="text" class="required" data-typeahead="typeahead" name="some-text" />

Of course, you can use data-* attributes for styling, so you don't necessarily get around your separation of style and behavior.

#input[data-typeahead] {
    background-image:  url("typeahead.png");
    background-repeat: no-repeat;
}
  • +1 for data attributes. They are a very underused tool in the web devs armory. – razethestray Jul 16 '14 at 17:37
2

Combine the two ID's together, as in ID="WidgetID_RelativeID" This will guarantee uniqueness.

  • I suppose that would work but it's one of those solutions that feels ugly and is indicative of not using all the features of the language. Like prefixing your db table columns with the db name instead of just using . notation. What are your thoughts on Jonathan's solution? – slicedtoad Jul 16 '14 at 16:10
  • @Robert Harvey: How would you write a selector for all of the relativeID elements in the document? – Paul Hanbury Jul 16 '14 at 16:25
  • @PaulHanbury: The OP says that those are not guaranteed to be unique. – Robert Harvey Jul 16 '14 at 16:26
  • @PaulHanbury api.jquery.com/attribute-ends-with-selector – Eric King Jul 16 '14 at 16:28
  • The OP didn't mention jQuery. But I do suppose that $("[id$=widgetsuffix relativeID]") would match. – Paul Hanbury Jul 16 '14 at 16:37
1

Note: This question may be better suited to Stack Overflow rather than programmers.

I would use the .dataset(MDN) to store local IDs. I would access them using element.querySelector(MDN).

Example[1]:

<widget id="AwesomeWidget">
  <div data-ID="Sidebar"></div>
  <div data-ID="Toolbar"></div>
</widget>

and I would access them in Javascript using the following approach:

AwesomeWidget.querySelector("div[data-ID='Sidebar']");

[1]: Not valid HTML: Custom-elements must have have a - in their names, so x-widget is OK but widget is not.

  • hmm, I will look into this. And I put this here instead of SO since it's more a question about standards and best practice. – slicedtoad Jul 16 '14 at 16:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.