Multiselect Rails 3, Default Selections with Javascript - 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();

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.

Error when attempting to dynamically change Select2

I am developing an ASP.NET MVC web project. I am currently using select2 for several dropdowns in my project, due to its clean and appealing features. I am also having some problems with select2. I am wanting to create a dropdown on a create page that 'changes' state when another dropdown value is changed. Select2 has a drop-down that offers both the ability to select from the dropdown results OR type your own entry in and save. (see the tagging section on https://select2.github.io/examples.html). I need to be able to turn tags on/off dynamically through javascript AFTER page load. It seems that select2 will only initialize the dropdown and after that, it won't allow dynamic changes.
View Html and Javascript code used to initialize select2 on page load:
<div class="col-md-8">
#Html.ListBoxFor(model => model.modelNum, Model.modelNumList, new { #class= "js-tags" })
</div>
<script type="text/javascript">
$(".js-tags").select2({
placeholder: "Enter Model",
tags: true,
maximumSelectionLength: 1
})
</script>
The above part works great. Select2 is initialized, and follows my settings. After this, my plan is to change the settings of the select2 my destroying and reinitializing the instance, therefore editing the dropdown and turning tags back off. The below javascript method is called when another dropdown is changed.
CODE:
<script type="text/javascript" language="javascript">
function ChangeModelNum(_classID)
{
if(_classID == 1)
{
$(".js-tags").select2("destroy").select2({
placeholder: "Select Model",
tags: false,
maximumSelectionLength: 1
})
}
else
{
$(".js-tags").select2({
placeholder: "Enter Model",
tags: true,
maximumSelectionLength: 1
})
}
}
As you can see, if the user selects the classID as 1, I want to disable tagging for the dropdown. But it simply doesn't work. I also get this error in developer tools:
JavaScript runtime error: Object doesn't support property or method 'select2'
I have made sure there are no double jquery references also. It makes no sense why it has an error with Select2 right after using it perfectly.
ADDITION:
Here is the code that triggers ChangeModelNum:
<div class="col-md-2">
#Html.DropDownListFor(model => model.classnum, Model.classL, "Select Class", new { #onchange = "javascript:ChangeModelNum(this.value);", #class = "form-control" })
</div>
Thanks for any help!
I am not sure, but I think that this particular error could be caused by method chaining
$(".js-tags").select2("destroy").select2...
Try to split it to two separate calls:
$(".js-tags").select2("destroy");
$(".js-tags").select2({
placeholder: "Select Model",
tags: false,
maximumSelectionLength: 1
})

Rails nested attributes with Ckeditor and Cocoon additional rich text editors don't show up

I have a nested attributes form that uses the Ckeditor gem and Simple form to build a form with multiple Rich text editors. One text editor for the Body and one for the Footer.
The relationship is body has many footers
I want to let users add as many footers as they want. To implement this I am using the Cocoon gem.
When a user clicks Add additional footer a form is given the problem is it is not a Ckeditor rich text editor just a regular form.
Form
= f.simple_fields_for :footers do |footer|
= render 'footer_fields', f: footer
.links
= link_to_add_association 'Add Additional Footer', f, :footers
Partial
= f.input :content, label: 'Footer', as: :rich_text_mergefields, input_html: {class: 'span12'}
Is there anyway to add Ckeditor text areas on the fly with Cocoon or any way else?
I ended up doing the following, hope it helps someone in the future.
= f.input :content, label: 'Footer', as: :rich_text_mergefields, input_html: { class: 'span12 footer-field'}
$('#owner').on('cocoon:after-insert', function(_, element) {
id = $(element).index() + '_footer'
text_area = $(element[0]).find('.footer-field').attr('id', id);
config = $(element[0]).find('.footer-field').data('ckeditorOptions');
CKEDITOR.replace(id, config);
});

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.

How to make dynamic dropdown in Rails?

I'm working on a e-commerce project where there will be radio buttons for size selection. I have a dropdown for quantity. I want to make this dropdown dynamic based on stock available for the user selected size. Can anyone tell me how this can be done on Rails? without cluttering my view file with lot of javascript!?
If you are using Rails 3 with prototype (default afaik), you could use the prototype legacy helpers (Link on Github) to add an observer and render a partial view for your dropdown box. You could add an observer like this
<%= observe_field 'element_var_name',
:url => { :action => "another_action_here" },
:update => "div_tag_to_update",
:with => "'selected='+ escape($('element_var_name').value)" %>
Be sure to adjust element_var_name and the action to your situation. div_tag_to_update is the div that will update with the dropdown box. The another_action_here action should render a view like this:
def call_ids_by_type
#element_list = ... # whatever fits for you, like: [[key, value],[key, value]]
render :layout => false
end
In the partial view, you can use the element list to generate the dropdown box:
<%= f.select :var_name, #element_list %>

Categories

Resources