Autocompletion in a nested form text field - javascript

I am using rails 5 and i want to autocomplete a text field which is in a nested form. The nested form has been generated via cocoon.
When i try to use auto complete function in the parent form it works fine. However it seems like my javascript doesnt work for the nested form.
This is model file of the nested form
class Programline < ApplicationRecord
belongs_to :program, inverse_of: :programlines
belongs_to :exercise
def exercise_name
exercise.try(:exe_desc)
end
def exercise_name=(exe_desc)
self.exercise = Exercise.find_by_exe_desc(exe_desc) if
exe_desc.present?
end
end
This is my text field within the nested form.
<%= f.text_field :exercise_name, data: {autocomplete_source: Exercise.order(:exe_desc).map(&:exe_desc)} ,class: "form-control", placeholder: "Exercise", autofocus: true %>
This is my javascript file.
jQuery
$(function() {
$(document).on("focus","programline_exercise_name", function() {
$('programline_exercise_name').autocomplete({
source: $('programline_exercise_name').data('autocomplete- source')
});
});
})
When i fill the form it works fine, inserts data and builds relationship without any problem. But it does not automatically find the data which is in exercise table.
Thanks for your helps.

You cross-posted this in cocoon issues, so I will replicate my answer to you here.
Your selection filter for jquery seems wrong. You write on("focus","programline_exercise_name" and $('programline_exercise_name') which would go looking for a html-element with that name. Like $('p') will select all paragraphs. I am assuming you want to select an element with id or class programline_exercise_name ? For dynamically added fields you would definitely be using a class, but then your jquery snippet would also be wrong.
So if you add the wanted class-name to the field
<%= f.text_field :exercise_name, data: { autocomplete_source: Exercise.order(:exe_desc).map(&:exe_desc)},
class: "form-control programline_exercise_name",
placeholder: "Exercise",
autofocus: true %>
You would then need something like
$(document).on("focus", ".programline_exercise_name", function() {
var _this = $(this);
_this.autocomplete({
source: _this.data('autocomplete- source')
});
});
Not tested, so let me explain: when the focus event is triggered on any of the text-fields with class .programline_exercise_name, only set the autocomplete for the element that caused the event.

Your JQuery should look as follows (assuming your nested field has id programline_exercise_name) :
$(function() {
$(document).on("focus","#programline_exercise_name", function() {
$('#programline_exercise_name').autocomplete({
source: $('#programline_exercise_name').data('autocomplete- source')
});
});
});

Related

How to update single column using modal on one page based on ajax request

I have page who contains 3 boxes and all of these boxes's data need to update in one db table so I used to update all of them one by one using partial and custom ajax.
View Code:
.col-lg-3.col-md-3.col-sm-6.col-xs-6
.box-bar
h5.prodman Short Description
br
btn.btn-primary.btn-lg
= link_to 'Edit', edit_product_path(#product, field: 'sd'), remote: true
.col-lg-3.col-md-3.col-sm-6.col-xs-6
.box-bar
h5.prodman Long Description
br
btn.btn-primary.btn-lg
= link_to 'Edit', edit_product_path(#product, field: 'ld'), remote: true
.col-lg-3.col-md-3.col-sm-6.col-xs-6
.box-bar
h5.prodman T&Cs (General, Privacy, Fair Usage etc)
br
btn.btn-primary.btn-lg
= link_to 'Edit', edit_product_path(#product, field: 'tc'), remote: true
Upon clicking link_to the modal loads all those content:
edit.js.erb code:
<% field_name, field_title = get_field_name_title(params[:field]) %>
$('#dialog h4').html("<i class=' glyphicon glyphicon-pencil'></i> Update <%= field_title %>");
$('.modal-body').html('<%= j render('terms_field_form',{field_name: field_name}) %>');
$('#dialog').modal("show");
$('#dialog').on('shown.bs.modal', function () {
CKEDITOR.replace('<%= "#{field_name}" %>');
});
$(document).on('click', '.update_terms', function () {
$.ajax({
type: 'PATCH',
dataType: 'script',
url: '<%= product_path(#product) %>',
data: {
"authenticity_token": $('input[name=authenticity_token]').val(),
"product": {"<%= field_name %>": $('.terms_content').val()}
}
});
});
Partial Code:
= text_area_tag "#{field_name}".to_sym, #product.send(field_name), class: 'form-control terms_content', id: field_name
= button_tag 'Submit', class: 'btn btn-primary mg-t-20 mg-b-20 mg-r-10 update_terms'
Dynamic fields (column and titles ) code:
def get_field_name_title(field)
return 'short_description', 'Short Description' if field == 'sd'
return 'long_description', 'Lease Terms' if field == 'ld'
return 'terms_and_conditions', 'T&Cs (General, Privacy, Fair Usage etc)' if field == 'tc'
end
Problem
The boxes contents always remain same. Means, I am updating 'Long Description' and I will update it in db but if I try to update any other box it show the name of that box again ( the previous one I updated ).
I got an impression that on each click and updation the modal stay same and on next click its adding with existing once. And it iterates it to next click. So, click1, next time I clicked2, so click1,click2. then next time i clicked3, so click1,click2,click3. this is the issue.
So, no new fresh event to new click.
Is there any proper way to do it if my process lags any feature?
You are having issues because you haven't fully committed to the single page paradigm. I'm not sure of the interaction with CKEDITOR, but the 3 warning signs I see ...
1) Your update doesn't work, but create does
2) Your code is randomly populating all of the fields with the same data
3) Your code has no unique identifier for the fields in the css/html
You need to uniquely identify the fields which will be altered.
Note: all of this assumes that you are intending to treat each field separately as it's own form - I'm not sure you make a conscious decision about which strategy to use - so I'm just following the lead of the questions you seem to be asking - as I said in the rails/ruby chat - the simplest way is to make it all one form, have a single update button for it and be done
Your div or id for the html code needs to reflect this fact, by being wrapped around those modal fields.
Which will allow you to use to jquery .bind & attach a trigger on just that field to run the update against server.
... example of us setting up a html class/div to anchor the jquery too ...
Old:
.col-lg-3.col-md-3.col-sm-6.col-xs-6
.box-bar
h5.prodman Short Description
br
btn.btn-primary.btn-lg
= link_to 'Edit', edit_product_path(#product, field: 'sd'), remote: true
New with class - (not tested but general idea):
.sd-class # -- note this can be any name, as long as sd/ld/tc aren't the same
.col-lg-3.col-md-3.col-sm-6.col-xs-6
.box-bar
h5.prodman Short Description
br
btn.btn-primary.btn-lg
= link_to 'Edit', edit_product_path(#product, field: 'sd'), remote: true
Next your simply setup an jquery binding based on that anchor - answered thousands of times - Modal updating with jquery.
I'm guessing here - but CKEDITOR should be able to take that modal field that is properly pointed too inside the anchoring div I pointed out to you ... see this answer for how to test and locate an element inside another to feed it the right field.
Note: the other part is that CKEDITOR MIGHT need to be set to nil/initialized each time you call it, to ensure blank or set to the field using the unique class div we setup as an anchor
See this answer for help selecting the right field with jquery
I feel like most of your issue is the code you wrote doesn't explicitly tell CKEDITOR where to find the information it's targeting & it's not reseting after each run. So you might have to initialize CKEDITOR each time - see their forums for help on that one.

Rails nested form dynamic div id

In my Rails App I am using a nested form and in my controller I have a loop which looks like this:
2.times do
practice = #team.practices.build
end
In my nested form I create a select field with the following code:
<%= f.select :day, Practice.days.keys.to_a, {}, {class: 'form-control'} %>
which gets the id: "team_practices_attributes_0_day". This is for the first practice. The second practice shower receives this id: "team_practices_attributes_1_day"
Now I want to use the variable (0, 1) in my other ids for some jQuery. Is there a way to access this number in a form?
I'm a little confused by the context of your 2.times loop (is practice referenced on the form?) Is that where the two selects are built?). So, I'm not sure if you want this on the select helper or in the answers. But a data attribute is an easy way to access data from any element.
You can add data attributes to the a select helper as part of the HTML options.
<%= f.select :day, Practice.days.keys.to_a, {}, {class: 'form-control', data-id: practice.id} %>
And then access them by calling the attribute name after data in jQuery. Note, you might want to add a specific class to query against.
var id = $('.form-control').data("id");

Rails change input type in a form on click

I have a form for creating posts in rails. I made the body optional. I use ckeditor for editing the body details, but it takes some time to load and since the body is optional I don't want to always load it.
I use a normal text_area input type and when a user clicks on it I want to replace that text_area with my cjtext_area field.
I am currently trying that with a jQuery function that works if I pass in some text, but not if I pass in my whole textarea.
This is how my dummy text_area looks like:
<%= f.text_area :body, placeholder: "Enter more optional details...", cols: 25, rows: 3, required: true, id: 'textarea', :onclick=>"replaceField(#{f.cktext_area :body});"%>
This is my jQuery to change the text_area with a value that is passed into the function:
function replaceField(ckeditor)
{
$("#form_body").replaceWith('<div id="form_body">'+ckeditor+'</div>');
}
As I mentioned before, this works if I pass in some text, but not if I pass in the whole f.cktext_area field.
Are there any other ways I could achieve this?

Multiselect Rails 3, Default Selections with Javascript

I have a Rails 3 application where I allow the user to apply tags to their listing. I've read a few stackoverflow threads with similar questions but this one is unique since I am using a frontend framework. I am using the webarch framework: http://www.revox.io/webarch/form_elements.html
If you CTRL + F "Multi Select" you can see the exact element that I am using.
Summary
I use this code to populate tags:
<%= f.collection_select :tag_ids, Tag.all, :id, :name, {:selected => #listing.tags.map(&:id).map(&:to_i)}, { :multiple => true, :style => "width:100%", :id => "multi", :class => "select2-offscreen", :placeholder => "Select Tags." } %>
This works to assign tags, but the tags that have already been saved to a listing do not appear in the dropdown on the edit view. For example, if the a user has tagged their listing as "Jim" and "Lucy", they should see this when they arrive on the edit view.
Framework's JS code
The framework is added to the site. In the JS files, it has the following code:
$(document).ready(function(){
//Dropdown menu - select2 plug-in
$("#source").select2();
//Multiselect - Select2 plug-in
$("#multi").val(["Jim","Lucy"]).select2();
This is excellent starting logic, but obviously I don't want "Jim" "Lucy" manually coded into my dropdowns. How can I override this in js to make it work correctly for the existing tags?
{:selected => #listing.tags.map(&:id).map(&:to_i)}
I just had to go into the plugin's files and change the code to:
$(document).ready(function(){
//Dropdown menu - select2 plug-in
$("#source").select2();
//Multiselect - Select2 plug-in
var multi = $("#multi");
var selected = multi.find("option[selected]").map(function() { return this.value; });
multi.val(selected).select2();

How to make a change event only run one time the event is called for a class

I'm designing a multi dynamic select menus, i.e., I have a menu for brands, after the user select the brand, using JavaScript and AJAX, I will search for the models available from that brand and add them to the second select menu. This process repeats again but this time showing the features of the model selected.
To do this, and because I have many different areas that need the same system, I use a class with the same name in every brand select menu and another one to every model select menu.
<div class='brand_select' id='14'>
<%= f.collection_select :brand, Product.find_all_by_area(14, :group => 'brand'), :brand, :brand, :prompt => 'Choose brand' %>
</div>
<div class='model_select'>
<%= f.collection_select :model, Product.find_all_by_area(14), :model, :model, :prompt => 'Choose model' %>
</div>
<div class='brand_select' id='15'>
<%= f.collection_select :brand, Product.find_all_by_area(15, :group => 'brand'), :brand, :brand, :prompt => 'Choose brand' %>
</div>
<div class='model_select'>
<%= f.collection_select :model, Product.find_all_by_area(15), :model, :model, :prompt => 'Choose model' %>
</div>
And the JavaScript:
$('.brand_select').change(function(event) {
// option selected
var brand=$(event.target).find('option:selected').val();
// if none is selected
if (brand == ''){
$(event.target).parent().parent().find('.modelo_select').hide();
$(event.target).parent().parent().find('.caracteristica').hide();
}
else {
$(event.target).parent().parent().find('.modelo_select').show();
// find id to search on the database
var id=$(event.target).parent().attr('id');
// find the target (id of the object)
var target=$(event.target).attr('id');
$.ajax({
type: "POST",
url: "http://"+location.host+"/model/"+brand+"/"+id+"/"+target,
brand: brand,
id: id,
target: target
});
}
});
$('.model_select').change(function(event) {
// find model selected to search on the database
var model=$(event.target).find('option:selected').val();
// find brand selected to search on the database
var brand=$(event.target).parent().parent().find('.marca_select').find('option:selected').val();
// find id to search on the database
var id=$(event.target).parent().parent().find('.marca_select').attr('id');
// find the target (id of the object)
var target=$(event.target).attr('id');
$.ajax({
type: "POST",
url: "http://"+location.host+"/feature/"+brand+"/"+model+"/"+id+"/"+target,
brand: brand,
model: model,
id: id,
target: target
});
});
This code works but it repeats the event change the same number of times as the classes with that name.
What I want to do is for the function to run only one time every time a change event is called for the class.
I don't know if this is possible with class structure that I have or if I have to associate an id or a class with different names for each area to the function.
I don't see why the event should fire twice because all you're doing with $(selector).change is saying that every time a change event fires on something with that selector you want to handle it. I even ran a quick test to be sure and it doesn't fire more than once.
Can you explain a bit better what the symptom actually is? As in, what actually happens twice? Does everything in your event handler happens twice?
I was thinking that your selectors for the actions you perform on the parents might be a bit too lax ($(event.target).parent().parent()) so if you only want to do something on the container where your event was fired that wouldn't be the best way (but then again I don't know what your end purpose is here).
That for your help, I found out that the problem has nothing to do with Javascript but is instead on the Ruby on Rails.
I was adding on application.html.erb other js files and if you have the //= require_tree on the application.js it adds every js file in the tree, so adding js files on application.html.erb will make them repeat and cause strange behaviors like this one.

Categories

Resources