I have a form where I need the user to select (with radio buttons) an option that will determine the next form field beneath it. In this case, their post can be a post or a revision of a post. Thus, selecting 'post' will show a title field (to name the post) and selecting 'revision' will show a select list of existing posts to choose from (the title will be inherited).
_form.html.erb
<!--Form inputs-->
<%= f.collection_radio_buttons :is_revision, [[false, 'Post'] ,[true, 'Revision']], :first, :last %>
<%= f.input :revision_id, collection: #originals, :input_html => {:id => 'revision'} %>
<%= f.input :title, :input_html => { :maxlength => '50', :placeholder => 'Title', :id => 'title'} %>
<!--Javascript-->
<script type="text/javascript">
$('input[name="post[is_revision]"]').on("change", function(){
if ( $("#post_is_revision_true").attr("checked")){
$("#title").hide();
$("#revision").show();
}
if ( $("#post_is_revision_false").attr("checked")){
$("#revision").hide();
$("#title").show();
}
});
</script>
I should mention that this works fine when hiding and showing one field, yet when selecting the other radio button nothing changes. I feel the logic is correct (although I'm not the strongest with JS) but I can't seem to get this.
EDIT: I made a few jQuery errors. Also, here is a jsFiddle example
Try this.
$('input[name="post[is_revision"]').change(function() {
var selected = $('input:checked[name="post[is_revision]"]').val();
if(selected == 'revision') {
$('#title').hide();
$('#revision').show();
} else if(selected == 'new_post') {
$('#revision').hide();
$('#title').show();
}
});
Another way to do it, smaller but more confusing:
$('input[name="post[is_revision"]').change(function() {
var is_revision = $('input:checked[name="post[is_revision]"]').val() == "revision";
$('#title').toggle(!is_revision);
$('#revision').toggle(is_revision);
});
If one will always be selected first, you could condense it to this:
$('input[name="post[is_revision"]').change(function() {
$('#title').toggle();
$('#revision').toggle();
});
Or for kicks and giggles and slides:
$('input[name="post[is_revision"]').change(function() {
$('#title').slideToggle();
$('#revision').slideToggle();
});
Comment if you have problems with any.
Related
Not sure if I am asking this question wrong, but I can't seem to find exactly the issue I am faced with.
I have a very basic rails 6 app for a task list. Tasks are either complete or incomplete and the change/update of this is to be done via javascript (the html side works just fine).
Here is my form partial _task.html.erb:
<%= form_with model: task, html: { class: "edit_task", id: "edit_task_#{task.id}" } do |f| %>
<%= f.check_box :complete %>
<%= f.submit "Update" %>
<%= f.label :complete, task.name %>
<%= link_to "(remove)", task, method: :delete, data: {confirm: "Are you sure?"}, remote: true %>
<% end %>
Here is the javascript to submit the form, tasks.js
function submit_update(){
const checkboxes = document.querySelectorAll('.edit_task input[type=checkbox]');
const submitbutton = document.querySelectorAll('.edit_task input[type=submit]');
submitbutton.forEach(button => button.remove());
checkboxes.forEach(checkbox => {
checkbox.addEventListener('click', () => checkbox.parentElement.submit());
});
}
window.addEventListener('turbolinks:load', event => {
submit_update();
document.addEventListener('task_added', event => submit_update());
});
This part works just fine, but once submitted and based on this section of the controller
def update
#task.update!(task_params)
respond_to do |format|
format.html { redirect_to root_url, notice: 'Task successfully updated' }
format.js
end
end
My understanding is together this should launch update.js.erb, which currently looks like
unction update_task() {
const current_task = document.querySelector('#edit_task_<%= #task.id %>');
const complete_tasks = document.querySelector('#complete_tasks');
const incomplete_tasks = document.querySelector('#incomplete_tasks');
<% if #task.complete? %>
complete_tasks.insertAdjacentHTML('beforeend',current_task.innerHTML);
<% else %>
incomplete_tasks.insertAdjacentHTML('beforeend',current_task.innerHTML);
<% end %>
}
update_task();
I have tried changing the above to a single line using an alert call and it still never gets called.
If someone could let me know why update.js.erb is not being called, it would be much appreciated :)
If any additional information is required, please let me know?
EDIT:
On further testing, I have found that if I submit the update via the click of the button, ie remove the submission via javascript, that the update.js.erb is actioned correctly.
So it would seem the focus needs to be on the tasks.js file and how that submits?
What is weird is that when that is included, after the submit the HTML format runs just fine, just not the js format??
After a number of days of trying to get the correct search words I have found the solution and happy to submit for others to find :)
The magic can be found here
The change for my example is as follows --
checkboxes.forEach(checkbox => {
checkbox.addEventListener('click', () => checkbox.parentElement.submit());
});
// becomes
checkboxes.forEach(checkbox => {
checkbox.addEventListener('click', event => {
checkbox.parentElement.dispatchEvent(new Event('submit', {bubbles: true}));
});
});
I have since edited the update.js.erb (does the same thing just a bit cleaner), but it also
needed an additional entry for newly added items to trigger having the entry change positions:
$ cat app/views/tasks/update.js.erb
function update_task() {
const current_task = document.querySelector('#edit_task_<%= #task.id %>');
const to_task = document.querySelector('#<%= #task.complete? ? "complete_tasks" : "incomplete_tasks" %>');
// Remove from previous list
current_task.remove();
// Append to the end of new list
to_task.insertAdjacentHTML('beforeend', '<%= j render(#task) %>');
// Advise tasks.js that new entry needs listener added
to_task.dispatchEvent(new Event('task_added', { bubbles: true }));
}
update_task();
Hope others find this useful :)
I'm having trouble accessing and using the value of a checkbox and then select field for forms dynamically added via the Cocoon Gem for Rails. I've read through many SO posts and the official Cocoon documentation and I just can't seem to get it right.
The idea is that after adding a form via Cocoon, there are hidden fields that only show up if a specific checkbox is :checked, with one of those fields that being a f.select and upon the selection of that value more fields will either show or hide.
_mortgage_fields.html.erb
...
<%= f.form_group :misc_mortgage do %>
<%= f.check_box :misc_mortgage, label: "Miscellaneous Mortgage" %>
<% end %>
<%= f.select :misc_mortgage_context, [["Assignment", "Assignment"], ["Subordination", "Subordination"], ["Modification", "Modification"]],
{ label: "Miscellaneous Mortgage Type" }, wrapper: { class: 'mtgHidden' }%>
<%= f.text_field :reference_mortgage, class: 'form-control', wrapper: { class: 'mtgHidden' } %>
<%= f.text_field :subordinated_mortgage, class: 'form-control', wrapper: { class: 'Subordination' } %>
<%= f.text_field :modification_amount, class: 'form-control', wrapper: { class: 'Modification' } %>
...
The top level form is wrapped with <div id="mtgForm">..</div>
cocoonoptions.js
$(document.ready(function() {
$('#mtgForm').on('cocoon:after-insert', function(e, misc_checkbox) {
alert('getting there');
$(misc_checkbox).find('input[type=checkbox][id*="+misc_mortgage"]').change(function() {
alert('almost there');
if ($(this).is(':checked'))
alert('there!');
$('.mtgHidden').show();
else
$('.mtgHidden').hide();
});
$(misc_checkbox).find("select[name*='misc_mortgage_context']").change(function() {
var mtg = $(this).val();
if (mtg == "Subordination") {
$('.Subordination').show();
$('.Modification').hide();
}
else if (mtg == "Modification") {
$('.Modification').show();
$('.Subordination').hide();
}
else {
$('.Subordination').hide();
$('.Modification').hide();
}
});
});
The wrapper: { ... } fields are set to display: none by CSS and then shown or hidden according to the above values via JS. This same code works (without the cocoon:after-insert part of course) on a static HTML page for adding a single item without the necessity of adding multiple items at once like Cocoon is beautifully made to do.
I've tried the code above many different ways based on different posts or sites I've found online but I can only seem to get the first test alert to fire. Including misc_checkbox.find('...') without the $(...) wrapper.
Am I going about this the wrong way or is my code just incorrect? Thanks in advance for any and all help!
Update
Of course as soon as I post the question I figured it out. The + in [id*="+misc_mortgage"] was throwing it off and I wasn't loading cocoonoptions.js correctly. Going to leave this question up so maybe it will help someone in the future.
So my code was almost correct. Once I changed
$(misc_checkbox).find('input[type=checkbox][id*="+misc_mortgage"]')
to $(misc_checkbox).find('input[type=checkbox][id*="misc_mortgage"]') and loaded the JS via
<% content_for :javascript do %>
<script type="text/javascript">
</script>
<% end %>
function at the bottom of view, everything worked.
I have a form to create a true/false question. I am trying to have a button to toggle the value of a text_field from true and false. (I really do not care what way it is done, I just want the user to be able to easily change the answer to true or false.
This is what I have, it only toggles one time to false and only works when I click the text field not the button. I am trying to learn javascript, so bear with me...
<%= f.label :content, "Answer" %>
<%= f.text_field :content, :value => 'True', :readonly => true, :class => "d-id", :id => "answer" %>
<%= button_tag "Toggle True/False", :id => "answer", :class => "btn btn-small btn-inverse", :type => "button" %>
<script>
function checkAnswer() {
if ($("#answer").val('False'))
{
$("#answer").val('True');
}
if ($("#answer").val('True'))
{
$("#answer").val('False');
}
}
$(document).ready(function(){
$('#answer').click(function () {
checkAnswer();
});
})
</script>
http://jsfiddle.net/jayblanchard/ene5w/
I cleaned up your syntax some and came up with this -
function checkAnswer() {
var answer = $('#answer').val();
if ('False' == answer) {
$("#answer").val('True');
} else {
$("#answer").val('False');
}
}
Also, you have two elements with the same ID which is not allowed in an HTML page. You'll get wonky results. You could change these to classes.
Changed to a button instead of a link - http://jsfiddle.net/jayblanchard/ene5w/1/
Change the text of the button - http://jsfiddle.net/jayblanchard/ene5w/2/
Try this:
if ($("#answer").val() === 'False') {
$("#answer").val('True');
} else {
$("#answer").val('False');
}
Say I've a time_select in a form like :
<%= f.time_select :rtime, :disabled => true %>
and I've a checkbox in the same form, like :
<%= f.check_box :rtime %>
How do I write a JS/JQuery script that enables the time_select tag when its checked?
===========================================
The solution that worked for me:
===========================================
The time_select tag auto-generated two select fields with auto-generated ids, one for hour and one for mins. I went to the source code of my HTML page and found out the ids of these two auto-generated fields which were "trip_rtime_4i" and "trip_rtime_5i".
So i wrote the javascript for my check_box as follows:
<%= f.check_box :rtime, :onclick => "if(this.checked)
{
document.getElementById('trip_rtime_4i').disabled = false;
document.getElementById('trip_rtime_5i').disabled = false;
}
else
{
document.getElementById('trip_rtime_4i').disabled = true;
document.getElementById('trip_rtime_5i').disabled = true;
} " %>
This enables and disables the time field on checking and unchecking the checkbox.
Hope this helps :)
I've been trying to implement what should be a pretty simple feature, but I'm not having much luck. I have a drop-down menu on my ROR app which prompts the user to Select a Country.
NOTE: The list of Countries is contained in the Constants.rb file (but basically the two available options are: Interantional and United States.)
What I would like to see happen: When a user selects "United States" the div id state_nav (a div containing a drop-down menu with a list of States) would show up... if the user selects International, the state_nav menu would remain hidden.
Here is what I had thus far in terms of code (I'm using HAML)
The javascript is located in the header of the html
:javascript
function showDiv(obj)
{
if(obj[obj.selectedIndex].value == 'United States')
{
document.getElementById('state_div').style.display = 'block';
}
else
{
document.getElementById('state_div').style.display = 'none';
}
}
this is the code located in the body of the html.HAML
.section
%div{:class => "label_leftalign field"}
%p.information
please list the country, state (if applicable), and city where you're located
= f.label :country, "Location"
= f.select :country, COUNTRIES, :onChange => "showDiv(this)", :prompt => true
%div{:class => "label_leftalign field"}
#state_div{:style => "display:none;"}
= f.label :state, " ".html_safe
= f.select :state, STATES, :prompt => true
At present... when I load the page it the State drop-down (#state_div) is hidden, and it remains hidden regardless of what Country is selected.
First I would change :onChange to :onchange. Then throw an alert into your js to see if the JS is at least being called:
:javascript
function showDiv(obj)
{
alert(obj[obj.selectedIndex].value);
if(obj[obj.selectedIndex].value == 'United States')
{
document.getElementById('state_div').style.display = 'block';
}
else
{
document.getElementById('state_div').style.display = 'none';
}
}
UPDATED:
You can change your select to include missing hash param:
.section
%div{:class => "label_leftalign field"}
%p.information
please list the country, state (if applicable), and city where you're located
= f.label :country, "Location"
= f.select :country, COUNTRIES, {}, :onChange => "showDiv(this)", :prompt => true
%div{:class => "label_leftalign field"}
#state_div{:style => "display:none;"}
= f.label :state, " ".html_safe
= f.select :state, STATES, :prompt => true
I tried that on my local and it worked. Make sure that the value of your option field reflects that value that you are asserting in obj[obj.selectedIndex].value.