-1

I am making website where I am created a lot of labels that are assigned in output as here

Use fiddle link at the end of the post

<!-- lets say that I want to make a kind of board to show some game clans or... whatever -->

<label class='team' name='ally'>Madcowz</label><BR>
<label class='team' name='ally'>Fluffy Unicorns</label><BR>
<label class='team' name='enemy'>Blue bastards</label><BR><BR>

<b>JS stuff:</b>
<div id='printSomeOutputHere'></div>

<!-- The problem is that the NAME tag does not exist for label in this case: -->
<!-- I can't use ID because ID should be unique values -->
<script>
var teams = $(".team");
for(i=0; i<teams.length; i++)
{
    document.getElementById('printSomeOutputHere').innerHTML += teams[i].name + ": " + teams[i].textContent;
    document.getElementById('printSomeOutputHere').innerHTML += "<BR>";
}
</script>

Fiddle: http://jsfiddle.net/cusnj74g/

name attribute is undefined, so how can I mark these labels with same name if I can't use (I can, but I should not) ID

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Bartłomiej Sobieszek
  • 2,692
  • 2
  • 25
  • 40
  • 2
    use a data attribute? data-name? – Shan Robertson Jan 19 '15 at 18:12
  • 1
    are you wanting a jQuery solution or a plain javascript solution? – DA. Jan 19 '15 at 18:16
  • 1
    *"Use fiddle link at the end of the post"* If you don't want people to use the Stack Snippet in your question, make the code in the question just a code block (not a Stack Snippet). But really, it's better to use a Stack Snippet than a fiddle now that SO has them. – T.J. Crowder Jan 19 '15 at 18:19
  • [`name` is not a valid `label` attribute](http://www.w3.org/TR/html5/forms.html#the-label-element). – T.J. Crowder Jan 19 '15 at 18:19
  • 2
    `teams[i].getAttribute("name")` – 1252748 Jan 19 '15 at 18:20
  • @Stephen: I rolled back your edit. As the question has code in it using jQuery, removing the `jquery` tag isn't appropriate. – T.J. Crowder Jan 19 '15 at 18:21
  • @Thomas is right. `name` isn't officially an attribute of `label`. But you are allowed to make custom attributes. Still name is kind of ambiguous. – Mouser Jan 19 '15 at 18:25
  • 1
    @Mouser: *"you are allowed to make custom attributes"* Only if they start with `data-`. – T.J. Crowder Jan 19 '15 at 18:25
  • @T.J.Crowder what could possible happen if you didn't start it with `data-`? And yes the remote possibility that the attribute you came up with will somewhere in the not so foreseeable future become part of the standard and your code will then break or behave weird. – Mouser Jan 19 '15 at 18:29
  • Thank you all, I am not even close to being an intermediate html / js / jQuery programmer and the biggest problem for me is to adapt this style, taking control over balance between php html js and jQuery / Ajax and sql is terrible to learn in short period of time. Every word posted here from you is a gold tip :) Sure I know how to make a webpage, but I don't know how to make it in... well... readable and nice code :D Especially php blows my mind up, when even comments don't help me to make it clear – Bartłomiej Sobieszek Jan 19 '15 at 18:41
  • 1
    @Mouser The standard requires the prefix for good reason - primarily to avoid collisions with future standards as you have yourself stated. Let me reverse your question, what could possibl**y** happen if you prefix your custom attributes with "data-"? Your code now validates? This may be a legal requirement in some areas depending on accessibility laws. Apart from anything else, valid code allows you to focus on "real" validation errors rather than having to spot them amongst dozens or hundreds of "unimportant" "what could go wrong" ones. – pwdst Jan 19 '15 at 18:44
  • You seem to be asking how to use `name` without using `name`. You should instead describe what you are trying to accomplish, functionally or rendering, i.e. what is the purpose for which you would use `name` attributes. Besides, you seem to be using `label` elements against their definition; they specify labels for controls, but you don’t show any controls, and with this markup, these `labels` are not associated with any controls. – Jukka K. Korpela Jan 19 '15 at 18:44

4 Answers4

5

A couple of points:

  1. You seem to know that name is not a valid attribute for label elements. So don't use it, use data-name instead.

  2. You're using label elements incorrectly. There are two ways you use label: A) By putting the input, select, or textarea it relates to inside it (<label><input type="checkbox"> No spam please</label>), or by using the for attribute to associate it with one of those elements elsewhere in the document (<label for="no-spam-please">No spam please</label>...<input id="no-spam-please" type="checkbox">). Having a label with no control in it and no for is fairly pointless; just use a span.

  3. You're using jQuery in one place, but not in others. I suggest that if you're going to have a library on your page, it's best to get full use out of it. In this case, to access the attribute, you'd use $(teams[i]).attr("name") or better, $(teams[i]).attr("data-name") if you're using a data-* attribute (see #1 above). (Some may tell you to use .data to access the attribute; don't, that's not what it's for. But you might consider looking at what it's for and whether that helps you.)

  4. .innerHTML += "content" is an anti-pattern. It makes the browser loop through all elements within the element you're doing it to to build a string, then append the string on the right with it, then parse the result, and delete all existing elements within the element and replace them with the parsed result. Instead, consider .insertAdjacentHTML("beforeend", "content")

  5. You don't declare i anywhere, which means your code falls prey to The Horror of Implicit Globals. Declare i, or use any of several other ways to loop that don't require an index counter.

  6. Your output will be fairly hard to read, recommend breaking it up (perhaps a div for each team?).

  7. textContent is not reliable cross-browser, some browsers use innerText instead. (And there are differences in how whitespace is treated between them.) Since you're using jQuery, use text.

