I have a #course form that belongs_to a lesson, and each lesson has_many gradable_items. The lesson_id is selected via a drop menu. When the user changes the lesson select, the nested inputs representing each gradable_item must be updated. This is doable with a page refresh and passing the lesson_id as url param...so, that that lessons gradable_items exist as nested inputs, where they can then be graded (and saved as graded_items). But, seems AJAX is perfect for this.
The code below is not working...and I'm wondering what I'm missing.
course_lesson_id - the select menu where the lesson is chosen
"/gradable_items_input?lesson=#{el.val()}" - the url to the gradable_items_inputs.js.erb template that ajax should inject into the view where the function call was originated.
gradable_items_container - is where AJAX should inject the code returned from the template
The alert() triggers as expected, and the class is added but not removed...since I never get success.
What I am expecting to occur is this:
The select menu is changed, this triggers the function. The function grabs the id of the selected item in the lesson_id menu and then goes to the gradable_items_inputs url using the lesson_id as a url param. When this template is accessed it queries the db in the Course controller using the gradable_items_inputs action. This query uses url param for the lesson_id to filter records and populate the gradable_items_inputs.js.erb file. Then, when success...AJAX puts the code from the gradable_items_inputs template inside the div with id #gradable_items_container.
Is my thought process here flawed? I guess the answer must be yes...since it is not working.
jQuery ->
el = $("#course_lesson_id")
el.on "change", ->
$.ajax "/gradable_items_inputs?lesson=#{el.val()}",
beforeSend: ->
$("#ajax_tell").addClass "is-fetching"
success: (response) ->
$("#gradable_items_container").html(response)
complete: (response) ->
$("#ajax_tell").removeClass "is-fetching"
error: ->
$("#{ajax_tell}").html "<p>ERROR</p>"
timeout: 3000
alert "test"
The gradable_items_inputs.js.erb file:
$('#gradable_items_container').html('
<% #gradable_items.each do |gradable_item| %>
<%= f.simple_fields_for :graded_items do |graded_item| %>
<p>
<%= gradable_item.name %>
<%= graded_item.input :gradable_item_id, input_html: { value: gradable_item.id, }, as: :hidden %>
<%= graded_item.input :grade, collection: gradescales(#course), label: false %>
</p>
<% end %>
<% end %>
');
courses_controller.rb
def gradable_items_inputs
#lesson = Lesson.find(params[:lesson])
respond_to do |format|
format.js { }
end
end
Try adding
dataType:'script'
To the Ajax call params. This will ensure that the request format is js.
The best way to debug an Ajax call is to monitor it from both sides. Look at your rails server log to see how the request is received and the use your browser network inspector to see the response.
it seems you haven't created the routes for gradable_item_inputs.
check routes.rb, must have the following code:
resources :courses do
collection do
get gradable_item_inputs
end
end
Related
I'm not even sure where to start here, so if anyone can even just point me in a potential direction that would be helpful.
I have a form in my Rails app with two select inputs.
Here's the independent select
<%= collection_select(:pass, :route_id, Route.all, :id, :name) %>
Here's the dependent select
<%= collection_select(:pass, :afternoon_trip, Trip.all, :id, :departure) %>
Right now each Route (from the independent select) has a number of trips associated with it. The Trip (dependent) select shows all trips as options.
I want to only show in the Trip select only the trips that belong to the selected route. Any thoughts on how to do this?
I also want to change the trip options when someone changes their route selection, but this is a secondary issue.
Thank you!
I think you'd want to tackle this one with some ajax. Get the selected option's id, send that to your controller, and render a new menu based on the data the controller sends back. Pseudo code and coffeescript might look like:
# javascript
selectMenu = $('menu selectors')
selectMenu.mouseUp ->
selectedId = // get menu's selected id
$.ajax "path/to/populate_dependant?selected_id=" + selectedId
# controller
def populate_dependant
id = params[:selected_id]
#collection = Model.where(attribute: id)
respond_to do |format|
format.js {}
end
end
# populate_dependant.js.erb
// write javascript to append the following to your form:
<%= f.label :model %>
<%= f.collection_select :model_id, #collection, :id, :attribute_name, :prompt => "Select something" %>
The mouseUp event does not work in steel's answer and it is not clear how to reload the page. The following worked for me. Assume the page where the menu is located is the show action of the trips controller.
The coffee script is
selectMenu = $('#route_select')
selectMenu.change ->
selectedID = $('#route_select :selected').text()
$.ajax "/trips/populate_dependant?selected_id=" + selectedId
Change the populate_dependant to
def populate_dependant
id = params[:selected_id]
session[:collection] = Model.where(attribute: id)
respond_to :js
render :populate_dependant
end
This stores the collection in the session. Then create a new coffee script page in the views for the controller.
#app/views/trips/populate_dependent.coffee.erb
window.location.reload();
This reloads the original page. Then add the following to the show action
def show
...
#collection = session[:collection]
...
end
This works very quickly if using turbolinks.
URL : /evaluations
I have made a form to select a specific item (a period)
class EvaluationsController < ApplicationController
def index
#periods = Period.all
end
My form :
<% form_for XXXXX do %>
<%= collection_select(:period, :period_id, #periods, :id, :fullname) %>
<%= submit_tag("Valider") %>
<% end %>
I would like the form to go to /evaluations/3 when submited (if the selected period is 3).
When I go manually to /evaluations/3 it works like a charm but I really don't know how to write the form_for to go the right url by submitting the form.
Simple way
Submit period ID to process data, and then redirect to action, which handles
evaluations/:id with :id as parameters.
redirect_to <youraction>(:period => #id)
This should do the trick.
Not so simple way
If you want to change something dynamically on your page after data was submitted - call method and respond with javascript
respond_to do |format|
format.js
end
In javascript response you can put whatever you want - simple redirects or script, which will change page dynamically. It's up to you.
Hope it helps.
you need to use some javascript to update the action of the form
$('#period_period_id').change(function() {
$('form').attr('action', '/evaluations/' + this.value);
})
I have a form for payments like this:
<%= f.label :invoice_id %>
<%= f.select(:invoice_id, current_user.outstanding_invoices_collection) %>
<%= f.label :amount %>
<%= f.text_field :amount %>
I wonder if there's a way to populate the value of the amount text field somehow, e.g. with the open balance of the associated invoice?
In my Invoice model have this function:
def balance
payments.map(&:amount).sum - total
end
How can this be done?
Im assuming you want to populate the text box based on the selection of a invoice from dropdown. In that case
The idea is
You need to make a ajax call onchange of the invoice dropdown.
That ajax response should update the value of the text box.
And with rails-3 i think its recommended to do this in unrobustive way. Here is a link you can follow. Start playing with it meanwhile I will try to make something functional. Hope to get a good result again.
Are you looking for how to populate the value only?
Update:
Here is the ajax part
#Application.js or any sutable js file
$(function($) {
$("#your_drop_down_id").change(function() {
#Your the url to your controller action here
$.ajax({url: '/get_amount',
data: 'invoice_id=' + this.value,
dataType: 'script'})
});
});
#in get_amount Action
invoice = Invoice.find(params[:invoice_id]) #Other appropriate logic to get the invoice
#amount = invoice.balance
#get_amount.js.erb
$('#your_text_box_id').val('<%= #amount %>');
#routes.rb
#This part is written following the gist: https://gist.github.com/3889180 by #TinTin
resources :payments do
collection do
get 'get_amount'
end
end
Let me know if any part is confusing to you.
In your controller you can assign any value to any field, and it will be displayed in the view.
def new
#payment = new Payment()
#payment.amount = 100
end
If you want some dynamic value, e.g: based on a combobox selection, then do it in javascript or with AJAX.
In rails, what kind of AJAX call would need to be made in order to create and modify resources. Say if i had a resource like this
Man(age: integer, country_from:string, residence:string)
Now how would this be made through an AJAX call (like sending post to my create function, how would parameters be sent in, how would my controllers be setup). Be detailed, my AJAX is very, very, very weak. (right now i have my Man made like rails generate scaffold Man age:int country_from:string ...)
PS
Im using rails 3
So I believe there are two sides to this: the javascript and the controller changes.
In your controller you need to ensure it can return json output (or xml or whatever your chosen ajax-y output is):
def man
# do your work
return_data = {}
# initialize your return data
respond_to do |format|
render :json => return_data.to_json, :layout => nil
end
end
There are many ways to generate your json output but basically you have to make sure it's in a shape that is easily consumed on the view javascript.
I use jQuery and here's the code to execute an ajax call:
function foo(some_param) {
$.ajax({
type: 'GET',
url: "/<controller>/man?FOO=" + some_params,
dataType: 'json',
success: handle_success,
error: handle_errors
}
function handle_success(data) {
# process return JSON. it's a javascript object corresponding to the shape
# of your JSON. If your json was a hash server side, it will be an 'object', etc
}
function handle_error(data) {
# handle error cases based upon failure in the infrastructure, not
# failure cases that you encounter due to input, etc.
}
You can tie the foo function to some button or onclick as you desire.
I am not sure this is complete enough. Let me know if you need more detail, etc.
Rails 3 can help by telling the form that you want it to be "remote" (ajax)
<%= form_for #man, :remote=>true do |f| %>
<div class="field">
<%= f.label :man %>
<%= f.text_field :man %>
</div>
<%= f.submit "Save", :disable_with=>"Saving..."%>
<% end %>
in your Controllers
class MansController < ApplicationController
respond_to :js, :html
def update
#man = Man.find(params[:id])
#man.update_attributes(params[:man])
respond_with #man
end
end
Then, you can have
/app/views/mans/update.js.erb
<% if #man.errors.any? %>
alert("This is javascript code that either renders the form in place of the other form");
<% else %>
alert("success!")
<% end %>
Note: Wherever I say "mans" above, it might be "men"
I am using Ruby on Rails 3 with Prototype/Scriptaculous and I am trying to update a 'div' content after that ActiveRecord values are changed, without reload the page.
In the "edit.html.erb" I have:
...
<div id="test_id">
<%= #account.name.to_s %>
</div>
<%= link_to_function( "Make test" ) do |page|
page.replace_html :test_id, #account.name.to_s
end %>
...
Before clicking on "Make test" I update the '#account.name' value, even via AJAX. Then, clicking on "Make test", the template doesn't changes.
These are steps:
I show the page
I update '#account.name' via AJAX
I click on "Make test"
'div' with 'id="test_id"' doesn't change!
What am I doing wrong?
P.S.: I think that #account is not reloaded in the page, also if his values are changed in the database. If so, what should I do?
I have seen the Railscasts "AJAX with RJS" and I followed an example in that (it is like the my), but it doesn't work for me.
If you have rendered edit.html.erb when the value of #account.name is "George", the HTML will remain the same (with the value "George") until you refresh it. Your call to link_to_function is, on page load, rendering an html link that calls javascript that replaces the inner html of the "test_id" div with 'George'. Unless you replace that HTML, it will always replace the inner html of that div with 'George'.
It's hard to recommend a solution without knowing exactly what you'd like to do...
updated to have more detail:
If you are making an AJAX call that changes the value of the account name on the server to "Fred", and want that change to appear on the page, you should refresh the parts of the page that use that value in that same AJAX call (that same controller action).
Your link_to_function generates HTML like this (if #account.name was 'George' when the page was rendered):
<a onclick="try { Element.update("test_id", "George"); ... >Make test</a>
It is not an ajax call, it is just a link that executes javascript. If you want to make it an ajax call that finds the latest value of the account name and refreshes the test_id div, do something like this:
<%# you need prototype included, but it should probably be in application.rhtml %>
<%= javascript_include_tag "prototype.js" %>
<div id="test_id">
<%= #account.name.to_s %>
</div>
<%= link_to_remote "Make test", :url => { :controller => "account", :action => "change_name" } %>
The 'Make test' link will now perform an AJAX call to the 'change_name' method in the 'account' controller. This method would look something like this:
def change_name
# here you would load the account from the db; I'm cheating
#account = Account.new(:name => "Fred")
render :update do |page|
page.replace_html :test_id, :text => #account.name.to_s
end
end