0

I've got something like this, but it doesn't work:

<!-- ... code .. -->

var id = 0;        

data.forEach(function(item, i) {
      id = id+1;

$( ".button-" + id ).click(function() {
$( ".button-" + id ).toggle();

});

<!-- ... code .. -->

What I want: There are some DIVs like button-1, button-2 ... and so on. I made an toggle and I wanted to automate it with this loop, because the content is dynamically generated. But this seems to be the wrong way... In this loop it does not work.

So how to make toggles dynamically for button-1, button-2, ... ??

It's just about this, which seems to be wrong:

$( ".button-" + id ).click(function() {
$( ".button-" + id ).toggle();

EDIT

Well, maybe my question was a little bit messy Thank you all so far for your answers, I really appreciate it! But there wasn't the right answer for me... So again and now more concrete:

I've got some buttons with material icons, which are supposed to change their state on click.

<a href="" class="likebutton-1"><i class="material-icons">favorite</i></a>
<a href="" class="likebutton-1" style="display:none;"><i class="material-icons">favorite_border</i></a>

The HTML content is generated dynamically, so there's a likebutton-1, likebutton-2...

Then there's another DIV which shows a number of likes:

<div class="likes-1">99 likes</div>
<div class="likes-1" style="display:none;">100 likes</div>

The DIVs a both within a outer container.

And here is my jQuery Code for that:

$( ".likebutton-1" ).click(function() {
$( ".likebutton-1" ).toggle();
$( ".likes-1" ).toggle();
});      

Well, that code works for me. The icon toggles from favorite to favorite_border and the likes toggle from 99 to 100... (It's just a demo application, so it's not necessary to really count the likes)

But I want to generate that jQuery code dynamically, too, and that's what is not working... for now I have to set manually toggles for likebutton-1, likebutton-2 ...

Kabalaba
  • 63
  • 2
  • 7

5 Answers5

2

I think this is what you mean :D

https://jsfiddle.net/1eo4b33m/1/

$("[class*=button-]").click(function(){
    $(this).toggle()
})
Jamie Phan
  • 796
  • 1
  • 7
  • 26
  • Perhaps also `"[class*=button-]"` if the buttons have other classes added to them and the above doesn't work – ESR Jan 19 '17 at 14:10
  • Though it also will applies to `foobutton-` class, but I think it is better then not apply if there are multiple class, Edited. – Jamie Phan Jan 19 '17 at 14:15
  • Sure, neither solution is 100% robust, either could be suitable depending on OP's circumstances. – ESR Jan 19 '17 at 14:16
  • Hey... mhh tried it, but instead of toggling, the buttons just disappear. I have two button-1, button-2 ... where in each case of them one is display:none; (toggling works if I make it manually ... but not with this solution) – Kabalaba Jan 19 '17 at 14:22
  • This works (my manual solution): $( ".button" ).click(function() { $( ".button" ).toggle(); }); – Kabalaba Jan 19 '17 at 14:27
  • This is what toggle means, click on itself, then it disappear, usually a toggle event is binded to another element to toggle itself. There is an updated example. https://jsfiddle.net/1eo4b33m/2/ **EDIT:** Late reply, glad you found your solution :D – Jamie Phan Jan 19 '17 at 14:36
  • Sorry, no. My manual solution worked before, but it was manual ;-) So I had to make many functions for every button-1, button-2 ... and so on. That's what i wanted to avoid. – Kabalaba Jan 19 '17 at 14:43
2

Based on your latest update I would suggest some structural changes in your HTML markup.

Instead of using:

<a href="" class="likebutton-1"><i class="material-icons">favorite</i></a>
<a href="" class="likebutton-1" style="display:none;"><i class="material-icons">favorite_border</i></a>

I suggest to use only one element - that could prevent styling issues. In addition remove the -1 or -X suffix if you generate those segments dynamically otherwise you need a lot of (dynamically created) event listeners.

Do it like this:

<a href="#" class="likebutton"><i class="material-icons icon-fav">favorite</i></a> 

I added the class icon-fav to your element to access it more easily in advance.

Now we do the same for your like section and improve the code structure. Seperate the like-count (so the number) from the text. So we can easily increment or decrement this number.

<div class="likes"><span class="likes-count">99</span> likes</div>

Because you mentioned you generate this segments automatically I assume you have a or something similar around those elements, like:

<div class="parent-container">
  <a href="#" class="likebutton"><i class="material-icons icon-fav">favorite</i></a>  
  <div class="likes"><span class="likes-count">99</span> likes</div>
</div>

Now we care about the rest - the JavaScript.

We need some tree traversal because of the removed -x suffix of your classes - otherwise we would change all your elements at once when clicking one of them. You can find more about jQuery Tree Traversal here.

$(".likebutton").click(function() {
    var $parent = $(this).closest(".parent-container");
    var likes = parseInt($parent.find(".likes-count").text());

    if($parent.find(".icon-fav").text() == "favorite") {
        $parent.find(".icon-fav").text("favorite_border");
        $parent.find(".likes-count").text(++likes);
    }
    else {
        $parent.find(".icon-fav").text("favorite");
        $parent.find(".likes-count").text(--likes);
    }
});   

This event listener finds its parent container with the .closest() method which makes this code work even if your code is even more nested. This $parent variable is kind of the search-base for all followed queries. I use .find() to traverse up all the way - if it is necessary - because you probably have a more nested structure.

Here is a working jsfiddle! Give it a try.

maxarndt
  • 560
  • 7
  • 16
  • Wow, great!! Thank you so much... totally solved my issue and it's even much more elegant than my initial approach :-) – Kabalaba Jan 20 '17 at 09:58
1

Give this a shot, instead! :)

$("[class*='button-']").click(function(){
    $(this).toggle();
});
GROVER.
  • 4,071
  • 2
  • 19
  • 66
1

you have to use closure here,

var id = 0;   

data.forEach(function(item, i) {
      id = id+1;
      var bindEvents = function theOutterFunction() {     
        return function() {
        $( ".button-" + id ).click(function() {
        $( ".button-" + id ).toggle();
       }
      }();
      bindEvents();
});
Fanyo SILIADIN
  • 802
  • 5
  • 11
  • There's something messy with the brackets... I get a blank page, but can't find the error here. EDIT: Fixed it. But still doesn't work... mh :( – Kabalaba Jan 19 '17 at 14:51
1

You have some good answers. but it looks like you're missing just how simple this is. What you need to be making use of is jQuery's .on method. You can look at this SO Q&A for a bit more info on setting up dynamic events.

However, in summary, what it means is: "assigning events for dynamic elements to a static parent." Read here for more info on "What is dynamic and static". In short, dynamic means created after the page is loaded.

So in essence, you can use the answer given by Jamie Phan, you just simply need to understand how to implement it.

All you really need is a "static parent". This is an element that already exist in the HTML when the page is loaded. Quite often I, personally, make use of the DOM object, however, it's best practice to have a close parent of with an ID. For example, if your HTML looked like:

<div>
    <h1>Dynamic buttons added below</h1>
    <ul id="divDyno"><!-- Buttons will be added here --></ul>
</div>

Then your static parent would be <div id="divDyno"... which can be selected using the string '#divDyno'. So, your code would look like so:

$('#ulDyno').on('click', '[class*=button-]', function(e) {
    $(this).toggle();
})

The following is a quick example of how to implement these techniques with ease. I've add a few things so you can see it work in full, but I'll try to explain everything in depth.

Modified to simply toggle classes (aka change state) of buttons

/** This will be the event fired when clicking on a "dynamically" created button **/
function button_click_event() {
 // only need use "this", no need for ID.
 // 'this' is the button html element itself
 $(this).toggleClass('black white');
}

/** This event will dynamically create buttons **/
function create_button() {
  // first I get the length of how many buttons exist,
  // simply to add to the button text
 var len = $('ul li').length,
  // then I create a <li> to append to the <ul>
  li = $('<li />').appendTo('ul'),
  // then, of course, I create the <button> and add it to the <li>
  btn = $('<button />').text('Button '+len).addClass('button-'+len).appendTo(li);
 // now we'll give the button a class for color
 btn.addClass(len%2 ? 'black': 'white')
}

/** This will simply show all "toggled" buttons **/
function show_buttons() {
 $('ul button').show();
}
$(function() {
 // As per the previously mentioned example
 // In jQuery, you can set events for a dynamic element by using a static parent.
 $('#ulDyno').on('click', '[class*=button-]', button_click_event)
 
 // In the following case, I'll simply use the DOM for brevity,
 //  but it's still best to use a "static" element with an ID
 // This event is simply for the "Add" button. To "dynamically" create buttons.
 $(document).on('click', '#btnAdd', create_button)// notice i didn't close with a ";"
  // With no close, the return is "$(document)", So I can write more code attached to it.
  // This event will show any "toggled" buttons
  .on('click', '#btnShow', show_buttons);
});
html, body { font-size: 20px; width: 100%; }
html, body, table { height: 100%; margin: 0 auto; padding: 0; text-align: center; }
div { left: 1em; position: fixed; top: 1em; }
ul { margin: 0 auto; padding: 0; }
li { list-style: none; margin: .5em auto; padding: 0; }
button { padding: .5em .8em; }
.black { background-color: #000; color: #fff }
.white { background-color: #fff; color: #000 }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div><button id="btnAdd">Add Buttons</button><button id="btnShow">Show All Buttons</button></div>
<table>
 <tr>
  <td>
   <br />
   <ul id="ulDyno"></ul>
  </td>
 </tr>
</table>
Community
  • 1
  • 1
SpYk3HH
  • 22,272
  • 11
  • 70
  • 81
  • Thank you very much! But still the problem, that my button disappears. I want to change the button to another one. This works with .toggle, because I have two classes of it, one with display:none. So it toggles between these two. But only if I do it manually for every number/id... But with your solution it just disappears instead of changing the state. Do you know what I mean? – Kabalaba Jan 19 '17 at 15:48
  • @Kabalaba honestly ... no. I'm not following what you're saying. Try and walk me thru, step by step, what you're "expecting" to accomplish, and I will do my best to adjust my answer – SpYk3HH Jan 19 '17 at 15:50
  • @Kabalaba ***Changed already, check example, tell me what you think?*** – SpYk3HH Jan 19 '17 at 15:56