Rails and jQuery: remove class after click - javascript

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>

Related

Rails5: how to pass element to bs modal with form_tag

I have an index view listing my elements. I want a button link to open a modal view containing a form_tag to pass some text which then get's sent to a third party API, but 'linked' to the element (it's ID) passed.
So far I get the modal showing and it's submitting correctly. But: the modal get's always the first/last element of the index list.
/config/routes.rb
namespace: manage do
resources :elements do
member do
post :my_action
end
end
end
/manage/elements/index.html.haml
#elements.each do |element|
%tr
%td
= link_to 'btn-text', '#myModal', data: { toggle: 'modal', target: '#myModal'}
= render 'manage/elements/element_modal', element: element
/manage/elements/_element_modal.html.haml
#myModal.modal.fade{...}
.modal-dialog
.modal-content
= form_tag path_to_my_action(element), method: :post do
= text_field_tag :text, params[:text]
= submit_tag
I tried different approaches (a modal for each element, data-attributes, AJAX) like found eg here: Bootstrap Modal in Rails Keeps displaying the first record
But actually I can't get any of these working and I don't get why. Can you give me a hint based on above example so I finally get this working? Thanks!

Rails: Dynamic form generation from the database

I've been scratching my brain (kinda painful, wouldn't advise it) trying to figure out a way to pull this off, but I haven't been able to come up with anything that really seems feasible.
The idea is this: I have a page that allows you to create an event. This event could be anything from a wedding to a marathon or fund raiser. Different events need to have a form specific to that event type, e.g. the wedding event needs the name of the bride, groom, address, receptions, etc.
What I'm trying to figure out is how to allow them to select an event type, and then go to localhost:3000/events/create(/:event_type) and have that view load in the correct form fields.
My original thought was to have event types stored in a database with each form stored as JSON, but this just seems more complicated than I'd think necessary.
Any ideas?
Here's routes.rb so far:
get 'my_events/', to: 'events#index', as: :events
get 'events/create', to: 'events#create', as: :new_event
match 'events/new', to: 'events#new', as: :post_new_event, via: :post
get 'event/:slug', to: 'events#show', as: :show_event
root 'static#index'
devise_for :users, :controllers => { :omniauth_callbacks => 'omniauth_callbacks' }
And the events controller:
class EventsController < ApplicationController
def index
#events = Event.all()
end
def create
#event = Event.new()
end
def show
#event = Event.find_by slug: params[:slug]
end
def delete
end
end
You can generate a form with tags to match any number of columns without knowing the column names like this
<%= form_for #event do |f| %>
<% #event.attributes.each do |k,v| %>
<% unless k == 'id' %> #in the case of an edit form, the id should not be changable
<p>
<%= f.label k.to_sym %><br> #get the name of the column, put it into a symbol
<%= f.text_field k.to_sym %> #same as above, will put the matching value in if it exists
</p>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
Though this may not be suited for how your model appears to be set up, a single Event database that can hold any event. This would work better if you had a specific database for each type.
To go in to detail on how I would see this working for you...
Your planned route /events/create/:event_type would work
in your new action in the controller
def new
if params[:event_type] == 'wedding'
#event = Wedding.new #would need to do the same for each event type
end #a model/database for each different type of event
end
However if event is a parent Event database to a child event type, you may be able to make it work, though I'm not familiar enough with relational databases in Ruby on Rails to say how.
This is a fairly common pattern. On your edit/new form(or modal), you need to have a javascript handler on your event_id field. When it changes, you do an ajax request to your server to get the valid event_types for that event so that you may populate the event_types input control.
I would strongly discourage doing any client side storage (hard coding) of the event_types as this design will not allow for easy addition of future events.

Rails: Update database based on DOM element / jQuery

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.

Click rails button to permanently change data model and css

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!

Correct object not passing to remote form

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.

Categories

Resources