iamdhunt
iamdhunt

Reputation: 453

Rails jquery select by dynamic value

I'm using Ruby on Rails and I'm trying to hide/show an individual div from a collection of dynamically generated items by using the dynamically generated id which I then insert in a data attribute. This is what I've come up with so far, I think I'm on the right track but can't figure out what I'm missing. Without the if statement it works but shows the hidden div of every item instead of that specific one, and with the if statement, nothing happens.

Link and hidden div

<span class="options" data-ovly=<%= activity.targetable.id %>>
    <i class="fa fa-ellipsis-h"></i>
</span>

<div class="ed_ovly none" data-ovly=<%= activity.targetable.id %>>
    <span class="shu_e">
        <%= link_to "Edit", edit_medium_path(activity.targetable), :title => "Edit", :alt => "Edit", class: '' %>
    </span>
    <span class="shu_d">
        <%= render :partial => "activities/delete", :locals => {:activity => activity} %>
    </span>
</div>

jquery

$('.options').click(function(){
    var $ovly = $(this).attr("data-ovly");

    if ($('.ed_ovly').data("ovly") === $ovly) {
        $('.ed_ovly').toggleClass("none");
    }
});

Upvotes: 0

Views: 246

Answers (1)

Gerry
Gerry

Reputation: 10497

TL;DR

Use id attributes instead of data-ovly in your div tags and avoid the if statement in your script:

html

<span class="options" data-ovly=<%= activity.targetable.id %>>
  <i class="fa fa-ellipsis-h"></i>
</span>

<div class="ed_ovly none" id="<%= activity.targetable.id %>">
  <span class="shu_e">
    <%= link_to "Edit", edit_medium_path(activity.targetable), :title => "Edit", :alt => "Edit", class: '' %>
  </span>
  <span class="shu_d">
    <%= render :partial => "activities/delete", :locals => {:activity => activity} %>
  </span>
</div>

script

$('.options').click(function() {
  var $ovly = $(this).data("ovly");
  $('#' + $ovly).toggleClass("none");
});

Check this snippet:

$(document).ready(function() {
  $('.options').click(function() {
    var $ovly = $(this).data("ovly");
    $('#' + $ovly).toggleClass("none");
  });
});
.none {
  display: none;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<span class="options" data-ovly="1">
    ovly#1 <i class="fa fa-ellipsis-h"></i>
</span>
<br><br>
<span class="options" data-ovly="2">
    ovly#2 <i class="fa fa-ellipsis-h"></i>
</span>

<div class="ed_ovly none" id="1">
  <span class="shu_e">
    <a title="Edit ovly # 1" alt="Edit" href="#">Edit</a>
  </span>
  <span class="shu_d">
    "Your rendered partial for ovly # 1"
  </span>
</div>

<div class="ed_ovly none" id="2">
  <span class="shu_e">
    <a title="Edit ovly # 2" alt="Edit" href="#">Edit</a>
  </span>
  <span class="shu_d">
    "Your rendered partial for ovly # 2"
  </span>
</div>


Explanation

The first problem is in your if statement: You are using === to compare your values, but, since you are getting those values with different methods (attr and data), you are getting different data types.

Look closely at your code (i added a couple of comments):

$('.options').click(function(){
    var $ovly = $(this).attr("data-ovly");      // Returns a string: "1"

    if ($('.ed_ovly').data("ovly") === $ovly)   // Returns a number:  1
    {
        $('.ed_ovly').toggleClass("none");
    }
});

So your if returns false every time (since you are comparing string with number). To fix this, just use the same method1 to get data in both lines, like this:

$('.options').click(function(){
    var $ovly = $(this).data("ovly");           // Returns a number: 1

    if ($('.ed_ovly').data("ovly") === $ovly)   // Returns a number: 1
    {
        $('.ed_ovly').toggleClass("none");
    }
});

Now that you are getting same data types, your if statement will work as expected. But you are not out of the woods yet, there is another issue with your code, look how you are identifying each unique <div>:

if ($('.ed_ovly').data("ovly") === $ovly)
{
    $('.ed_ovly').toggleClass("none");
}

You are using $('.ed_ovly'), that is, you are using the class, and all divs have that class, so with

$('.ed_ovly').data("ovly")

you will always get the value of the first div with class ed_ovly; and in

$('.ed_ovly').toggleClass("none")

you apply toggleClasss("none") to all divs with ed_ovly class (and, as a result, you will hide/show all divs every time).

So, you want to target only one div at a time, and the best way to do it is assigning an id to each div (also dynamically), something like this:

<div class="ed_ovly none" data-ovly="<%= activity.targetable.id %>" id="<%= activity.targetable.id %">
    <!-- Your div code... -->
</div>

And on your script, refer only to the div you want to show/hide using its id, and that can be done by changing $('.ed_ovly') to $('#' + $ovly). Now your script should look like this:

if ($('#' + $ovly).data("ovly") === $ovly) {
    $('#' + $ovly).toggleClass("none");
}

Your script now should be working fine, but something is off: with the changes we made, now the if is not necessary at all! Since we now get a unique id for each div, its safe to delete it:

$('.options').click(function() {
    var $ovly = $(this).data("ovly");
    $('#' + $ovly).toggleClass("none");
});

And, while we are at it, lets get rid also of that unnecessary data tag in your div (i assume you don't need it for anything else):

<div class="ed_ovly none"  id="<%= activity.targetable.id %">
    <!-- Your div code... -->
</div>

Note

1 You could still get away using both methods by comparing them with ==, but i prefer sticking with ===. Check this question for more information.

Upvotes: 1

Related Questions