1

Immediate apologies for the vague title, wasn't really sure how to explain.

Basically I have 10 buttons with 10 different IDs and when I click them I want them to toggle the class of an textarea element. I was wondering if there's some sort of loop to avoid using 10 event listeners to call 10 different functions which toggle the classes of different textareas. Hopefully that makes sense, any help would be greatly appreciated. I'll post the relevent code below.

$(document).ready(function () {
  note1btn.addEventListener("click", displayNote);

  //DISPLAY NOTE
  function displayNote() {
      $("#note1input").toggleClass("hide");
  }
});
.hide {
  visibility: hidden;
  height: 1px !important;
  padding: 0px !important;
  margin: 0px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="note1btn" data-role="button">Note #1</button>
<textarea id="note1input" class="hide" rows="10" cols="50"></textarea>
<button id="note2btn" data-role="button">Note #2</button>
<textarea id="not2input" class="hide" rows="10" cols="50"></textarea>
<button id="note3btn" data-role="button">Note #3</button>
<textarea id="not3input" class="hide" rows="10" cols="50"></textarea>
<button id="note4btn" data-role="button">Note #4</button>
<textarea id="note4input" class="hide" rows="10" cols="50"></textarea>
<button id="note5btn" data-role="button">Note #5</button>
<textarea id="note5input" class="hide" rows="10" cols="50"></textarea>
<button id="note6btn" data-role="button">Note #6</button>
<textarea id="note6input" class="hide" rows="10" cols="50"></textarea>
<button id="note7btn" data-role="button">Note #7</button>
<textarea id="note7input" class="hide" rows="10" cols="50"></textarea>
<button id="note8btn" data-role="button">Note #8</button>
<textarea id="note8input" class="hide" rows="10" cols="50"></textarea>
<button id="note9btn" data-role="button">Note #9</button>
<textarea id="note9input" class="hide" rows="10" cols="50"></textarea>
<button id="note10btn" data-role="button">Note #10</button>
<textarea id="note10input" class="hide" rows="10" cols="50"></textarea>
Moshe Katz
  • 15,992
  • 7
  • 69
  • 116
Xander
  • 991
  • 1
  • 13
  • 32
  • Just going to point out that having multiple class attributes will not work out. The html dom will pick the first class attribute and only apply classes that are within that first attribute. – Sagar Mar 15 '17 at 19:58
  • *Do not edit the **question** to include the **answer**.* It makes it much harder to understand. Accepting​ the answer below is all you need to do. – Moshe Katz Mar 16 '17 at 03:20

5 Answers5

4

Add a class to each button like class="notebutton" then specify an event for the class.

Also you're mixing jQuery and regular DOM calls. Much easier to use just jQuery. In your JS do:

$('.notebutton').click( function(e) {
    e.preventDefault();
    $(this).next().toggleClass("hide");
});

this in the function refers to the item that was clicked. So use next() to get the textarea that follows.

Cfreak
  • 19,191
  • 6
  • 49
  • 60
  • Hi @Cfreak I tried implementing a similar approach and it works in the snippet in my asnwer but doesn't actually work for my project. Would you mind taking a look at this fiddle? https://jsfiddle.net/6n9z7z3m/ – Xander Mar 15 '17 at 19:53
  • @EthanBristow I can't seem to get the fiddle to work because its loading the external JS libraries over http rather than https. (my client blocks that). I couldn't seem to figure out how to change it easily. – Cfreak Mar 15 '17 at 20:02
  • It seems the way I've done it is working when the css .hide has a visibility: hidden but if I change it to display: none it doesn't work :/ Don't suppose you know why? – Xander Mar 15 '17 at 20:13
2

Since you're using jQuery you could attach click event to group of elements using selectors, so in this case you could use attribute selector [] with the start with selector (^) to target all the buttons starts with note then use the $(this)keyword that refer to the current clickedbuttonand target the nexttextareausing.next()` method, your code will be like :

$(document).ready(function() {
    $("body").on('click', '[id^="note"]', function(e) {
        $(this).toggleClass("hide");
    });
});

Or you could give all your button's a common class and use it as selector like :

$(document).ready(function() {
    $("body").on('click', '.notebutton', function(e) {
        $(this).next('textarea').toggleClass("hide");
    });
});

NOTE : If your button's are inside a form they all will act as a submit buttons, so you could prevent the default behavior in the js using e.prevenDefault() or add the type='button' to the HTML code :

$(document).ready(function() {
    $("body").on('click', '[id^="note"]', function(e) {
        e.prevenDefault();

        $(this).next('textarea').toggleClass("hide");
    });
});

Hope this helps.

$(document).ready(function() {
  $("body").on('click', '[id^="note"]', function(e) {
      $(this).next('textarea').toggleClass("hide");
  });
});
.hide {
    display: none;
    height: 1px !important;
    padding: 0px !important;
    margin: 0px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<button id="note1btn" data-role="button">Note #1</button>
<textarea id="note1input" class="hide" rows="10" cols="50"></textarea>
<button id="note2btn" data-role="button">Note #2</button>
<textarea id="not2input" class="hide" rows="10" cols="50"></textarea>
<button id="note3btn" data-role="button">Note #3</button>
<textarea id="not3input" class="hide" rows="10" cols="50"></textarea>
<button id="note4btn" data-role="button">Note #4</button>
<textarea id="note4input" class="hide" rows="10" cols="50"></textarea>
<button id="note5btn" data-role="button">Note #5</button>
<textarea id="note5input" class="hide" rows="10" cols="50"></textarea>
<button id="note6btn" data-role="button">Note #6</button>
<textarea id="note6input" class="hide" rows="10" cols="50"></textarea>
<button id="note7btn" data-role="button">Note #7</button>
<textarea id="note7input" class="hide" rows="10" cols="50"></textarea>
<button id="note8btn" data-role="button">Note #8</button>
<textarea id="note8input" class="hide" rows="10" cols="50"></textarea>
<button id="note9btn" data-role="button">Note #9</button>
<textarea id="note9input" class="hide" rows="10" cols="50"></textarea>
<button id="note10btn" data-role="button">Note #10</button>
<textarea id="note10input" class="hide" rows="10" cols="50"></textarea>
Zakaria Acharki
  • 66,747
  • 15
  • 75
  • 101
  • Hello @Zakaria This method seems to work fine when the css is set to visibility:hidden but if I use display: none it just doesn't work at all. Any ideas on why that might be? thanks – Xander Mar 15 '17 at 20:11
  • Hi @Ethan Sure it will work check my updated snippet replacing the `visibility` by `display`. – Zakaria Acharki Mar 16 '17 at 09:41
2

You can use jQuery's event delegation capabilities to handle an arbitrary number of notes with this syntax:

$(document).on('click', 'selector', eventHandler)

I would suggest that you change your HTML to use classes like .note-button and .note-input instead of using a hard-coded id for each, though.

Finally, a friendly reminder that you can use display: none to hide an element in CSS.


Demo Snippet:

$(document).on('click', '.note-button', function displayNote() {
  $(this).next('.note-input').toggleClass('hide')
})
.hide { display: none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<button class="note-button">Note #1</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #2</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #3</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #4</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #5</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #6</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #7</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #8</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #9</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>

<button class="note-button">Note #10</button>
<textarea class="note-input hide" rows="10" cols="50"></textarea>
gyre
  • 16,369
  • 3
  • 37
  • 47
  • Hi, I updated my question with this code and the snippet is working for me, however when I implemented it into my project it's still not working. The text areas are just not hidden and nothing happens when I click the button either. Any idea what sort of thing might be causing this to happen? thanks @gyre – Xander Mar 15 '17 at 19:36
  • If I add alert("test"); to the onclick function the alert works when I click the button but none of the text areas or changing – Xander Mar 15 '17 at 19:40
  • Did you adjust the HTML the same way I did above? If you open up the developer console what errors are being thrown? – gyre Mar 15 '17 at 19:43
  • No errors on the console as far as I can see. I'm not completely sure where to put the on click function, here's a screenshot of my whole JS file, just with some extra swipe left/swipe right stuff https://gyazo.com/45e9b24ede0511fc14f324077686be10 – Xander Mar 15 '17 at 19:46
  • And yeah I copied the html exactly – Xander Mar 15 '17 at 19:47
  • I accidentally added multiple class attributes... Does fixing the html like I did in the (edited) snippet above do anything? – gyre Mar 15 '17 at 19:54
  • I should've noticed that myself :/ Still doesn't work unfortunatley. What's interesting is that i changed it back from display: none to visibility hidden and then it works for some reason. But doesn't toggle when the .hide has display:none – Xander Mar 15 '17 at 19:58
  • Problem being that the visibility hidden doesn't remove the space it was taking up so thjere's a big gap – Xander Mar 15 '17 at 19:59
  • I checked out your example, and it looks like you need to use `display: none !important;` to overcome issues with CSS selector specificity. – gyre Mar 15 '17 at 20:12
0

I would consider to re-construct the DOM like this

$('.note-input button').click(function(){
  $(this).parent().find('textarea').toggleClass('hide');
});
.hide {
    visibility: hidden;
    height: 1px !important;
    padding: 0px !important;
    margin: 0px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="note-input">
  <button data-role="button">Note #1</button>
  <br> 
  <textarea name="note1" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #2</button>
  <br> 
  <textarea name="note2" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #3</button>
  <br> 
  <textarea name="note3" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #4</button>
  <br> 
  <textarea name="note4" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #5</button>
  <br> 
  <textarea name="note5" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #6</button>
  <br> 
  <textarea name="note6" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #7</button>
  <br> 
  <textarea name="note7" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #8</button>
  <br> 
  <textarea name="note8" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #9</button>
  <br> 
  <textarea name="note9" class="hide" rows="10" cols="50"></textarea>
</div>
<div class="note-input">
  <button data-role="button">Note #10</button>
  <br> 
  <textarea name="note10" class="hide" rows="10" cols="50"></textarea>
</div>
Earthchie
  • 54
  • 5
0

I can think of 2 ways to solve this problem from what i've worked on.

First way:- Use of onclick html attribute

Here basically you will be sending the object dom itself to the function and use jQuery's next() function Here's the link of stackoverflow to better understand this solution.

html

<button id="note1btn" data-role="button" onclick="myFunc(this)">Note #1</button>  
<textarea id="note1text" class="toggle" rows="10" cols="50"></textarea>

script

myFunc(domObj){
   $(this).next().toggleClass('toggle');
}

Second way:- Use of selectors

This answer is already given by many others before my answer (@Zakaria Acharki, @gyre, @Earthchie, and others if m missing anyone out) and so I will just be giving a brief explanation on what this one does.

Basically as per @Zakaria's answer, you are simply attaching an event listener to that particular class/attribute and running the script.

I do not have enough knowledge to argue which one is better over which and for what reasons, and so I will not pursue on which method you should use, however I assure you that both will work the same way.

There is also a third way which I would call it a hack way.

Third method:- Hack way

In this method, you will be passing the ID of the elements to the function e.g:-

Html:-

<button id="note1btn" data-role="button" onclick="myFunc('note1text')">Note #1</button>
<textarea id="note1text" class="hide" rows="10" cols="50"></textarea>

Script

myFunc(id){
    $(id).toggleClass("hide");
}
Community
  • 1
  • 1
Sagar
  • 477
  • 4
  • 15