2

I'd like to add a button to all spans with a given class. Is the answer in this question still the preferred way of doing it (I keep seeing answers get contradicted as out of date)?

adding onclick event to dynamically added button?

Here is my code (so far):

var button = document.createElement("button");
button.innerText = "Add test";

var allSpans = document.getElementsByTagName('span');

allSpans.forEach(function(span) {
    if(span.class == "behavior-header-title"){
        span. //i'd like to call something like addElement(button) here
    }
});
Community
  • 1
  • 1
Ramy
  • 20,541
  • 41
  • 103
  • 153

4 Answers4

2

When you call getElementsByTagName, you get back an HTMLCollection. It's like an Array, but it's not an Array, so it doesn't have a forEach method. So you'll have to call Array.prototype.forEach.

To do the actual appending, you want Node#appendChild, which appends a Node to another Node. However, Nodes can only appear one place in the DOM. If you append the same Node twice, it will get moved from its location to the new location. So you need to clone the button each time.

Putting it all together:

var button = document.createElement("button");
button.innerText = "Add test";

var allSpans = document.getElementsByTagName('span');
Array.prototype.forEach.call(allSpans, function(span) {
  if(span.className === 'behavior-header-title') {
    span.appendChild(button.cloneNode(button))
  }
});
Interrobang
  • 16,984
  • 3
  • 55
  • 63
2

Convert the HTMLCollection to an Array and append the button element with appendChild:

var allSpans = document.getElementsByTagName('span');

[].slice.call(allSpans).forEach(function(span) {
    if(span.className === 'behavior-header-title') {
        var button = document.createElement('button');
        button.innerText = 'Add test';
        span.appendChild(button);
    }
});
<span></span>
<span class="behavior-header-title"></span>
<span></span>
<span class="behavior-header-title"></span>
Miguel Mota
  • 20,135
  • 5
  • 45
  • 64
  • should that be `slice.call(allSpans)`? – Ramy Mar 19 '15 at 02:02
  • ah, gotcha. sorry. was trying to translate to my own code – Ramy Mar 19 '15 at 02:04
  • this isn't working for me and I can't tell why. I have no reason to believe this won't work but it's not working for me atm. – Ramy Mar 19 '15 at 02:06
  • Are you getting errors in console? Can you provide a JSFiddle with the code you're trying to run? http://jsfiddle.net/61eeoxm4/ – Miguel Mota Mar 19 '15 at 02:08
  • actually it's working in jsfiddle. must be something with the html. I'll have to look more closely at that. – Ramy Mar 19 '15 at 02:14
1

What you are trying to do is build a dynamic web page. While this should be left moreso to PHP (PHP Hypertext Processor, a serverside scripting language widely supported by multiple web servers), there is a solution in javascript.

There are multiple solutions to this problem, but I will give you the barebone basics of what you will need to do in order to achieve this.


The first thing that you need to do is make the button have a onclick attribute set. You can do this like so:

var button=document.createElement("BUTTON");
button.setAttribute("onclick","yourFunction()"); //Function Definition will go here.

This will make it so your button will have functionality when added to the document.

Next, you must actually create the function. I assume that you want one of two things:

  1. A set function, which would be already created for the environment in which it is used, or
  2. A dynamic function, one that would be different based on the caller.

I will give a small example of each.

For the set function:

var button=document.createElement("BUTTON");
button.onclick = function(){
    //Event handling code.
};

For the dynamic function (A little more effort):

//...FUNCTION...//
function bFunc(/*parameters*/){
    /*Code (Using Parameters)*/
}

//...BUTTON...//

var button=document.createElement("BUTTON");
button.onclick = function(){
    bFunc(/*Any parameters needed*/);
};

And then add the button to the span:

var spans = document.getElementsByTagName("span"); //CREATE ARRAY OF ALL SPANS
for(var i = 0; i < spans.length; i++){
    spans[i].appendChild(button); //APPEND THE BUTTON TO EACH SPAN
}    
Interrobang
  • 16,984
  • 3
  • 55
  • 63
DripDrop
  • 994
  • 1
  • 9
  • 18
  • I downvoted your answer because mixing JavaScript event handlers and HTML is bad practice such as using the `onclick` attribute, it's lack of Separation of Concerns. You're encouraging to write a function as a string in the setAttribute argument which is definitely the wrong way to go about it. And finally `var spans[] =` is not how you define an array. Please test your code before posting. – Miguel Mota Mar 19 '15 at 02:10
  • Oh, sorry! My answers are generally more conceptual, with just the essence of what I am trying to get across included. I will edit my answer. – DripDrop Mar 19 '15 at 02:12
  • No problem! I'm sorry though, I recently went back to Java, which is where I assume the confusion with the arrays took place. – DripDrop Mar 19 '15 at 02:20
-3

I can't imagine that the preferred way, at least in production, doesn't involve jQuery. With jQuery, the code would be:

$(function() {
    $("span.behavior-header-title").each( function(index, element) {
        element.append("<button></button")
    });
});

Working fiddle without jQuery: https://jsfiddle.net/tsclaus/b2by02yv/2/

Tahsis Claus
  • 1,879
  • 1
  • 15
  • 27
  • 1
    Why can't you "imagine" that the preferred way is *without* jQuery? jQuery is still JavaScript. – Miguel Mota Mar 19 '15 at 01:51
  • @moogs http://meta.stackexchange.com/questions/45176/when-is-use-jquery-not-a-valid-answer-to-a-javascript-question I mean really, including jQuery might add .1 seconds to your loading time, and my answer has half the function calls your's does. – Tahsis Claus Mar 19 '15 at 01:54
  • I hope your answer was sarcasm. – Miguel Mota Mar 19 '15 at 01:57
  • 1
    I appreciate the answer but I'm trying to do it purely in JS. partly to learn JS. (no i did not down vote you) – Ramy Mar 19 '15 at 02:08
  • 1
    @Ramy If I cared about the downvotes I would delete my answer (as it returns the reputation). I have edited my answer with fairly concise code. – Tahsis Claus Mar 19 '15 at 02:35