Rails jquery select by dynamic value - javascript

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");
}
});

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.

Related

Vanilla JS: Reveal only the next element at the same parent group

I am trying to create few tabs - with loop.
Then when you click on the tab's name which is a span, its expand(or hide) the next span, which is below it. The problem is that the function works only in the first created tab from the loop and if you click on the second/third, etc tab - the function triggers only at the first tab.
Was trying with querySelector and nextElementSibling without any success.
Using ejs template, express and vanilla javascript only.
This is the loop/tab.
<div>
<% listedProducts.forEach(function(product) { %>
<div class="col">
<span id="info" class="b-d" onclick="hideReveal()">
<%= product.name %>
</span>
<span>
<img src="<%= product.logo %>" alt="">
<p class="r-d"><%= product.supplierCompany %></p>
<p class="r-d"><%= product.dateListed %></p>
<p class="r-d"><%= product.dateApproved %></p>
<p class="r-d"><%= product.supplierName %></p>
</span>
</div>
<% }); %>
</div>
and the function
function hideReveal() {
var tab = document.getElementById("info");
if (tab.style.display === "none") {
tab.style.display = "block";
} else {
tab.style.display = "none";
}
}
Would like a little help, please. Thank you and have a nice weekend.
in your click handler, pass an event argument, e.g., function clickHandler(evt) then say var thisTab = evt.target.id. This assumes you have an id attribute on the tab(s). Then you can toggle the open/closed class of thisTab's firstElementChild

jiren/filter.js with express and ejs files - conflicts

I'm creating an app with express/sequelize and ejs files.
And now i want to use this fantastic solution of filters by Jiren but this solution is using the same syntax as ejs variables.
When i'm including my template with these variables in the script tag type="text/html" its trigger me an error (which is not defined but appears at the lines of my include). When i change the template to "john do" the page is displaying but my console brings me the "error JSONquery is not defined" (it's maybe two differents errors i'm not sure but JSONquery is a part of the filter.js plugin). I can show you my template here
<script id="artists-template" type="text/html">
<li
class="main__product-list-item"
data-height="<%= height %>"
data-width="<%= width %>"
data-low="<%= yearBegin %>"
data-high="<%= yearEnd %>"
data-name='<%= artist %>'
data-longueur='<%= height %>'
data-largeur='<%= width%>'
>
<figure class="main__product">
<a class="main__product-image-link" href="/name/<%= id %>">
<% if(Images.length !== 0) { %>
<img alt="illustration" src="./img/_thumb<%= Images[0]['adress'] %>.jpg"/>
<% } else { %>
<img alt="illustration" src="./img/icon-no-image.svg"/>
<% } %>
</a>
<figcaption class="main__product-description">
<h3>
<a href="/name/<%= id %>">
<span class="product__title">"<%= title %>" - <%= artist %></span>
<span class="product__date">, <span class="product__period"><%= period %></span></span>
</a>
</h3>
<p>
Créé probablement entre <span class="product__low-date"><%= yearBegin %></span> et <span class="product__high-date"><%= yearEnd %></span>
<br/>Hauteur : <span class="product__height"><%= height %></span> cm / Largeur : <span class="product__width"><%= width %></span> cm
<span class="main__product-description-story"><%= description %></span></p>
</figcaption>
</figure>
</li>
</script>
It's the same problem when i inject just one variable like <%= artist %>. Here is how i bind my data:
<% var datas = JSON.stringify(creations) %>
<script>
var data = <%- datas %>;
console.log(data);
</script>
I hope it's just a simple issue and i have to change just a simple character to make it work. At this time I think that the biggest issue is about this "JsonQUERY is not defined" because even if i don't bind my template with datas, the zone which must be filled with the template is actually not bound.
I tried to google the error but i found nothing. If someone have any ideas...thanks.
Here is the website of the filters solution : https://github.com/jiren/filter.js
Hourrayyy !!! I've found the solution, i googled ejs conflicts and found that the point is to change the plug-in syntax: if you encounter the same problem try to change those lines :
var templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
to these
var templateSettings = {
interpolate: /\{\{(.+?)\}\}/g,
escape: /\{\{\-(.+?)\}\}/g,
evaluate: /\{\%(.+?)\%\}/g
};
now i just have to use this syntax : {{ variable }} and its working properly !

