Ruby Rails - optional form input shown conditional on checkbox - javascript

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.

Related

Add a css class using to "this" item in a forEach within EJS/node.js

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.

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

Change the content of 3 divs using javascript and ajax

i'm using rails 4 and javascript and here's my question:
i need to change the values of 3 divs using a button. The values of the divs are generated by a ruby function that came from the controller of that page.
Code:
<% $number= randNumbers %>
<div id="1"><%= $number[0] %></div>
<div id="2"><%= $number[1] %></div>
<div id="3"><%= $number[2] %></div>
<button id="btn1" >Click me!</button>
Here's the ruby method
def randNumbers
n1=rand(1..10)
n2=rand(1..10)
n3=rand(1..10)
return array=[n1,n2,n3]
end
So i need to recall the ruby function to generate new random numbers everytime i click on the button "btn1" without reloading the page.
I know that i have to use ajax or jquery, but i do not really know how to use it with ruby methods.
Thanks for helping :D
You can try the following:
HTML code in View:
Remove the code <% $number= randNumbers %>
Change the code to:
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
<button id="btn1" >Click me!</button>
Javascript Code in View:
$( document ).ready(function() {
call_ajax();
});
$("#btn1").click(function(){
call_ajax();
});
function call_ajax(){
$.ajax({ type:'POST', url:'/controller/get_random', data: {},
success:function(data)
{
$("#1").text(data.arr[0])
$("#2").text(data.arr[1])
$("#3").text(data.arr[2])
},
error:function()
{
// Handle error if Ajax fails
}
});
}
Method in Controller:
def get_random
n1=rand(1..10)
n2=rand(1..10)
n3=rand(1..10)
array=[n1,n2,n3]
render json: {arr: array}
end
Also add routes in routes.rb: post '/controller/get_random'

Rails select_tag - jQuery/JavaScript hide/show on change event

I have the following in a helper:
def cancellation_policies_options_for_elite(room)
options_for_select( [ [t("cancellation_policies.standard"), "standard"], [t("cancellation_policies.moderate"), "moderate"], [t("cancellation_policies.strict"), "strict"], [t("cancellation_policies.elite"), "elite"], [t("cancellation_policies.super_elite"), "super_elite"]] )
end
Which specifies both the text rendered in the select menu but also the value (i.e. standard, moderate etc.)
In my view I then call:
<%= select_tag('selected_cancellation_policy_id', cancellation_policies_options_for_elite(#room), id: 'select-policy', class: 'input-xxlarge') %>
Below this I have the following divs:
<div id="moderate" class="policies" style="display:none">
Moderate policy
</div>
<div id="strict" class="policies" style="display:none">
Strict policy
</div>
<div id="elite" class="policies" style="display:none">
Elite policy
</div>
$("#select-policy").on('change', function() {
alert("It's working!");
$('.policies').hide();
$("#" + $(this).val()).show();
}
I have jQuery and jQuery UI in my project and it is all compiling correctly as many other jQuery elements are working. However I am getting no response at all from this function and completely missing why. Any ideas on this?
This should work:-
$(document).ready(function(){
$('.policies').hide();
});
Then on change of select box do this:-
$(document).on('change', '#select-policy', function() {
alert("It's working!");
$('.policies').not("#" + $(this).val()).hide();
});
Also, in "Elite Policy" div, id should be "super_elite" instead of "elite". Because in select box cancellation elite value is "super_elite". And standard policy div is missing here.

How can I change a background image depending on what results are being displayed?

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.

Categories