I'm using Rails and I've got a table made up off div's. I want users to be able to click on a table cell and have a menu (in the form of another div row) slide out underneath it. With a second click on the cell the menu should slide back up.
There should be 2 different menu's / click actions per row. I would like to add/remove a div below the clicked action. I've tried working with a table but the div's seem to work better. I just don't really know how to render the partial correctly. my code:
js:
$(document).ready(function () {
openBuySliders = [];
openSellSliders = [];
function openSlider(parent, actionType) {
$( *some partial file* ).insertAfter( parent );
}
function closeSlider() {
// remove the slider
}
$("div[buy-stocks]").click(function() {
var parent = $(event.target).parent()
if ($.inArray(cellID, openBuySliders) == -1) {
openBuySliders.push(cellID);
openSlider(parent, "buy");
}else {
var index = openBuySliders.indexOf(cellID);
openBuySliders.splice(index, 1);
closeSlider(parent);
}
})
$("div[sell-stocks]").click(function() {
var parent = $(event.target).parent()
alert(test);
if ($.inArray(cellID, openSellSliders) == -1) {
openSellSliders.push(cellID);
openSlider(parent, "sell");
}else {
var index = openSellSliders.indexOf(cellID);
openSellSliders.splice(index, 1);
closeSlider(parent);
}
})
});
my html:
<div class="rTable">
<div class="rTableRow">
<div class="rTableHead"><strong>Company</strong></div>
<div class="rTableHead"><strong>Stocks available</strong></div>
<div class="rTableHead"><strong>Stocks owned</strong></div>
</div>
<% current_game.companies.each do |company|%>
<div class="rTableRow" row-id="<%= company.id%>">
<div class="rTableCell"> <%= company.name %> </div>
<div class="rTableCell" buy-stocks="<%= game_player_view_path%>"> <%= company.stocks.size %> </div>
<div class="rTableCell" sell-stocks="<%= game_player_view_path %>"> <%= #player.stocks.where(company_id: company.id).size %> </div>
</div>
<% end %>
</div>
my controller:
def show
respond_to do |format|
format.html
format.js { render :nothing => true }
end
end
I'm trying to render it using jquery insert after but this might not be the smartest solution. I'm really struggling with the JS in the app so any help is appreciated.
I would suggest something like this:
HTML:
<table>
<tr>
<td>
<div class='click-me'> Content </div>
<div class='menu' style='display:none'> Hidden </div>
</td>
</tr>
</table>
JS:
$(document).ready(function() {
$('.click-me').click(function(e) {
var target = $(e.target);
target.parent().find('.menu').toggle();
});
});
Related
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
I've been trying this for hours but I am stumped.
I have a kind of "shopping list" node.js app where you can tick off items as bought. I want the bought items to be styled green or smth. It is passing a mongoose obj to the client side along a route.
Server side:
router.get("/:id", function(req, res){
//find the list with provided ID
List.findById(req.params.id).populate("listItems").exec(function(err, foundList){
if(err){
console.log(err);
} else {
//render show template with that list
res.render("lists/show", {list: foundList});
The foundList obj basically has a structure of (not valid code, just so u can get an idea):
List {
name: String,
listItems: [{
text: String,
bought: Boolean
}]
On the client side I am using a forEach in ejs to loop through the listItems and display a html element for each item:
<% list.listItems.forEach(function(listItem){ %>
<div class="card">
<div class="card list">
..listItem name here
</div>
</div>
<% }) %>
I want to basically make it so that when an element is checked off and listItem.bought == true, the card list element is green, and when lisItem.bought == false, it's just white.
I've got it working with following code, however if one occurrence of the forEach is bought = true, all .card elements turn green. I want it so that only the element in question is effected.
<% list.listItems.forEach(function(listItem){ %>
<% if(listItem.bought === true){ %>
<script>
$(document).ready(function(){
(".card").css("background-color","green");
});
</script>
<% } else { %>
<script>
$(document).ready(function(){
(".card").css("background-color","white");
});
</script>
<% } %>
<div class="card">
<div class="card list">
....
Question: How do I target 1 occurrence of a forEach from server side data in ejs, and add a class/style to it. E.g. if there is 2 items on the list, 1 is bought and one not, one should be green and one white. Currently they both go green.
Thanks!
I don't think you need jQuery for this. You can just add the background color like this:
<% list.listItems.forEach(function (listItem) { %>
<div class="card" style="background-color: <%= listItem.bought ? 'green' : 'white' %>">
<div class="card list">
...
</div>
</div>
<% }); %>
If you want to use jQuery you probably need do add ids to the cards and use them to change the backgrounds.
I am partially rendering data from an endpoint in a list using underscore, each list item has a link to "learn more...". Clicking on that link opens up a text modal/lightbox that shows the rest of the info for that particular element. I would like to add prev and next arrows to see the additional info on the items on the list, without having to close the modal and click on the next item.
I am thinking the way to approach this would be to add a class of "current" to my selected element, and remove/assign this class to each element as needed. But I am stuck thinking how to go about this... (newbie here, be kind).
HTML
<script type="text/template" id="event-template">
<div class="event row no-gutter">
<div class="col-md-12 info">
<div class="col-md-3">
<p class="day"><%= day %></p>
</div>
<div class="col-md-9">
<%= month %> at <%= time %>, <%= storename %> <br> <%= city %> <%= state %>
<a class="show-panel" data-id=<%=entry_id%> href="#_"> Learn More...</a>
</div>
<div class="lightbox-panel" id="lightbox-panel-<%=entry_id%>">
<h2><%= storename %></h2>
<p><%= month %>, <%= desc %></p>
<p align="center"><a class="close-panel" href="#_">Close window</a></p>
<div class="col-md-10" id="prev">Previous</div>
<div class="col-md-2" id="next">Next</div>
</div>
</div>
</div>
</script>
JS
// Open lightbox
$("#events-placeholder").on("click", ".show-panel", function(e) {
var entry_id = $(this).attr("data-id");
$("#lightbox-panel-"+entry_id).fadeIn(300);
$("body").css("background-color", "black");
});
//Close lightbox
$("#events-placeholder").on("click", "#close-panel", function(e) {
$(".lightbox-panel").fadeOut(300);
$("body").css("background-color", "white");
});
// Prev Info
$(".events-placeholder").on("click", "#prev", function(e) {
// ???
var current = $(this).attr("data-id");
var previous = current - 1;
$("#lightbox-panel-"+entry_id-1).fadeIn(300);
});
// Next Info
$("#events-placeholder").on("click", "#next", function(e) {
// ???
});
I am working on a dynamic form input display where if the users clicks something to show "advanced options" in the form, the input vectors will be displayed, but otherwise (the default) they will not be shown. I have the following pieces in my form partial:
UPDATED 1x:
<div class="form-inputs">
<%= f.input :message, label: 'Write message'%>
</div>
<div class="form-inputs">
<%= f.check_box :advanced, {}, :id => "advancedbox" %>
</div>
<div class="form-inputs" id="advancedopts" style="display:none;">
<%= f.input :startdatetime, label: 'Specify', :as => :datetime_picker %>
<%= f.input :expirationdatetime, label: 'Specify', :as => :datetime_picker %>
</div>
And the JS in the head of the form partial:
UPDATED 1x:
<head><script type="text/javascript">
var checkbox = document.getElementById('advancedbox');
checkbox.onchange = function() {
if (checkbox.checked) {
document.getElementById("advancedopts").style.display = "block;";
} else {
document.getElementById("advancedopts").style.display = "none;";
}
}
</script></head>
I took the inspiration for this from the following post: show rest of a form if a checkbox is ckecked in ruby on rails
But I cannot get it to work: the checkbox shows, but clicking it on or off does not show my advanced form inputs. Can anyone help me debug?
Thanks!!
Your problem is that there is no event being listened for. In the example you linked, checkbox.onchange is an event that triggers a function (action) that displays the div. As yours is all namespaced within a function with no event to fire it, nothing happens as it is not evaluated when the state of your checkbox changes.
So if you move the line
var checkbox = document.getElementById('advancedbox');
outside your show function and then key the onchange event to that variable as in the example you linked, it should work.
EDIT: jQuery solution...
$(document).ready(function(){
$("#advancedbox").change(function(){
if( $(this).is(':checked') ){
$('#advancedopts').show(); // you could instead animate using .fadeIn() or .slideDown() if that was preferable
} else {
$('#advancedopts').hide(); // ditto above, using .fadeOut(), .slideUp() etc.
}
});
});
Your problem is here:
<div class="form-inputs" name="advancedopts" style="display:none;">
Changing the name attribute to id should do the trick:
<div class="form-inputs" id="advancedopts" style="display:none;">
Because I do not need to save the user selection, I use the following which works well for my purposes (inspired by changing DIV visibility with JavaScript):
in form partial:
<input type="button" value="Show advanced" onClick="show()">
<div class="form-inputs" id="advancedopts">
... </div>
in application.js:
function show(){
document.getElementById("advancedopts").style.visibility= 'visible' ;
}
in scaffolds.css:
#advancedopts{
visibility:hidden;
}
And works sufficiently for me without the use of a listener. Just in case anyone has a similar simple need and starts off on a track-more-complicated-than-necessary like me.
I have a table of venues and areas where each venue belongs to an area and an area has many venues.
The venues index page is displaying all the venue records as partials and I have a set of checkboxes to filter the venues shown by what area they are in.
I also have a div (map_container) which shows a map .png image of all the areas on the right of the screen.
venue index.html.erb
<div class="map_container">
</div>
<div class="filter_options_container">
<form class="form">
<fieldset class="filter_form_fieldset areas">
<% Area.all.each do |a| %>
<%= check_box_tag 'areas[]', a.id, false, :id => "area-#{a.id}" %>
<label for="area-<%= a.id %>"><p1><%= a.name %></p1></label>
<% end %>
</fieldset>
<div class="form_filter_button">
<p2><input type="submit" value="Filter"/></p2>
</div>
</form>
</div>
<div class="venue_partials_container">
<%= render :partial => 'venue', :collection => #venues %>
<div class="clearall"></div>
</div>
<div class="clearall"></div>
How would it be possible to check whether all the venues being displayed have the same area_id and if they do display a different map image in the map div? So if all venues have area_id of 1 then display map1.png or if they all have an area_id of 2 then display map2.png etc.
Thanks for any help, its much appreciated!
Sounds like you might want the background image to update dynamically when checkboxes are changed by the user? If so, the best bet is to use CSS to set a background-image URL on map_container, based on some other class:
.map_container_map1 {
background-image: url('/images/map1.png')
}
In javascript, attach the class map_container_map1 if all the checkboxes are set for area 1.
You should write a javascript function that's called on docReady, as well as whenever a checkbox is clicked. Something like this, in jQuery:
// docReady
$(function() {
updateMap();
}
$(document).delegate('checkbox[name|="areas"', 'change', function(event) {
updateMap();
});
function updateMap() {
// Loop through all the checkboxes, check their values to see if they're the same
$('checkbox[name|="areas"').each(function() {
...
});
var map = $j('.map_container');
map.removeClass('map_container_area1 map_container_area2');
if (area1)
$j('.map_container').addClass('map_container_area1');
else if (area2)
$j('.map_container').addClass('map_container_area2');
}
This should hopefully get you started.