Open Semantic UI Calendar within a loop

I need to open Semantic-UI-Calendar within a loop but nothing works, which it should. The logic is, when I click data-id="expensecal", it should give me the id which is expense_date2 or expense_date1 but instead it give me the id of the input:
Rails View:
#---Loop----#
<div class="required field">
<label>Claim date</label>
<div class="ui calendar" data-id="expensecal" id="expense_date<%= contract.id %>">
<div class="ui input left icon">
<i class="calendar icon"></i>
<%= f.text_field :date, id: "expense_date_input", placeholder: "Expense date" %>
</div>
</div>
</div>
JavaScript:
$( "[data-id=expensecal]" ).click(function(e) {
e.preventDefault();
let id = '#' + e.target.id;
console.log(id); // Shows the field input id. Why?
$(id).calendar({
type: 'date'
});
});
I use this method to open up a semantic modal in a loop and it works ok but not sure why not with the calendar.
Initialize all the elements at page ready using a class, remove the click event
Try using the following code:
$('.ui.calendar').calendar({
type: 'date'
});
demo:https://jsbin.com/kenaqiyuqe/1/edit?html,js,output

List.js is returning wrong results

I'm using List.js for the first time. I really liked it, and in the moment I am using it together with rails 4.2 to create a Pokémon team creator tool.
I am also using jQuery 1.11.3 as the JavaScript library for rails.
I have this right now:
It's coded like this:
<script>
var options = {
valueNames: ['name']
};
var userList = new List('pokemons', options);
</script>
<div id="pokemons">
<input class="search form-control" placeholder="Search" />
<ul class="list" style="list-style: none; padding:0; margin:0;">
<% PokemonDefault.where(forme: nil).each do |pokemon| %>
<li>
<div class="name">
<%=image_tag 'miniaturePokemon/'+pokemon.code+'.png' %>
<%=pokemon.name %>
</div>
</li>
<% end %>
</ul>
</div>
It gets all pokémon from PokemonDefaults table, and shows their image and name.
However, List.js is acting weird when I type stuff like 'baa':
As you can see, any of this pokémon has "baa" in their name.
What is happening?
I would assume that List is getting confused because you have an img tag in your div. Try rendering your html like:
<li>
<%=image_tag 'miniaturePokemon/'+pokemon.code+'.png' %>
<span class="name"><%=pokemon.name %></span>
</li>

from underscore template to mustache.js

I would like to change from underscore template to mustache.js.
Since in mustache.js there are no if statements how can I change this piece of code in order to use mustache.js ?
<% if (done) { %>
<span class="todo-clear">
<a href="#">
Clear <span class="number-done"><%= done %></span>
completed <span class="word-done"><%= done === 1 ? 'item' : 'items' %></span>
</a>
</span>
<% } %>
My solution is:
{{#total}}
<span class="todo-count">{{ total }}
<span class="number">{{ remaining }}</span>
<span class="word"><%= remaining == 1 ? 'item' : 'items' %></span> left.-->
</span>
<span class="hint">
Drag tasks from one list into another and vice versa.
</span>
{{/total}}
It works for total variable, because it could be 0 or more, but I have no idea what is the best way to fix it on remaining variable, which could be 1 or more.
<span class="word"><%= remaining == 1 ? 'item' : 'items' %></span> left.</span>
It should be something like that:
<span class="word">
{{#remaining}} 'items' {{/remaining}}
{{^remaining}} 'item' {{/remaining}}
</span>
It does not work because remaining could be 1 or more.
In your view you could make something like this:
Mustache.render(yourTemplate, {
remaining: items.length > 1 ? true : false
}
If your just moving to a new templating framework, I would recommend using handlebars.js. This has support for if statements as follows:
{{#if total}}
<span>something</span>
{{else}}
<span>something else</span>
{{/if}}

Categories