...but yes, the code would work if you used .getAttribute("name") rather than .name. Browsers make access to even invalid attributes available through getAttribute. They just don't necessarily create reflected properties for them.

Here's a version with the various comments above applied:

var output = $("#printSomeOutputHere");
$(".team").each(function() {
  var $this = $(this);
  output.append("<div>" + $this.attr("data-name") + ": " + $this.text() + "</div>");
});
<span class='team' data-name='ally'>Madcowz</span><BR>
<span class='team' data-name='ally'>Fluffy Unicorns</span><BR>
<span class='team' data-name='enemy'>Blue bastards</span><BR><BR>

<b>JS stuff:</b>
<div id='printSomeOutputHere'></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

...or to avoid repeated appends we could use map and join:

$("#printSomeOutputHere").append(
  $(".team").map(function() {
    var $this = $(this);
    return "<div>" + $this.attr("data-name") + ": " + $this.text() + "</div>";
  }).get().join("")
);
<span class='team' data-name='ally'>Madcowz</span><BR>
<span class='team' data-name='ally'>Fluffy Unicorns</span><BR>
<span class='team' data-name='enemy'>Blue bastards</span><BR><BR>

<b>JS stuff:</b>
<div id='printSomeOutputHere'></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Very thorough post. I prefer your answer to mine. – Paul Jan 19 '15 at 18:36
  • Since jQuery is in the mix, how about using [`.data()`](http://api.jquery.com/data/) rather than `attr`? – steveax Jan 20 '15 at 02:31
  • @pwdst: Doh! Copy and paste error, meant to fix those. Thanks, fixed now. – T.J. Crowder Jan 20 '15 at 09:23
  • 1
    @steveax: Because as I say in the answer, that's not what `data` is for. If you're only accessing the attributes, not actually using the separate data cache that `data` manages, using `data` is inappropriate (and sometimes misleading, since it doesn't write back to the attribute). – T.J. Crowder Jan 20 '15 at 09:27
1

Use getAttribute instead:

teams[i].getAttribute('name')
rwacarter
  • 1,915
  • 1
  • 14
  • 25
  • 1
    Do this but also do what Shan Robertson mentioned, rename all you instances of name to data-name and do teams[i].getAttribute('data-name') the label tag doesn't have a name attribute. – 88jayto Jan 19 '15 at 18:18
1

Why not use multiple classes:

<label class='team ally'>Madcowz</label><BR>
<label class='team ally'>Fluffy Unicorns</label><BR>
<label class='team enemy'>Blue bastards</label><BR><BR>

And the JS:

<script>
var outEl = document.getElementById('printSomeOutputHere');
var teams = $(".team");
for(i=0; i<teams.length; i++)
{
    outEl.innerHTML +=
        (teams[i].hasClass('ally')? 'ally':'enemy') + ": " +
        teams[i].textContent;
}
</script>
ptrk
  • 1,800
  • 1
  • 15
  • 24
  • Because my example is not the real thing I am working on, actually it only shows my problem, but in my project the idea of making 100+ different classes isn't fine with my taste (I think that there always should be more ids than classes, not in reverse ways). It's just a matter how I see my code – Bartłomiej Sobieszek Jan 19 '15 at 18:37
  • I get your point, but I'd argue that CSS classes are not like OOP classes, ie you don't introduce an additional 'entity' with each of them. – ptrk Jan 19 '15 at 18:44
  • @BartłomiejSobieszek: I'm not necessarily supporting ptrk's "use a class for this", but *"I think that there always should be more ids than classes, not in reverse ways"* puts you markedly at odds with most advice in that area, I believe. :-) – T.J. Crowder Jan 19 '15 at 18:44
1

From https://developer.mozilla.org/en-US/docs/Web/API/Element.name:

[The name property] only applies to the following elements: <a>, <applet>, <button>, <form>, <frame>, <iframe>, <img>, <input>, <map>, <meta>, <object>, <param>, <select>, and <textarea>.

Since you're using jQuery I would use something like:

for(var t in teams){
    $('#printSomeOutputHere').get(0).innerHTML += 
        teams[t].getAttribute("name") 
        + ": " 
        + teams[t].text() 
        + "<BR />";
}
Paul
  • 646
  • 4
  • 13
  • `getAttribute` does work, but the code above will fail because of the `for-in`. That will loop through every public property on the jQuery object `teams`, which includes (as of jQuery 1.11.1) 149 properties other than the indexes, properties such as `length` and `ajaxStart` and `bind`. The code will throw as of the first key that isn't an index, since `teams[t]` will give you back something that isn't an element, and has no `getAttribute` on it. ([More about looping arrays and array-like things.](http://stackoverflow.com/questions/9329446/for-each-over-an-array-in-javascript/9329476#9329476)) – T.J. Crowder Jan 19 '15 at 18:42
  • Interesting, @T.J.Crowder. I suppose it would be more appropriate in this case to use a jQuery $.each(). – Paul Jan 19 '15 at 18:45