I am new to Rails and working on a quiz application, and am having trouble implementing the timer properly. When a user creates a new quiz, the controller calculates the time they are given based on the number of questions, 1 minute per question, and this is value is stored in the database. The user is then redirected to the first quiz question and the timer starts. They can choose a multiple choice answer, then click "Next" to go to the next question. The problem is that the page for the next question loads and the timer starts over instead of continuing where it left off on the previous page.
The timer is in javascript. It is implemented in my view as a div:
<%= content_tag "div", class: "timer", data: {time: #time} do %><% end %>
I can access the current time in my .js.coffee file (such as when "Next" is clicked) with
$(".timer").countdown("getTimes")
How can I send this time value to the Rails controller / database since it is a javascript/jQuery object?
Or should I try a different approach altogether?
Thanks!
You can store the value returned by the JS timer code in an hidden html input field and retrieve that value as form variable when the form is submitted.
For more info on hidden inputs: http://webdesign.about.com/od/htmltags/p/input-hidden-tag.htm
As per DevDude's guidance, a hidden input field worked to solve this.
My view has the timer in the "content_tag"
The hidden input is placed in the form.
The submit buttons are given a class of "nav-time" to call in coffeescript.
show.html.erb
<%= content_tag "div", class: "timer", data: {time: #time} do %><% end %>
<%= form_tag . . . %>
.
.
<input type="hidden" name="time-submitted" value="">
.
.
<%= submit_tag "Next", class: "nav-time"%>
<%end%>
The coffeescript updates the value of the hidden field.
timed_test.js.coffee
jQuery ->
$('.nav-time').on 'click', (event) ->
times = $(".timer").countdown("getTimes")
$('input[name="time-submitted"]').val(times)
The time is passed to the controller through the params[time-submitted], and the database is updated. When the next page, is rendered, the time is where it left off on the previous page.
Related
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.
So I'm creating a photo proofing web app for a client. I want him to be able to skim the images on the site and under each image is an 'Approve' button, which he can click and the image border will turn green, signaling it's good for export.
Now my JS/Jquery knowledge is pretty limited, but I know that this might go deeper than just front-end work, because I want to see those changes even after browser is closed, which I think requires a both back-end and front-end solution.
I'm thinking to create a boolean attribute under my image model, and when you click the 'Approve' button, it'll switch the boolean value to true, which will change the css class to turn green. Is there a way rails can detect a boolean value and change the css accordingly? I want to be able to see the changes my client made.
Would appreciate any feedback/advice on my approach, or if there's a better way out there to go about this. Thanks!
first add on your images table an approved column with type boolean
and on your images controller and these action
def approve
#image =Image.find(params[:id])
#image.update_column(:approved,true)
respond_to do |format|
format.js
end
end
in routes add these method
resources :images do
member do
put :approve
end
end
in your html
<div class="image">
<img src="<%=#image.source%>" />
<%= link_to "approve",approve_image_path(#image),:remote=>true,:method=>"PUT",:class=>"approve_me"%>
</div>
in your image.js file add these method
$("body").on("click",".approve_me",function(e){
e.preventDefault();
$(this).parents(".image").find("img).css("border-color","green");
});
I think you are almost there.
Firstly - yes, changing the css with javascript on runtime will immediately change the appearance of dom elements.
On the client side - you want to indicate to the user which images have been selected, but you also need to store the approved value for each element in your submit form.
In Rails it is common to create hidden input elements storing additional data. Given the task at hand - they can store a value of 0/1 - rejected/approved. You can come up with your own convention for naming the image/select values.
Then, in your view, add onclick listeners to your images pointing to a javascript function:
1) checking if the clicked element is already selected,
2) changing the css of the current element,
3) updating the hidden input value for that element.
Here is a dummy demonstration - jsfiddle
Later, you can then get the approved/rejected value from the params in your controller, like (see below).
In case you want to assign a css class when constructing the view and depending on an approved flag value, you could do something like:
<img id="image_<%= image_id %>" src="<%= image_item.path" class="<%= (image_item.approved.to_i == 1) ? 'approved_img' : 'non_appr_img' %>" %>
<input id="image_<%= image_id %>_app_flg" type="hidden" value="<%= image_item.approved %>" />
where image_item is an object properties path and approved (self explanatory), image_id the id of the image object, approved_img and non_appr_img - css classes.
I'm not discussing the back-end for storing the approved flag, as it seems it is out of the scope of the question
EDIT
Brief concerning back-end
Given the you have an images model, extend it to include an approval property (prepare a database migration and edit your model .rb file to include the new columns).
In the view, include all of the hidden inputs inside a form which will be submitted to your controller(for example looping through an array on your images). For example:
<%= form_for :images, :url => {:action => "approve_images"}, :html => {:name => "testForm"} do |f| %>
<!-- TODO do stuff here - eg display images -->
<% #images.each do |imageItem| %>
<%= f.hidden_field "#{imageItem.id}_appproved", {:value => imageItem.approved}%>
<% end %>
<!-- TODO add a submit button -->
<% end %>
*You need to
Here :images is the controller, approve_images is the function in the controller that the form will be submitted to (include in routes), #images is an array with images data (from your model) and that you have prepared in the controller before rendering the view. I assume the images have ids and approved property.
This will yield in your view dom elements like this:
<input id="images_IMAGEID_appproved" name="images[IMAGEID_approved]" type="hidden" value="1" />
After submitting the form, in your controller you will be able to access these values like this:
img_approved = params[:images][IMAGEID+"_approved"]
Finally you can store that value to your database. Good luck! :)
I am omitting a lot of even more basic things, but I think the question is too broad as it is and there are plenty of resource detailing how to create,read,write a model, prepare data for the view etc. If not - please get started with http://guides.rubyonrails.org/getting_started.html
Thanks everyone who helped me answer this question below! I came up with a solution I'm pretty happy about, figured I'd share it hoping it'll help somebody else along the way.
The problem: I was looking for an AJAX solution that could make permanent changes to the data model. I wanted somebody to be able to toggle/highlight certain items on a page, and have those changes saved on the backend so I can view it later.
This required both a front-end ajax solution for the user interface and back-end solution so the ultimate changes will be saved in the data model so when I load up the site later, I can see the changes he made.
My solution (with the help of those who answered below):
Backend - I created a link that when pressed, would toggle the attribute in my model either true/false
Frontend - In order to give the client a real-time feel, I had to set the link to perform ajax requests and change the css accordingly.
My controller:
def approve
#pipe = Pipe.find(params[:id])
respond_to do |format|
if #pipe.toggle!(:approved)
format.html { redirect_to root_url }
format.js
else
format.html { render :index }
end
end
end
My pipes table has an approved:boolean attribute
My approve.js.erb file (I wrapped each pipe in a div using div_for(#pipe):
<% if #pipe.approved? %>
$('div#<%= dom_id(#pipe) %>').children('.flexslider').css('border','4px solid green');
$('div#<%= dom_id(#pipe) %>').children('a').text('un-approve');
<% else %>
$('div#<%= dom_id(#pipe) %>').children('.flexslider').css('border','4px solid white');
$('div#<%= dom_id(#pipe) %>').children('a').text('approve');
<% end %>
My Application Helper:
def approve_text(approvable)
approvable.approved? ? 'un-approve' : 'approve'
end
My trigger link (which uses abovementioned helper):
<%= link_to approve_text(pipe), approve_pipe_path(pipe), remote: true, method: 'PUT', class: approve_text(pipe) %>
My routes:
resources :pipes do
member do
put :approve
end
end
Again, thanks for those who helped provide answers. This is a solution I'm pretty happy with. I know it probably could use some help being refactored. If anyone has suggestions, would love to hear about it!
I am trying to change the colour of a row according to a rails database value. Also within the row is a form which is a drop down menu. On changing the selected value in the drop down form I update the changed value to the DB by a form submit and then call a javascript function to change the row colour using the new value through AJAX.
html.erb:
<%= f.select(:status, ["to call","didn't connect","confirmed","rejected"], {:selected => lead.status}, :onchange => %Q[$('#lead_form_#{lead.id}').submit();document.getElementById('lead_row_#{lead.id}').bgcolor=Application.getRowColour("#{lead.status}");]) %>
In the above code what is happening is that the #{lead.status} which is being passed to getRowColour is always the same i.e. the initial value of status when I first load the page. So how many ever times I change the status via the dropdown, the getRowColour("") does not change.
source of the page:
$('#lead_form_133').submit();document.getElementById('lead_row_133').bgcolor=Application.getRowColour("confirmed");
As can be seen the getRowColour() is taking a constant value and not re-evaluating it on every call. How can I send my lastest status param to this function?
Assuming the id of the status select-box is status consider using the following construction:
<%= f.select(:status, ["to call","didn't connect","confirmed","rejected"],
{:selected => lead.status} %>
Then add the onchange handler logic:
<script type="text/javascript">
$("#status").change(function() {
$('#lead_form_#{lead.id}').submit();
$('#lead_row_#{lead.id}')
.css('background-color', Application.getRowColour($("#status").val())
});
</script>
Each user of my site has their own profile page, which contains several items of the same class, call them job_items, which are instance variables of the job class. I'm working on adding edit functionality for each item. In each item I have
<%= link_to "edit", job_item, :onclick => "$('#edit_job').modal();", :remote => "true" %>
Which I want to bring up a modal containing the appropriate form:
...
<div class="modal-body">
<%= semantic_form_for(job_item, :html => { :class => "form-horizontal" }) do |f| %>
...
<% end %>
However, any time I click edit, it doesn't matter which job_item I clicked edit within, the modal appears with a form for the same job_item, namely the first on the page. How can I set which job_item I want to be edited in the form? I'm confused because if I hold my mouse over the edit link, the correct job url appears, however it is not being passed to the javascript modal.
Is it possible you have more than one element with the id "edit_job" in your page? If so, $('#edit_job') will just choose the first one, because it assumes the ids are unique. You could fix this by making sure the ids are unique
:onclick => "$('#edit_job_#{job_item.id}').modal();"
and changing the corresponding element ids accordingly.
I vahe view form, this form have:
<%= link_to day, root_path(:day => day), :id => 'link', :class => 'active_link' %>
This link reneder this form with day parameter and items on this form rendered with this parameter. I want that after clicking on this link, after re-rendering form - class 'active_link' removed. How can I make it?
P.S: this is link for item (day item from collection).
This is a view logic problem, not a JavaScript/jQuery problem. You are using a normal link to change the day parameter and re-render the entire page. Based on the only line of code you are showing us, I'm guessing your view loops through a bunch of dates and prints a link out for each one. The problem is, you are assigning the active_link class to all of the day links in your view. "Fixing" this problem with jQuery in the browser after the page loads is the wrong approach; instead fix your view logic to only assign the active_link class to the one correct link (and ditch the non-unique 'link' ids).
In your controller:
#active_day = params[:day]
In your view:
<% days.each do |day| %>
<%= link_to day, root_path(:day => day), :class => (day == #active_day ? 'active_link' : '') %>
<% end %>
Obviously, you'll need to tweak that code some to work in your app - you haven't shown enough code for me to write a working code solution.
You can do:
$('a.active_link').click(function(){
$(this).removeClass('active_link');
});
I'm no expert of ruby, but this works if your link is rendered as
<a id='link' class='active_link'></a>