According https://github.com/nathanvda/cocoon#link_to_add_association you should be able to pass a function to data-association-insertion-node
I have tried this:
<%= link_to_add_association 'Add Timeslot', f, :timeslots, :data => {'association-insertion-node' => 'get_row()'} %>
And this:
<%= link_to_add_association 'Add Timeslot', f, :timeslots, :data => {'association-insertion-node' => 'get_row'} %>
And this (getting desperate):
<%= link_to_add_association 'Add Timeslot', f, :timeslots, :data => {'association-insertion-node' => 'function get_row(node){var row = "<tr></tr>";$("#table_body").append(row);return row;}'} %>
But none of them work.
Javascript:
function get_row(node){
var row = "<tr></tr>"
$("#table_body").append(row);
return row
}
I am trying to add a tr to a table and then append the nested timeslot form to the tr.
At the moment this is not possible what you are trying to do. When setting the data-association-insertion-method like this, it will just be a string in javascript, and not a reference to a method.
As documented in the README, you have to do the following (assuming you gave your links a class .add-timeslot):
$(document).on('turbolinks:load', function() {
$(".add-timeslot a").
data("association-insertion-method", 'append').
data("association-insertion-node", function(link){
return link.closest('.row').next('.row').find('.sub_tasks_form')
});
});
(the example is almost verbatim copied from documention for demonstration purposes only --you will have to fill in your get_row function)
Related
I'm trying to create a fully manageable website where the user can fill some skills ('css', 'php', 'ruby', you name it). Next to it, they fill how good they think they are with this, in a percentage.
I intend to display the result in graphs but right now I'm stuck with this nested form, I can't make them show up.
So as I said earlier, you can add your skills in a page named settings, so here is how I linked them together:
skill.rb and setting.rb
class Skill < ApplicationRecord
belongs_to :settings, optional: true
end
class Setting < ApplicationRecord
has_many :skills, dependent: :destroy
accepts_nested_attributes_for :skills, allow_destroy: true,
reject_if: proc { |att| att['name'].blank? }
# Other lines...
ApplicationHelper.rb
def link_to_add_row(name, f, association, **args)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize, f: builder)
end
link_to name, '#', class: 'add_fields' + args[:class], data: { id: id, fields: fields.gsub('\n', '') }
end
application.js
$(document).on('turbolinks:load', function() {
$('form').on('click', '.remove_skill', function(event) {
$(this).prev('input[type="hidden"]').val('1');
$(this).closest('div').hide();
return event.preventDefault();
});
$('form').on('click', '.add_fields', function(event) {
let regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$('.skills').append($(this).data('skills').replace(regexp, time));
return event.preventDefault();
});
});
views/settings/_form.html.erb
<!-- Some other fields -->
<table>
<thead>
<tr>
<th></th>
<th>CompƩtence</th>
<th>MaƮtrise</th>
</tr>
</thead>
<tbody class="fields">
<%= fields_for :skills do |builder| %>
<%= render 'skill', f: builder %>
<% end %>
<%= link_to_add_row('Ajouter skill', f, :skills, class: 'add_skill') %>
</tbody>
</table>
<!-- Some other fields -->
**views/settings/_skill.html.erb
<tr>
<td>
<%= f.input_field :_destroy, as: :hidden %>
<%= link_to 'Delete', '#', class: 'remove_record' %>
</td>
<td><%= f.input :name, label: false %></td>
<td><%= f.input :completed, label: false %></td>
<td><%= f.input :due, label: false, as: :string %></td>
</tr>
I followed this video's instruction, and so far when I click on "add skill", I can see my nested form being rendered in my rails console, but that's all.
I think this is just something I didn't see, but I redid the tutorial twice and each time a bit different but nothing shows when i click on "add skill".
Any help is welcomed!
A few things to look at. first, this function:
$('form').on('click', '.add_fields', function(event) {
let regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$('.skills').append($(this).data('skills').replace(regexp, time));
return event.preventDefault();
});
Is looking for an element with a 'skills' class on it and will append the records there. I didn't see an element with it above unless I missed it.
Next, try disabling turbolinks, at least when debugging - I have had problems with that before.
Remove the gem 'turbolinks' line from your Gemfile.
Remove the //= require turbolinks from your app/assets/javascripts/application.js.
Remove the two "data-turbolinks-track" => true hash key/value pairs from your app/views/layouts/application.html.erb.
(from blog.steveklabnik.com/posts/2013-06-25-removing-turbolinks-from-rails-4
After that, throw in a wad of
console.log()
statements in to verify expected values are what you expect, elements exist etc at runtime.
Finally, I have a post about something similar here:
Javascript nested forms for has_many relationships
Which might be of use.
I have this rails helper _fields_answer.html.erb
<fieldset>
<div class="row">
<div class="col-xs-9">
<%= answerf.text_area :content, placeholder: "Answer", class: "form-control" %>
</div>
<%= answerf.hidden_field :question_number, value: qn %>
<div class="col-xs-2 buttonProjDel">
<%= answerf.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields btn btn-danger btn-xs buttonProjDelBut" %>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<% st = Time.now.strftime("%I%M%S%p") %>
<%= answerf.text_field :scale, id: 'slf'+st , type: 'text',
data: {'slider-id' => 'scale',
'slider-min' => '0',
'slider-max' => '10',
'slider-step' => '1',
'slider-value' => '5' } %>
</div>
</div>
<script>
$('<%= '#slf'+st %>').slider()
</script>
</fieldset>
And I render this helper dynamically, but I just can have the slider in the first one. So I tried to had a different Id for each one, but I am not able to do it.
With the code above I always get the same Id, even using the Time.
Why is the time used in id always the same?
There is another way to do this? I want to have a slide for each answer.
Edit:
The code that renders the helper:
In projects.js.coffee
$(document).on 'click', 'form .add_fields', (event) ->
time = new Date().getTime()
regexp = new RegExp($(this).data('id'), 'g')
$(this).before($(this).data('fields').replace(regexp, time))
event.preventDefault()
In application_helper.rb
def link_to_add_fields(name, f, association, locals)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render("fields_" + association.to_s.singularize, answerf: builder, qn: locals[:qn])
end
link_to(name, '#', class: "add_fields " + locals[:class], data: {id: id, fields: fields.gsub("\n", "")})
end
Your view rendering was done within a second! hence the reason you are seeing the same id value for all inputs.
The statement below will have the same value for 60 seconds.
st = Time.now.strftime("%I%M%S%p")
As it appears you want the slider to be on each input, I would recommend using either a data attribute or simply a css class. An example using css class would be:
<div class="row">
<div class="col-xs-12">
<%= answerf.text_field :scale, class: 'has-slider', type: 'text',
data: {'slider-id' => 'scale',
'slider-min' => '0',
'slider-max' => '10',
'slider-step' => '1',
'slider-value' => '5' } %>
</div>
</div>
Say we assign class has-slider, we could then use this class selector and execute slider() on the matched elements in javascript as:
# app/assets/javascripts/input_slider.js.coffee
$ ->
# Execute slider on all inputs with has-slider css class
$('input.has-slider').slider()
And, you seem to know why you have slider only on the first input; This is because all your inputs have same id value and DOM selection retrieves the first match. ids need to be unique within a document.
Update:
As you're adding input elements within the dom after page load, the $('input.has-slider').slider() call made on app/assets/javscripts/input_slider.js.coffee would not work. It would only work for elements already present in the DOM. In order to make it work for elements added after DOM load, you can use jQuery on() method.
You could trigger some custom event and call slider() method as follows:
# app/assets/javascripts/projects.js.coffee
$(document).on 'click', 'form .add_fields', (event) ->
...
$(this).before($(this).data('fields').replace(regexp, time)).trigger('show-slider')
..
Then you will listen on the show-slider event and call slider() as:
# app/assets/javascripts/input_slider.js.coffee
$ ->
# Execute slider on all inputs with has-slider css class
$('input.has-slider').slider()
$(document).on 'show-slider', (event) ->
$(input.has-slider').slider()
Hope this clears any confusion.
I'm trying to build a RoR app, with three models:
Games that can be classified in a Sector(called GameSector) and in a subsector (called GameSubsector)
A sector is made up of many subsectors.
a Subsector.
Here are my basic models relationships:
models/game.rb
belongs_to :game_sector, :foreign_key => 'game_sector_id', :counter_cache => true
belongs_to :game_subsector, :foreign_key => 'game_subsector_id',:counter_cache => true
I use Active Admin to input the Games, Sectors or subsectors information.
I have a very basic form when I create a game and I'd just like to make the second select drop down (game_subsector) adjust on the choice of the first select (gamesector) so that I don't the the whole (very long) list of game_subsectors but only those that belong to the game_sector I choose.
After dozens of tests and techniques tried but failing, I've finally used this dev's advice that appeared relevant to me: http://samuelmullen.com/2011/02/dynamic-dropdowns-with-rails-jquery-and-ajax/.
But it still does not work.
Here is the form on Active Admin which is located on admin/game.rb
ActiveAdmin.register Game do
menu :parent => "Campaigns", :priority => 1
controller do
with_role :admin_user
def game_subsectors_by_game_sector
if params[:id].present?
#game_subsectors = GameSector.find(params[:id]).game_subsectors
else
#game_subsectors = []
end
respond_to do |format|
format.js
end
end
end
form do |f|
f.inputs "Details" do
f.input :name
f.input :game_sector_id,
:label => "Select industry:",
:as => :select, :collection => GameSector.all(:order => :name),
:input_html => { :rel => "/game_sectors/game_subsectors_by_game_sector" }
f.input :game_subsector_id, :as => :select, :collection => GameSubsector.all(:order => :name)
f.actions
end
I feel the javascript is even maybe not fired.
The jquery I use is located on app/assets/javascript/admin/active_admin.js (I changed config so it loads this javascript when loading active admin pages)
jQuery.ajaxSetup({
'beforeSend': function(xhr) { xhr.setRequestHeader("Accept", "text/javascript"); }
});
$.fn.subSelectWithAjax = function() {
var that = this;
this.change(function() {
$.post(that.attr('rel'), {id: that.val()}, null, "script");
});
};
$("#game_game_sector_id").subSelectWithAjax(); //it it found in my view???
Finally I created a view as this expert adviced: in app/views/layout/ game_subsectors_by_game_sector.js.erb
$("#game_game_subsector_id").html('<%= options_for_select(#game_subsectors.map {|sc| [sc.name, sc.id]}).gsub(/n/, '') %>');
I'm not sure I have out it in the right place though...
What you need is:
Inspect with your web browser console your selects, and use a CSS selector to create a jQuery object for the sector select, something like:
$('#sector_select')
Append to this object a handler, so when it changes AJAX request is fired:
$('#sector_select').change(function(){
$.ajax('/subsectors/for_select', {sector_id: $(this).val()})
.done(function(response){ // 3. populate subsector select
$('#subsector_select').html(response);
});
});
See 3 in code, you need to inspect to get the right CSS selector. Be sure you are getting the expected response in the Network tab of your web browser inspector(if using Chrome).
You need a controller that answers in /subsectors/for_select, in the file app/controllers/subsectors_controller.rb:
class SubsectorsController < ApplicationController
def for_select
#subsectors = Subsector.where sector_id: params[:sector_id]
end
end
You need a view that returns the options to be populated app/views/subsectors/for_select.html.erb:
<% #subsectors.each do |ss| %>
<option value="<%= ss.id %>"><%= ss.name %></option>
<% end %>
You need a route:
get '/subsectors/for_select', to: 'subsectors#for_select'
I have a select tag which populates list of department names, When I select a value from drop down, I need to display an edit link below (link_to) and append the selected value of dropdown as id params.(I am not using form for this single select tag since I dont need to save value in my databse). How this could be possible. Please help. I am using rails2.3
I tried like the below but it didn't work.
Select A Dept
<%=select :select_dept, :dept, #dept.map{|dept| [dept.full_name, dept.id]},{:prompt => "#{t('select_a_batch')}"} %>
<%= link_to "Display", {:controller => "user", :action => "display_value", :id => $('#select_dept').val() } ,:class => "button" %>
Gopal is on the right track.
Give the link an id so you can pick it out
<%= link_to 'Display", {:controller ...}, :class => 'button', :id => 'display_link' %>
Hide it with CSS by default
#display_link { display:none; }
#display_link.showing { display:block; }
Then in javascript, do something like
$('#select_dept').on('change', function(ev) {
var deptId = $(this).find(':selected').val();
var newPath = '/users/' + deptId + '/display_value';
$('#display_link').attr('href', newPath);
$('#display_link').addClass('showing');
});
This will not set things up on page load, but you could run the same function you've passed as the change callback on page load to set things up (assuming one of the items might be selected on load).
I have a Rails application that in the erb code, I use a select box. What I would like to do is reload the page passing the sort parameter. My controller already handles it, but I don't know how to reload the page with the selected value from my select box. Here is my code:
<% #options = {:latest => 'lastest' , :alphabetical => 'alphabetical', :pricelow => 'price-low', :pricehigh =>'pricehigh'} %>
<%= select_tag 'sort[]', options_for_select(#options), :include_blank => true,:onchange => "location.reload('location?sort='+this.value)"%>
Have you considered using an ajax call on your list box? If you have a method on your controller that returns just the sorted list, based on sort parameter, then you could do:
<% #options = {:latest => 'lastest' , :alphabetical => 'alphabetical', :pricelow => 'price-low', :pricehigh =>'pricehigh'} %>
<%= select_tag 'sort[]', options_for_select(#options), :include_blank => true,:onchange => remote_function(:url => {:controller => 'your_controller', :action => 'list_sort_method'}, :with => "'sort='+this.value", :update => "div_containing_list") %>
If you don't want to use AJAX, then put a form_tag around your code.
Take a look at the Redmine source code on http://redmine.rubyforge.org/svn/trunk. The UsersController does something similar - there's a combo box that allows a filter. Selecting the combo reloads the page.