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.
Related
I have a functional nested form in ruby make with cocoon. The problem is that I am trying to use before-insert and after-insert and it does nothing.
My miew:
<div class="row" id="street_enter_itineraries">
<table>
<div class="street_enter_itineraries" >
<%= f.fields_for :street_enter_itineraries do |builder| %>
<%= render 'street_enter_itinerary_fields', f:builder %>
<% end %>
</div>
</table>
<div class="row">
<%= link_to_add_association "Añadir calle de entrada",f, :street_enter_itineraries, class: 'btn btn-info', data: {association_insertion_node: '.street_enter_itineraries', association_insertion_method: :append} %>
</div>
</div>
My javascript
$(document).ready(function() {
$('#street_enter_itineraries')
.on('cocoon:before-insert', function() {
var allIds= document.getElementsByClassName("tipocalleentradaidentificar");
if(allIds.length > 3){
event.preventDefault();
}
})
.on('cocoon:after-insert', function() {
refreshID();
})
});
I have seen this post: Cocoon add association, how to limit number of associations because of it is what I want to do. I have tried this option too, and console is empty:
$(document).on('cocoon:after-insert', '.content form', function(e) {
console.log('Something');
});
Thanks in advance.
Your jquery selector is wrong, you forgot the # at the start to signify searching for an id. So you wrote $('street_enter_itineraries') and you should write
$('#street_enter_itineraries')
[EDIT] Making the js turbolinks is relatively easy, either make sure it is triggered upon turbolinks:load, instead of using the document ready event (in your case probably the easiest)
$(document).on('turbolinks:load', function(e) {
$('#street_enter_itineraries') ...
})
or register the cocoon handlers on the document with the correct selector:
$(document).on('cocoon:before-insert', '#street_enter_itineraties', function(e) {
// do something here
}
I have an application in which I'm using the gems rails3-jquery-autocomplete and nested_form to suggest existing users to be tagged as contributors to a project entry.
The form view:
<%= f.fields_for :contributors do |contributor|%>
<%= contributor.autocomplete_field :name, autocomplete_user_profile_last_name_projects_path, :update_elements => { :user_id => "#user_id" } %><br>
<%= contributor.hidden_field :user_id %>
<%= contributor.radio_button :contributor_type, 'Colleague' %>
<%= contributor.radio_button :contributor_type, 'Supervisor' %>
<%= contributor.radio_button :contributor_type, 'Client' %>
<%= contributor.link_to_remove "Remove this contributor" %>
<% end %>
<%= f.link_to_add "Add a contributor", :contributors %><br>
I have also overwritten the get_autocomplete_function(parameters) function in order to allow more than one column in my autocomplete, namely the columns first_name and last_name
def get_autocomplete_items(parameters)
items = UserProfile.select("DISTINCT CONCAT_WS(' ', first_name, last_name ) AS full_name, first_name, last_name, id, user_id").where(["CONCAT_WS(' ', first_name, last_name) LIKE ?", "%#{parameters[:term]}%"])
end
I also have the following line in my Projects controller:
autocomplete :user_profile, :last_name, :full => true, :extra_data => [:first_name, :last_name, :user_id ], :display_value => :fullname
With the `fullname' function simply being:
def fullname
"#{first_name} #{last_name}"
end
What I want to do is to get the value of user_id from the autocomplete items and put its value inside the hidden field, but when I check the server the it outputs something like:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"DYQ7iJeqdwMQrprSGn0WNHXY5iXDZLA5pUd3OlYJ2so=", "project"=>{"creator"=>"1", "title"=>"lesdodis", "contributors_attributes"=>{"0"=>{"name"=>"Test User the 1st", "user_id"=>"", "contributor_type"=>"Client", "_destroy"=>"false", "id"=>"21"}, "1"=>{"name"=>"Test User the 2nd", "user_id"=>"", "contributor_type"=>"Supervisor", "_destroy"=>"false", "id"=>"22"}, "1393677266696"=>{"name"=>"", "user_id"=>"", "_destroy"=>"1"}, "1393677267518"=>{"name"=>"", "user_id"=>"", "_destroy"=>"1"}}, "description"=>"asdad", "tag_list"=>"sdads", "link"=>"asdasd", "gallery_attributes"=>{"screenshots_attributes"=>{"0"=>{"description"=>"", "_destroy"=>"false", "id"=>"10"}}, "id"=>"16"}}, "commit"=>"Update", "id"=>"16"}
where the user_id field inside contributors is left blank. I have already tried manually assigning ids to the fields by using contributor.object.id to assign a unique number to the field name with limited success, as the new dynamically added fields do not have object ids. I am using this form for both creating and updating a project entry, so I would like to ask for help in how to make this work regardless of editing the field or adding a new one.
Update:
After a while of searching I finally got it to work by adding this code
<% field_name = "#{contributor.object_name}[user_id]".gsub(/(\])?\[/, "_").chop %>
<%= contributor.autocomplete_field :name, autocomplete_user_profile_last_name_projects_path, :update_elements => { :user_id => "##{field_name}" } %><br>
I hope this helps anyone who might encounter the same problem.
I've been wrestling with a similar problem as well. In your case, my feeling is that the nested_form helpers are generating unique identifiers which are defeating the "#user_id" selector passed to :update_elements.
You might be able to workaround it by hooking into the event streams for each gem and then manually updating the hidden :user_id for the specific contributor in the form. For the dynamically added contributors, possibly something like:
$(document).on('nested:fieldAdded', function(nf_event) {
var ac_input = nf_event.field.find('.ui-autocomplete-input');
ac_input.bind('railsAutocomplete.select', function(ac_event, data) {
$(this).next('input[type=hidden]').val(data.item.id);
});
});
For your contributors generated through existing associations (ie. editing), you can bind to their autocomplete inputs on $(document).ready(). This might at least get you pointed in the right direction.
After a while of searching I finally got it to work by adding this code
<% field_name = "#{contributor.object_name}[user_id]".gsub(/(\])?\[/, "_").chop %>
<%= contributor.autocomplete_field :name, autocomplete_user_profile_last_name_projects_path, :update_elements => { :user_id => "##{field_name}" } %>
I hope this helps anyone who might encounter the same problem.
Basic Problem: I have a line of text, and on hover, I want that text to change to something else. Basic, right? What's tripping me up is that the text in question is stored in a hash in my controller, and I'm looping through it.
Here's a smaller version of my hash in my PagesController:
def team_list
return [ {
name: "Employee 1",
title: "Founder and CEO",
secret_title: "Something Funny",
image: "about-employee-color.jpg",
alt_image: "about-employee-alt.jpg"
},
{
name: "Employee 2",
title: "Not Founder and CEO",
secret_title: "Something Else Funny",
image: "about-employee2-color.jpg",
alt_image: "about-employee2-alt.jpg"
} ]
end
So then in my view (with #team defined as that hash in my PagesController), I'm looping through to create an About Page entry for each person.
<% #team.each do |member| %>
<div class="about-team">
<%= image_tag member[:image], :mouseover => member[:baby_pic] %>
<%= image_tag member[:baby_pic], :style => "display:none;" %>
<h2><%= member[:name] %></h2>
<h4><%= member[:title] %></h4>
<h4 style="display:none;"><%= member[:secret_title] %></h4>
</div>
<% end %>
And I'm trying to see if there's an easy solution just like my image_tag :mouseover to get my titles to change to secret_titles on hover. I tried CSS first, similar to this. But I can't just put that member variable into the CSS since it doesn't exist outside that loop. I imagine JavaScript would be the same way.
h4:hover { content:<%= member[:secret_title] %>; }
Anyway, what I'm hoping for is something like a text_tag that I haven't come across yet that has a similar :mouseover attribute as image_tag.
You can use a JQuery functionality to swap values that you store directly as attributes in the DOM element, which in this case will be the div with class about-team, without really changing rails controller.
Storing values:
<% #team.each do |member| %>
<div class="about-team" member-title="<%= member[:title] %>" secret-title="<%= member[:secret_title] %>">
<%= image_tag member[:image], :mouseover => member[:baby_pic] %>
<%= image_tag member[:baby_pic], :style => "display:none;" %>
<h2><%= member[:name] %></h2>
<h4><%= member[:title] %></h4>
</div>
<% end %>
Swaping values (JQuery defined once):
$('.about-team h4').hover(
function(){ //mouse enter
$(this).html($(this).parent().attr('secret-title'));
},
function(){ //mouse leave
$(this).html($(this).parent().attr('member-title'));
}
);
JQuery hover event as defined in API docs binds 2 handlers to the matched elements, so you can execute your swap logic when mouse is over and out as done in the code above.
JSFIDDLE: http://jsfiddle.net/VmqB7/4/
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.
In TextField of Ruby Code, I want to check whether the specified class is applied or not, on blur event. Please suggest some technique or way. Sample code is given below used by me.
Ruby Code for TextField::
<%=f.text_field :Username, :size=>4, :tabindex=>2, :class=>class_name,
:autocomplete => "off", :onblur=> $$$$$ %>
Suppose class_name : 'changeView' is applied on above textfield, then I have to detect this particular class & replace by another one like 'changeExtraview'. By using any of the javascript, we can replace that class name but suggest if you have any better option.
Thanks
Just a guessed answer...
So your class_name might be contain a value of changeView, and if in the case, you want to replace the changeView class name to changeExtraview, right?
If it is, then the following should be ok:
<%=f.text_field :Username, :size=>4, :tabindex=>2, :class=>class_name.gsub(/changeView/, "changeExtraview"), :autocomplete => "off", :onblur=> $$$$$ %>
========================
Another try:
<%=
f.text_field :Username, :size=>4, :tabindex=>2, :class=>class_name, :autocomplete => "off",
:onblur => "if($(this).hasClass('changeView')) {$(this).removeClass('changeView'); $(this).addClass('changeExtraview')}"
%>
========================
As #Faisal pointed out, using binding in JS side would be better. Although the answer was long time ago, I decided to update the answer again:
<%= f.text_field :Username, :size => 4, :tabindex => 2, :class => class_name, :autocomplete => "off" %>
And in any ways (I use content_for in this example), add the following js code:
<%= content_for :javascripts do %>
<script type="text/javascript">
jQuery(document).ready(function($) {
$("<%= class_name %>").bind("blur", function() {
var $this = $(this);
if ($this.hasClass('changeView')) {
$this.removeClass('changeView');
$this.addClass('changeExtraView');
}
});
});
</script>
<% end %>
Note that the above code requires you have <%= yield :javascripts %> in your layout file,