Hi there it's the third I ask you to help me on this point.
I don't know how to explain it because I read some tutorials or answers but I don't understand what can I do.
Ok I am working on an app to learn Japanese language with hiragana flashcards.
I created a feature to add a card as a favorite. When I click on a grey color heart, the heart becomes in red color and it saves in an index favs page.
The problem is when I click to add as favorite the full page is loaded and I don't want it. I just wnat have the heart object which changes of state.
I would use ajax and javascript but I don't know what can I call and which is the syntax. I have ever read http://guides.rubyonrails.org/working_with_javascript_in_rails.html
And Try to do the same but it doesn't work.
here is the favs controller
class FavsController < ApplicationController
def index
#favs = Fav.where(user: current_user)
end
def create
#hiragana = Hiragana.find(params[:hiragana_id])
#fav = current_user.favs.new(hiragana: #hiragana)
if not #hiragana.favs.where(user: current_user).take
#fav.save
end
# redirect_to favs_path
# redirect_to :back
render json: #fav
end
def destroy
#fav = Fav.find(params[:id])
#fav.destroy
redirect_to :back
end
end
Above I choose to redirect as a json format but now
here is the render favorite view
<% if current_user %>
<div class="hiragana-fav">
<% if hiragana.is_faved_by(current_user) %>
<%= link_to fav_path(hiragana.is_faved_by(current_user)), method: :delete do %>
<i class="fa fa-heart faved faved-on"></i>
<% end %>
<% else %>
<%= link_to hiragana_favs_path(hiragana), method: :post do %>
<i class="fa fa-heart faved faved-off"></i>
<% end %>
<% end %>
</div>
<% end %>
and the index hiraganas view where the favs render is located
<div class="row">
<ul class="list-inline text-center card-frame">
<li>
<div class="card">
<div class="front">
<% if current_user.try(:admin?) %>
<%= link_to hiragana_path(hiragana), class:'trash-hiragana', data: { confirm: 'Are you sure?' }, method: :delete do %>
<%= image_tag("delete-btn.png") %>
<% end %>
<% end %>
<span class="card-question img-popover" data-content="<h4 class='text-center letter-uppercase'><%= hiragana.bigletter.upcase %></h4><p class='text-center'><b><%= hiragana.midletter %></b> comme dans <b><%= hiragana.transcription %></b></p>">
<i class="fa fa-eye fa-lg"></i>
</span>
<div class="card-hiragana hiragana-<%=hiragana.bigletter.downcase.last%>">
<h1><b><%= hiragana.ideo1 %></b></h1>
</div>
<div class="card-katakana">
<p><%= hiragana.ideo2 %></p>
</div>
<%= render 'favs/favorites', hiragana: hiragana %>
</div>
<div class="back">
<div class="col-sm-3 col-xs-4 col-md-3 containerbackcards-<%=hiragana.bigletter.downcase.last%>">
<div class="backcard-hiragana">
<h1><b><%= hiragana.ideo1 %></b></h1>
</div>
<div class="card-bigletter">
<h4><%= hiragana.bigletter.upcase %></h4>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
I try to call it with this javascript code but i don't where I can place it and how do I have to call the file .js.erb? (I put it in application.js for now but it doesn't communicate with the rest of my code)
application.js
$(document).ready(function() {
$('.faved-on').click(function() {
var fav = $('.faved-off')
$.ajax({
type: "POST",
url: "/hiraganas",
dataType: "json",
success: function(data) {
console.log(data);
},
error: function(jqXHR) {
console.error(jqXHR.responseText);
}
});
})
})
Help will be appreciated :).
Have you tried this: http://guides.rubyonrails.org/working_with_javascript_in_rails.html#link-to ?
There is a simple "remote: true" to add inside your link_to code. Something like that:
<%= link_to hiragana_favs_path(hiragana), class: "add-to-favorite", method: :post, remote: true do %>
<i class="fa fa-heart faved faved-off"></i>
<% end %>
Then to perform some special actions in your Coffee (JS), you could do:
$ ->
$("a.add-to-favorite").on "ajax:success", (e, data, status, xhr) ->
console.log(data)
alert "Favorite added."
And you can do the same thing for the other link_to (the :delete one).
Also I would rather use "button_to" instead of "link_to method: :post" as you did, as "link_to" should not really be used to POST data. Button_to is a simple helper that works like link_to but is replaced by a form, which is better to post data. :)
Of course you don't have to, but it'd be better this way. :)
Let me know if it worked. If not, add comments and edit your question to add more info, I'll try to help you more by editing my answer and adding more info.
Related
I have a screen where a user can select differente kinds of plans for his account. Like this:
#plans
<% Plan.all.order(:amount).each do |plan| %>
<%= render 'shared/plan_detail', {plan: plan, button_text: 'Choose this' } %>
<% end %>
#plan_detail
<div class="plan-details">
<header class= <%= plan.css %> >
<h3><%= plan.name %></h3>
<small><%= plan.visibility %></small>
<p><%= plan.card_description.html_safe %></p>
<span class="plan-price"><sup>$</sup><%= plan.amount.to_s %></span>
</header>
<article>
<%= plan.features_description.html_safe %>
<%= link_to button_text, {:controller => "accounts", :action => "update_plan", :plan => plan.id }, title: button_text, :class=>"btn btn-md btn-block btn-outline-green dialog-open" %>
</article>
</div><!-- end plan details -->
And In my controller i have:
#accounts_controller.rb
def update_plan
#plan = Plan.find(params[:plan])
current_user.plan = #plan
current_user.save
end
My routes its like this
get '/account/plans', to: 'accounts#plans', as: :update_plan
put '/account/plans', to: 'accounts#update_plan'
But I click on the button, and nothing happens. What Im doing wrong here?
This is a long shot, but seeing that your link has dialog-open I wouldn't be surprised if there was some Javascript preventing your link from working. In order to debug this further I would
a) Check browser's Javascript console for any errors
b) Remove the dialog-open class to see what happens
Im submitting my form with checkboxes via Jquery with remote true but its not working. Its keeps rendering the html format in the controller and i can work out why.
Here is my submit button and form:
<%= button_to "Read sel", root_path, class: "btn btn-info btn-sm padlr", id: "notification-submit" %>
<%= form_tag read_selected_notifications_path, :authenticity_token => true, remote: true ,id: "notification-form" do %>
<% #notifications.each do |x| %>
<div class="notification-body flerowspb">
<div class="flerowspb" style="width:80%">
<div class="notif-check flecolcen">
<%= check_box_tag "read_notif[]", value="#{x.id}" %>
</div>
<div class="notif-details ">
<div class="notif-time flerowspb">
<% if !x.viewed %>
<span class="glow"> New <%= x.notification_type.capitalize %></span>
<% else %>
<span><span class="text-grey"> New <%= x.notification_type.capitalize %></span></span>
<% end %>
<span class="text-grey font-small"> <%= time_ago_in_words(x.created_at) %> ago</span>
</div>
<div class="notif-body font-medium text-grey">
<span class="text-blue"><%= link_to x.sender.username, profile_path(x.sender) %> </span> <%= x.title %> <br>
Click <span class="text-blue"><%= link_to "Here", entry_path(x.entry_id, notification_id: x.id) %> </span> to view it
</div>
</div>
</div>
<div class="notif-image">
<%= image_tag x.entry.image.small_thumb %>
</div>
</div>
<% end %>
<% end %>
So there is no actual submit button for the form as i want the button above the form not below it like this,
I understand i have to add :authenticity_token => true as rails doesnt add this to form_tag with remote: true
Here is my controller:
def read_selected
Notification.read_selected(current_user.id, params[:read_notif])
respond_to do |format|
format.html{
flash[:success] = "Selected notifications marked as read"
redirect_to notifications_path
}
format.js{
render 'notifications/jserb/read_selected'
}
end
end
Here is the js code:
$(document).on('turbolinks:load', function(){
if (window.location.href.match(/\/notifications/)) {
$('#notification-submit').on('click', function(e){
console.log('oisdjfilds');
e.preventDefault();
$('#notification-form').submit();
});
}
});
EDIT: I added in a submit button at the bottom of the form and it works as it should do, So it something to do with the way i'm submitting the form
I assume you're using Rails 5, since there is such an inconsistency in its behavior. Please, check out the issue
As far as I understand the quick solution for your problem is going to be:
Get the form HTML element:
form = document.getElementById('notification-form');
or
form = $('#notification-form')[0]
And then fire Rails submit:
Rails.fire(form, 'submit');
or
form.dispatchEvent(new Event('submit', {bubbles: true}));
UPDATE: I'm almost there! See my partial answer at the end of this question.
I've got a working form with two select dropdowns, the first for countries, the second for cities. When you select a country, an ajax request automagically gets the countries and updates the countries box.
The problem is the select dropdowns are ugly, and I can't really style them. What I want is a dropdown button, which I can use Bootstrap on to make pretty: Bootstrap Button
I don't have to change the jquery or controller logic, I just have to update my view. But I don't even know where to start. This is what I have:
<%= form_for :trip, url: {action: "index"}, html: {method: "get"} do |f| %>
<%= f.select :country_obj_id, options_for_select(#countries.collect { |country|
[country.name.titleize, country.id] }, #countries.first.name), {}, { id: 'countries_select' } %>
<%= f.select :city_obj_id, options_for_select(#cities.collect { |city|
[city.name.titleize, city.id] }, 0), {}, { id: 'cities_select' } %>
<%= f.submit "Go!" %>
<% end %>
How can I convert the selects into dropdown buttons?
UPDATE: I can now get a response back. I just don't know how to handle it to update the button.
The view has two dropdown buttons. The first is the countries, the second is the cities for the first country. I want to update the list of cities for the country that is selected:
<div class="dropdown" style="display:inline-block;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A Country
<span class="caret"></span></button>
<ul class="dropdown-menu">
<% #countries.each do |country| %>
<%= content_tag(:li, link_to(country.name.titleize, update_cities_path(country_obj_id: country.id), remote: :true)) %>
<% end %>
</ul>
</div>
<div class="dropdown" style="display:inline-block;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A City
<span class="caret"></span></button>
<ul class="dropdown-menu">
<% #cities.each do |city| %>
<%= content_tag(:li, city.name.titleize) %>
<% end %>
</ul>
</div>
Selecting a country goes into the update_cities function, which gets the cities for the country_obj_id that is passed.
def update_cities
#cities = CityObj.where("country_obj_id = ?",
params[:country_obj_id]).order(:name)
respond_to do |format|
format.js
end
end
Then the part that i don't understand. The format.js takes me to update_cities.js.coffee, which I have not changed from my original version that worked on the select dropdown:
$("#cities_select").empty()
.append("<%= escape_javascript(render(:partial => #cities)) %>")
That ends up updating my old select dropdown, which I left in the view for now. But how can I modify the js to update my new dropdown button?
You will need a mix of Javascript with Rails:
First, you will need to print all options in Bootstrap's button format:
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Countries
<span class="caret"></span></button>
<ul class="dropdown-menu">
<% #countries.each do |country| %>
<%= content_tag(:li, country.name.titleize) %>
<% end %>
</ul>
</div>
Add funcionality to select an option from this dropdown:
https://stackoverflow.com/a/22000328/891807
Got it. This is the coolest thing ever. It starts out with two buttons. The first says "Select A Country," and the second says "Select A City." The second button is not active to start with, and I'll probably hide it.
The view:
<div class="dropdown" style="display:inline-block;">
<button id="country-select-btn" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A Country
<span class="caret"></span></button>
<ul class="dropdown-menu">
<% #countries.each do |country| %>
<%= content_tag(:li, link_to(country.name.titleize, update_cities_path(country_obj_id: country.id), remote: :true)) %>
<% end %>
</ul>
</div>
<div class="dropdown" style="display:inline-block;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A City
<span class="caret"></span></button>
<ul id="cities_select" class="dropdown-menu">
</ul>
</div>
The dropdown items are just links, with a route set so clicking a link goes to the controller update_cities action with a country passed:
def update_cities
#cities = CityObj.where("country_obj_id = ?",
params[:country_obj_id]).order(:name)
#country = CountryObj.find_by(id: params[:country_obj_id])
respond_to do |format|
format.js
end
end
The format.js goes into update_cities.js
$("#cities_select").empty()
.append("<%= escape_javascript(render(:partial => #cities)) %>")
$("#country-select-btn").empty()
.append("<%= escape_javascript(render(:partial => #country )) %>")
That renders two partials. _city_obj.html.erb renders a link for each of the cities, which will go to the controller's index action when clicked:
<li><%= link_to(city_obj.name.titleize, index_path(:trip => {country_obj_id: city_obj.country_obj.id, city_obj_id: city_obj.id}), id: "cities_select") %></li>
The _country_obj.html partial just updates the "Select A Country" label on the button to the name of the selected country:
<%= country_obj.name.titleize %>
Now, when you click one of the city links, the controller index action can find all the guides for that city/country, then the view will render it.
From what I understood, you want to add style to your html form using bootstrap. If this is the case then this is how you can do that:
1.Add bootstrap gem if you have not done it already following the documentation(https://github.com/twbs/bootstrap-sass)
In short, you need to add following at your Gemfile:
gem 'bootstrap-sass', '~> 3.3.5'
Add following line at your app/assets/stylesheets/application.scss so that bootstrap styles gets added at every page:
#import "bootstrap-sprockets";
#import "bootstrap";
2.Using bootstrap styles, at your ugly select tag you need to add form-control at your class name as bootstrap documentation suggests. add class: "form-control" parameter like this:
<%= form_for :trip, url: {action: "index"}, html: {method: "get"} do |f| %>
<%= f.select :country_obj_id, options_for_select(#countries.collect { |country|
[country.name.titleize, country.id] }, #countries.first.name), {}, { id: 'countries_select', class: "form-control" } %>
<%= f.select :city_obj_id, options_for_select(#cities.collect { |city|
[city.name.titleize, city.id] }, 0), {}, { id: 'cities_select', class: "form-control" } %>
<%= f.submit "Go!" %>
<% end %>
I'm new in Rails. I try to make a list of groups (/groups) where I want to have edit and delete option in each row. Editing should be implemented by modal because Group has only one attribute - name. So I don't want to open /groups/number/edit.
My problem is: I don't know how to bind chosen group with form_for. Maybe it isn't good approach indeed.
Modal is displayed, but the name field is blank. When I used debug for #group is blank too. I don't know why.
Here is my code(single group row):
<li id="group-<%= group.id %>" class="list-group-item">
<span class="group-name"><%= group.name %></span>
<%= link_to edit_group_path(group.id), "data-toggle" => "modal", "data-target" => "#myModal", :class => "edit-option btn" do %>
<i class="fa fa-pencil-square-o fa-2x" ></i>
<% end %>
<%= link_to group, method: :delete, data: { confirm: "Na pewno chcesz usunąć tę grupę?" }, :class => "delete-option btn btn-danger" do %>
<i class="fa fa-trash-o" > usuń</i>
<% end %>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Zmień nazwę grupy</h4>
</div>
<%= form_for(#group) do |f| %>
<div class="modal-body">
<%= debug #group %>
<p>
<%= f.label :name, "Nazwa" %>
<%= f.text_field :name, class: 'form-control'%>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
<%= f.submit "Zapisz zmiany", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
Controller
def edit
#group = current_user.groups.find_by(id: params[:id])
end
def update
#group = current_user.groups.find_by(id: params[:id])
if #group.update_attributes(group_params)
flash[:success] = "Nazwa grupy została zmieniona"
redirect_to groups_path
else
redirect_to groups_path
end
end
I will assume that the answer to my question above is a yes, and so, I'll just continue to answer.
First thing: You don't want to be repeating different Modals for each group, you want only a single Modal to be used by all the groups.
Second thing: You are very correct with the idea of wanting to send the group.id to the edit method in your controller, for it to return that group back into your Modal
However, what is wrong is how you are trying to achieve this.
<%= link_to edit_group_path(group.id), "data-toggle" => "modal", "data-target" => "#myModal", :class => "edit-option btn" do %>
You are telling your link to do two things when clicked: (1) go to edit path (2) open modal. Which one will take more importance? Right now, it is the modal that is opening, and not the edit path working, which means that you are not getting to the controller at all, so accounting for why your #group is blank.
To achieve this, you will have to tell your link to do only one thing, and when that is successful, do the other.
What I'll advice is to use Ajax (by setting remote: true) on your link to go to the controller, and then open the modal on response.
Here is a breakdown of the steps:
1.Set remote: true to make the call with Ajax
<%= link_to edit_group_path(group.id), remote: true %>
2.Tell controller action (in this case, the edit action) to respond to js
def edit
#group = current_user.groups.find_by(id: params[:id])
format.js
end
Prepare an edit.js.erb file to handle the response (this will be in the same directory which your other view files are)
Populate the form with the #group from inside the response
Put the populated form in the modal
Use Javascript to show the modal
$('.modal-title').html("Edit Group")
$('.modal-body').html("<%= escape_javascript( render partial: 'form', locals: {group: #group} ) %>")
$('#myModal').modal()
As simple and as direct as that. Hope this helps a lot.
This is a foolish question But I have no idea where to begin.
I want to use Bootstrap's Progress Bars.
I have a simple todo list app. I want to be able to visually show that 70% of a todo list is complete.
How would I go about this, or what resources do I need to look at. I can only find information on using the progress bars to display a websites loading progress.
I want to set these up to be dynamic of course. So when a user marks an object as complete, then the progress bar should change as well.
_todo_item.html.erb
<div class="row clearfix">
<% if todo_item.completed? %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(#todo_list, todo_item.id), method: :patch do %>
<i style="opacity: 0.4;" class="glyphicon glyphicon-ok"></i>
<% end %>
</div>
<div class="todo_item">
<p style="opacity: 0.4;"><strike><%= todo_item.content %></strike></p>
</div>
<div class="trash">
<%= link_to todo_list_todo_item_path(#todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<span class="glyphicon glyphicon-trash"></span>
<% end %>
</div>
<% else %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(#todo_list, todo_item.id), method: :patch do %>
<span class="glyphicon glyphicon-ok"></span>
<% end %>
</div>
<div class="todo_item">
<p><%= todo_item.content %></p>
</div>
<div class="trash">
<%= link_to todo_list_todo_item_path(#todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<span class="glyphicon glyphicon-trash"></span>
<% end %>
</div>
<% end %>
</div>
todo_items_controller.rb
class TodoItemsController < ApplicationController
before_action :set_todo_list
before_action :set_todo_item, except: [:create]
def create
#todo_item = #todo_list.todo_items.create(todo_item_params)
redirect_to #todo_list
end
def destroy
if #todo_item.destroy
flash[:success] = "Todo List item was deleted"
else
flash[:error] = "Todo List item could not be deleted."
end
redirect_to #todo_list
end
def complete
#todo_item.update_attribute(:completed_at, Time.now)
redirect_to #todo_list, notice: "Todo item completed"
end
private
def set_todo_list
#todo_list = TodoList.find(params[:todo_list_id])
end
def set_todo_item
#todo_item = #todo_list.todo_items.find(params[:id])
end
def todo_item_params
params[:todo_item].permit(:content)
end
end
A users has a todo_list and a todo list has a todo_item. I want to use a progress bar so that I can show a percentage of tasks that have been completed.
If you look at this example, taken from the Bootstrap Docs, you can see the width is set on the .progress-bar element. That width is what sets the 'completeness' of the bar. So for 70% done, set its width to 70%.
Relevant code from Bootstrap:
<div class="progress">
<div class="progress-bar" style="width: 60%;" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
<span class="sr-only">60% Complete</span>
</div>
</div>
Bootstrap Progress Bar implementation for HTML Forms:
-This scripts creates an event handler.
-When the user switches input element (form-group in this case), it increments the progress bar status by 20% (there are 5 inputs in my form).
let progressBar = document.getElementsByClassName("progress-bar")[0];
$('.form-group').focusout(function() {
let currentValue = parseInt(progressBar.style['width']);
progressBar.style['width']=currentValue+20+"%";
});
You can find some examples here