I want to include a piece of JS on every page, but only if session
is set a certain way.
I've got a sidebar with a timer button in it. The sidebar ( layouts/_sidebar.html.erb
) is included on every page's layout once the user logs in.
Click the timer button once, and the timer starts. LogsController#start_from_button
records the click event time in session[:timer_start]
.
Click the button again, and LogsController#finish_from_button
records the second click time in session[:timer_finish]
. Then it renders a form for a new Log
, with START and FINISH fields pre-filled with the session
data. Finally, it clears the above session
values.
Unfortunately, upon page refresh, the timer resets completely. I don't want that to happen. I want it to keep going until the user clicks the button a second time.
My first fix was checking the timer status in ApplicationController
before every action. Then, if session[:timer_start]
isn't nil
, I might include the requisite JS to make the timer continue from session[:timer_start]
. But the only way I know to do that is pretty ugly:
# application_controller.rb
before_action :check_timer_status
...
def check_timer_status
if session[:timer_start]
# include page-specific JS
end
end
I also would like the templates to display as normal.
A) If this seems hacky, what's a better way of accomplishing this, or
B) If it's not too hacky, how might I be able to include the page-specific JS from that controller action?
To answer you question - you can use content_for(:include_js){ @include_js}
in view and
<% yield(:include_js) %>
<% javascript_include_tag ..... %>
<% end %>
in your main layout head section. Where is @include_js - boolean of your specific condition.
But I believe you shouldn't exclude js. Because js loads once and then browser uses cached copy. Use cookies to keep timer_start instead and read it by your js script.
Here is how you can do it.
Get the jquery-stopwatch library.
Put it in your public/assets/javascripts
directory
Add it to your application layout by putting :
<%= javascript_include_tag 'jquery.stopwatch' %>
You have to store the time your timer is stopped in your database. Just fire an event to record the Time.now
somewhere in the database.
Make a helper method in your application_helper. You are trying to record the milliseconds elapsed since the timer had started. You can send the milliseconds elapsed to the database by putting the button in a form or through AJAX. It's up to you.
def time_elapsed @time_now = Time.now @time_timer_stopped = #this is where you query your db and pull out the time the timer has been stopped. return (@time_now - @time_timer_stopped)*1000 #returns the miliseconds passed after you stopped the time end
time_elapsed
method is reachable $('#someDiv').stopwatch({startTime: <%= time_elapsed %>}).stopwatch('start') </script>
Voila, you have your stopwatch.
I ended up using cookies, and checked for them exclusively on the client side. Cookies were preferable to localStorage
in my case because down the development road I may want to check cookie values server-side, and localStorage
won't let me do that.
// Every page change, check if user has previously
// clicked the timelog start button but not the
// timelog finish button.
// If so, start the timer from when the user first
// clicked the button.
if(isCookie('start_time') || $start_time) {
timerRunningDisplay();
activateTimer();
}
// When user clicks timelog start button,
// start timer and save the click time in cookies.
$(document).on("click", '#start-timelog', function(e) {
e.preventDefault();
timerRunningDisplay();
activateTimer();
setCookie('start_time', $start_time, 7);
});
// Sets timer running, updated every second.
// Start is when user first clicked 'start' button.
function activateTimer() {
if(isCookie('start_time')) {
x.continueTimer();
}
else {
x.start();
}
clocktimer = setInterval(update, 1000);
}
The FINISH button POSTS to the finish_from_button
controller action using AJAX:
def finish_from_button
query_string = {
start_time: params[:start_time],
finish_time: params[:finish_time]
}.to_query
render js: %(window.location.href='#{new_timelog_path}?#{query_string}')
end
And the #new
action is rendered.
def new
@timelog = Timelog.new
@timelog.start_time = params[:start_time]
@timelog.end_time = params[:finish_time]
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.