AJAX function not getting called - javascript

I am new to RoR and AJAX, jquery etc. I am trying to make an ajax call in a view, but its not happening.
Corresponding controller(product_search_controller,rb) is:
def index
#products = querySolr(params[:q])
#productsProxy = Array.new
if #products != nil
#products.each do |p|
#productsProxy.push(ProductProxy.new(p))
end
else
#productProxy = []
end
#taxons = #productsProxy.map(&:get_taxonomy).compact.uniq
respond_with("Search Results") do |format|
format.js
format.html
format.xml { render :xml => #productsProxy, :only => [:name, :permalink, :description, :mrp], :methods => [:designer, :taxons, :price] }
end
end
Corresponding view(views/product_search/index.hrml.erb) is:
<%= render :partial => 'products', :locals => {:products => #productsProxy, :taxons => #taxons, :scope => self, :scope_type => "Search"} %>
<%= render :partial => 'shared/inf_scroll', :locals => {:url => "?&page=", :total_count => #total_count} %>
/views/product_search/_products.html.erb:
<% if products.empty? %>
<div class="not_found"><%= "No Products found for the selected query. Please try a different search." %></div>
<% elsif params.key?(:keywords) %>
<h3><%= t(:search_results, :keywords => h(params[:keywords])) %></h3>
<% end %>
<% if products.any? %>
<div class="product_rows">
<%= render :partial=> 'product_listing_feature', :locals => {:scope => scope, :scope_type => scope_type} %>
<div id="ql_product"></div>
<%taxons.each do |taxon|%>
<ul class="products" data-hook class="products">
<div class = "product_row">
<h1><%=taxon%></h1>
<% taxonProducts = Array.new %>
<% products.each do |product| %>
<%#ptaxon = product.get_taxonomy%>
<%if #ptaxon == taxon%>
<% taxonProducts.push(product) %>
<% end %>
<% end %>
<div class ="featured_product_list">
<ul class = "featured_products">
<div class = "page">
<%= render :partial=> 'product_listing', :locals=>{:collection=> taxonProducts} %>
</div>
</ul>
</div>
</div>
</ul>
<% end %>
</div>
</div>
<% end %>
i.e it renders another partial _product_listing which has the following script:
<script>
$("document").ready(function(){
$("li#product_<%=product.productId%>").hover(
function(){$("div#quick_look_<%=product.productId%>").css("visibility", "visible");},
function(){$("div#quick_look_<%=product.productId%>").css("visibility", "hidden");}
);
$("div#quick_look_<%=product.productId%>").css("visibility", "hidden");
});
hide_sold_out({
url: "<%= sold_out_status_taxons_url(#taxon) %>",
data: {
pids: "<%= collection.map(&:id).join(",") %>"
}
});
</script>
Helper:
var hide_sold_out = function(options){
$.ajax({
url: options["url"],
data: options["data"],
type: 'get',
dataType: 'text',
success: function(data){
pids = data.split(',');
for(var i = 0; i < pids.length; i++) {
if($("li#product_"+pids[i]).children("div.info").children("span.offer.sold").length == 0) {
$("li#product_"+pids[0]).children("div.info").append("<span class='offer sold'></div>");
$("li#product_"+pids[0]).children("div.info").children("div.product_listing_info_hover").children("div.listing_buttons").html("");
}
}
},
error: function(data){
console.log(data);
}
. I tried using the following in /views/product_search/index.js.erb:
$("ul.products").append("<div class='page'><%= escape_javascript(render(:partial => 'product_listing', :locals=>{:collection=> #productsProxy})) %></div></div>")
This didn't work. Then i tried:
<%#taxons.each do |taxon|%>
<%taxonProducts = Array.new%>
<%#productsProxy.each do |product|%>
<%#ptaxon=product.get_taxonomy%>
<%if #ptaxon==taxon%>
<%taxonProducts.push(product)%>
<%end%>
<%end%>
$("ul.products").append("<div class='page'><%= escape_javascript(render(:partial => 'product_listing', :locals=>{:collection=> #taxonProducts})) %></div></div>")
<%end%>
But the AJAX call is not doing what its supposed to do. Please could someone help me debug this. Thanks

These
url: options["url"],
data: options["data"],
should be
url: options.url,
data: options.data,

Related

Refresh Turbo Frames with a select without submitting on Rails 7

I'm learning Turbo Frames and Streams + Stimulus so it's possible I'm not 100% on track. I have a form for creating a new object, but within the form I'd like to have a select component that will display certain fields depending on the selection. It's important to note that due to this, I do not want to submit the form until the user has made this selection.
This is what I have:
_form.html.erb
<div class="form-group mb-3">
<%= form.label :parking, class: 'form-label' %>
<%= form.number_field :parking, class: 'form-control' %>
</div>
<%= turbo_frame_tag "turbo_transactions" do %>
<%= render 'property_transactions' %>
<% end %>
_property_transactions.html.erb
<div class="form-group mb-3" data-controller="property-transaction">
<%= label_tag :property_transactions, 'Property in:', class: 'form-label' %>
<%= select_tag :property_transactions, options_for_select(#property_transactions.collect {|p| [p.name, p.id]}), { data:
{ action: "property-transaction#redraw", property_transaction_target: 'transaction', turbo_frame: 'turbo_transactions' },
class: 'form-control', prompt: '', autocomplete: 'off' } %>
</div>
<% if #property_transaction %>
<%= turbo_frame_tag #property_transaction.en_translation_key do %>
<div class="form-group mb-3">
<%= render #property_transaction.en_translation_key %>
</div>
<% end %>
<% end %>
property_transaction_controller.js
import { Controller } from "#hotwired/stimulus";
import Rails from "#rails/ujs";
export default class extends Controller {
static targets = [ "transaction" ];
redraw() {
const params = { property_transaction: this.transaction };
Rails.ajax({
type: 'post',
dataType: 'json',
url: "/set_property_transaction",
data: new URLSearchParams(params).toString(),
success: (response) => { console.log('response', response) }
});
}
get transaction() {
return this.transactionTarget.value;
}
}
property_controller.rb
def set_property_transaction
respond_to do |format|
format.json
format.turbo_stream do
if #property_transactions
#property_transaction = #property_transactions.select { |p| p.id == property_transaction_params }
else
#property_transaction = PropertyTransaction.find(property_transaction_params)
end
end
end
end
set_property_transaction.turbo_stream.erb
<%= turbo_stream.replace #property_transaction.en_translation_key %>
_rent.html.erb
<%= turbo_frame_tag "rent" do %>
<!-- some input fields -->
<% end %>
_rent_with_option_to_buy.html.erb
<%= turbo_frame_tag "rent-with-option-to-buy" do %>
<!-- other input fields -->
<% end %>
_sale.html.erb
<%= turbo_frame_tag "sale" do %>
<!-- more input fields -->
<% end %>
When selecting the option, this error happens:
Started POST "/set_property_transaction" for ::1 at 2022-09-07 19:49:03 -0600
Processing by PropertiesController#set_property_transaction as JSON
Parameters: {"property_transaction"=>"2"}
Completed 406 Not Acceptable in 223ms (ActiveRecord: 0.0ms | Allocations: 1879)
ActionController::UnknownFormat (PropertiesController#set_property_transaction is missing a template for this request format and variant.
request.formats: ["application/json", "text/javascript", "*/*"]
request.variant: []):
My understanding to this is that I'm missing the set_property_translation template, but I do have it. Not sure what else could I do to make it recognizable.
Les Nightingill's comment definitely sent me in the right direction. I'll put the changes needed here.
_property_transactions.html.erb
<div class="form-group mb-3" data-controller="property-transaction">
<%= label_tag :property_transactions, 'Propiedad en:', class: 'form-label' %>
<%= select_tag :property_transactions, options_for_select(#property_transactions.collect {|p| [p.name, p.id]}), { data:
{ action: "property-transaction#redraw", property_transaction_target: 'transaction', turbo_frame: "turbo_transactions" },
class: 'form-control', prompt: '', autocomplete: 'off' } %>
</div>
<%= turbo_frame_tag "dynamic_fields" %>
property_transaction_controller.js
import { Controller } from "#hotwired/stimulus";
import { post } from "#rails/request.js";
export default class extends Controller {
static targets = [ "transaction" ];
async redraw() {
const params = { property_transaction: this.transaction };
const response = await post("/set_property_transaction", {
body: params,
contentType: 'application/json',
responseKind: 'turbo-stream'
});
if (response.ok) {
console.log('all good', response); // not necessary
}
}
get transaction() {
return this.transactionTarget.value;
}
}
set_property_transaction.turbo_stream.erb
<%= turbo_stream.update "dynamic_fields" do %>
<%= render partial: #property_transaction.en_translation_key %>
<% end %>

How to replace button in another view with javascript? Remote: true for link_to of an action in has_many trrough assosiation

Sorry for the long title. I don't know how I got stuck this much.
I wanted to have a button (actually a link_to styled as a button) for FOLLOW / UNFOLLOW on remote. That's a Follow model where records are stored for Corporation and User (a User can follow a Corporation). The follow/unfollow links are on the Corporation show page.
<% if user_signed_in? %>
<% if Follow.where(corporation_id: #corporation.id, user_id: current_user.id).first.nil? %>
<%= link_to 'FOLLOW', {:controller => "follows", :action => "create", :user_id => current_user.id, :corporation_id => #corporation.id}, remote: true, :method => "post", class: "btns follow", id: "follow1" %>
<% elsif %>
<%= link_to 'UNFOLLOW', {:controller => "follows", :action => "destroy", :corporation_id => #corporation.id, :user_id => current_user.id }, remote: true, :method => "delete", class: "btns unfollow", id: "unfollow" %>
<% end %>
<% end %>
These are the controller actions:
def create
#corporation_id = params[:corporation_id]
#follow = Follow.new(follow_params)
#follow.save
respond_to do |format|
format.js {render :file => "/corporations/create.js.erb" }
end
end
def destroy
#corporation_id = params[:corporation_id]
attending.destroy
#attending is a method where the follow is defined. This is ok.
respond_to do |format|
format.js {render :file => "/corporations/destroy.js.erb" }
end
end
I'm rendering create.js.erb in corporations, since the change has to happen there. If I leave it as format.js, it'll search in the follows folder which is empty.
The create.js.erb look like this:
$("#unfollow").click(function(){
$("unfollow").replaceWith("<%= escape_javascript(render :partial => "corporations/profile/follow", :locals => {corporation_id: #corporation_id}) %>");
});
Btw, I tried .html instead of replaceWith, but it's not that.
The destroy.js.erb is similar. And the _unfollow.html.erb partial is like this:
<% if !#corporation.nil? %>
<%= link_to 'UNFOLLOW', {:controller => "follows", :action => "destroy", :corporation_id => #corporation.id, :user_id => current_user.id }, :method => "delete", class: "btns unfollow", remote: true, id: "unfollow" %>
<% else %>
<%= Rails.logger.info("First here") %>
<%= Rails.logger.info(corporation_id) %>
<%= link_to 'UNFOLLOW', {:controller => "follows", :action => "destroy", :corporation_id => corporation_id.to_i, :user_id => current_user.id }, :method => "delete", class: "btns unfollow", remote: true, id: "unfollow" %>
<%= Rails.logger.info("Now here...") %>
<% end %>
Without the first condition it just fires up an error the corporation_id (it's same with locales[:corporation_id]) is not defined and similar.
I have no idea what to try now... All the tutorials on the net are quite simple but the remote action is just one action in the controller where it needs to change, this has to go to another controller then back, then again to Follow... I'd really appreciate the help.

JS controlling ajax tabs and JS controlling will_paginate in same js.erb not working (endless scroll)

I have tried to fix this for some time, but I cannot find the solution. I have ajax controlling some on page tabs, which is working fine:
$("#feed-content").html("<%= escape_javascript(render(:partial => "#{#partial_name}")) %>");
But then I added will_paginate with endless scrolling, where I put the js that is controlling that in the same js.erb file as the above (sale.js.erb):
$("#feed-content").html("<%= escape_javascript(render(:partial => "#{#partial_name}")) %>");
$('#products').append('<%= escape_javascript(render(:partial => 'sale_content', :products => #products, :remote => true)) %>');
<% if #products.next_page %>
$('.pagination').replaceWith('<%= escape_javascript( will_paginate(#products)) %>');
<% else %>
$('.pagination').remove();
<% end %>
But that do not working. But each part work individually.
Then i tried this, but it still does not work (it only loads the if part):
<% if params[:feed]%>
$("#feed-content").html("<%= escape_javascript(render(:partial => "#{#partial_name}")) %>");
<% else %>
$('#products').append('<%= escape_javascript(render(:partial => 'sale_content', :products => #products, :remote => true)) %>');
<% if #products.next_page %>
$('.pagination').replaceWith('<%= escape_javascript( will_paginate(#products)) %>');
<% else %>
$('.pagination').remove();
<% end %>
the view
...
<p class="hero-description-dark local-nav-container">Sort by <%= link_to "popular", products_popular_path(:feed => "popular"), :remote => true, :class => "active"%> or <%= link_to "sale", products_sale_path(:feed => "sale"), :remote => true%></p>
Controller
def sale
products = Product.gender(current_user).available.includes(:likes)
#products = products.filter_by_categories(products).first(100).paginate(:page => params[:page], :per_page => 6)
#partial_name = "sale"
respond_to do |format|
format.html
format.json { render json: #products}
format.js
end
end
there is a missing <% end %> tag. I which that is not the problem. Try something like this:
<% if params[:feed].present? %>
$("#feed-content").html("<%= escape_javascript(render(:partial => "#{#partial_name}")) %>");
<% else %>
$('#products').append('<%= escape_javascript(render(:partial => 'sale_content', :products => #products, :remote => true)) %>');
<% if #products.next_page %>
$('.pagination').replaceWith('<%= escape_javascript( will_paginate(#products)) %>');
<% else %>
$('.pagination').remove();
<% end %>
<% end %>
I found a solution myself. I added ID's to my "remote true"-links like this. In this case "popular":
<p>Sort by <%= link_to "popular", products_popular_path(:feed => "popular"), :remote => true, :class => "active", :id => "popular"%>
Then in the corresponding popular.js.erb file I added an onclick event to the ajax that controls the tabs. This means that the ajax only runs when the link is clicked at not when the page is supposed to do the endless-scrolling part.
$("#popular").click(function() {
$("#feed-content").html("<%= escape_javascript(render(:partial => "#{#partial_name}")) %>");
});
$('#products').append('<%= escape_javascript(render(:partial => "#{#partial_name}")) %>');
<% if #products.next_page %>
$('.pagination').replaceWith('<%= escape_javascript( will_paginate(#products)) %>');
<% else %>
$('.pagination').remove();
<% end %>
There may be a better and cleaner way, but this worked for me. I have asked another question here that is almost the same as this one. Just if someone needs more details.
UPDATE:
The above solution required two clicks on link to render the partial. The code beneath should be used instead:
$('#popular').bind('ajax:complete', function() {
$("#feed-content").html("<%= escape_javascript(render(:partial => "popular_content")) %>");
});

Ajaxified Star Rating System is not Updating Correctly

I've implemented a Star Rating System using this tutorial http://eighty-b.tumblr.com/post/1569674815/creating-an-ajaxified-star-rating-system-in-rails-3
The Ajax works perfectly, until I add the Javascript that Submits the form/saves the data after a given user makes a change.
For some reason, it will loop through all the elements on my Index Page, and Submits the correct integer value on the selected object, but then submits a bunch of NIL values on the rest. I only want it to update that ONE object.
(How can I submit the appropriate Book ID in the Javascript?)
New to rails please help :)
VIEWS
index.hrml.erb (books)
<% #books.each do |book| %>
<table id="book<%= book.id %>">
<tbody>
<tr>
<td>
<b><%= book.title %></b>
</td>
</tr>
<tr>
<td>
<%= book.release %>
</td>
</tr>
<tr>
<td id="rating"> #####This is my partial for my form
<%= render :partial => 'ratings/rating', :locals =>{:book => book} %>
</td>
</tr>
<tbody>
</table>
<% end %>
_rating.html.erb
Avg. Rating <%= book.average_rating %>
<%= form_for rating_ballot, :html => { :class => 'rating_ballot' }, :remote => true do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label("value_1", content_tag(:span, '1'), {:class=>"rating", :id=>"1"}) %>
<%= radio_button_tag("rating[value]", 1, current_user_rating == 1, :class => 'rating_button') %>
<%= f.label("value_2", content_tag(:span, '2'), {:class=>"rating", :id=>"2"}) %>
<%= radio_button_tag("rating[value]", 2, current_user_rating == 2, :class => 'rating_button') %>
<%= f.label("value_3", content_tag(:span, '3'), {:class=>"rating", :id=>"3"}) %>
<%= radio_button_tag("rating[value]", 3, current_user_rating == 3, :class => 'rating_button') %>
<%= f.label("value_4", content_tag(:span, '4'), {:class=>"rating", :id=>"4"}) %>
<%= radio_button_tag("rating[value]", 4, current_user_rating == 4, :class => 'rating_button') %>
<%= f.label("value_5", content_tag(:span, '5'), {:class=>"rating", :id=>"5"}) %>
<%= radio_button_tag("rating[value]", 5, current_user_rating == 5, :class => 'rating_button') %>
<%= hidden_field_tag("book_id", book.id) %>
<%= f.submit "Submit", class: "btn btn-primary"%>
<% end %>
create.js.erb & update.js.erb
$('table#book<%= #book.id%> td#rating').html("<%= escape_javascript(render :partial => 'ratings/rating', :locals => {:book => #book}) %>");
JAVASCRIPT
rating_ballot.js
####This Submits the Radio Button, but Loops through every Book on the page.
$(document).ready(function() {
###Submits the form (saves data) after user makes a change.
$('.rating_ballot').change(function() {
$('.rating_ballot').submit();
});
});
CONTROLLER
class RatingsController < ApplicationController
before_filter :current_user, only: [:create, :update]
respond_to :html, :js
def create
#book = Book.find_by_id(params[:book_id])
#rating = Rating.create(params[:rating])
#rating.book_id = #book.id
#rating.user_id = current_user.id
if #rating.save
respond_to do |format|
format.js
format.html { redirect_to :back }
end
end
end
def update
#book = Book.find_by_id(params[:book_id])
#rating = current_user.ratings.find_by_book_id(#book_id)
if #rating.update_attributes(params[:rating])
respond_to do |format|
format.js
format.html { redirect_to :back }
end
end
end
end
This is bcoz all the rating forms are submitted whenever any single rating is changed
Change your JS code as follows
$(document).ready(function() {
$('.rating_button').change(function() {
$(this).parents('form:first').submit();
});
});
Also above code will not work in JS loaded content.
i.e. your rating form will not be submitted once you add rating and that form is updated from create.js.erb or update.js.erb
Change it to
$(document).ready(function() {
$(document).on('change', '.rating_button', function(){
$(this).parents('form:first').submit();
});
});

redirect_to causes template is missing error

I am making a transition from Rails 2 to Rails 3.
_role_item.html.erb view:
<% if #employee.has_role?(role.id) %>
<%= link_to image_tag('pman/checkbox_unchecked.jpg'), action: 'add_role', :employee_id => #employee.id, :role_id => role.id %>
<% end %>
Clicking the checkbox should assign a role to that Employee and redirect back to the partial page which contains a role_list and a privilege_list.
In my controller I have:
def add_role
#employee = Employee::OldEmployee.find(params[:employee_id])
#employee.add_role(params[:role_id])
redirect_to :action => 'employee_privileges', :employee_id => #employee.id
end
The view which has both partials, _employee_privileges.html.erb:
<h3> <%= #employee.full_name %> (<%= #employee.initials %>) <%= #assign_roles %> - PRIVILEGES & ACCESS</h3>
<br>
<table><tr><td valign=top>
<%= render :partial => 'role_list' %>
</td><td width=50>
</td><td valign=top>
<%= render :partial => 'privilege_list' %>
</td></tr></table>
<br>
employee_privileges.js.erb:
$("#roles").html("<%= j(render partial: 'employee_privileges') %>");
Function within controller:
def
employee_privileges
#employee = Employee::OldEmployee.find(params[:employee_id])
#roles = Acl::Role.find :all
#modules = Acl::Module.find :all
#module_privileges = Array.new
#general_privileges = Acl::Privilege.find :all, :conditions => 'module_id IS NULL'
if !#general_privileges.empty?
#module_privileges << [nil, nil, nil, #general_privileges]
end
#modules.each do |m|
if !m.privileges.empty?
#module_privileges << [m.id, m.name, m.description, m.privileges]
end
end
#assign_roles = flash[:assign_roles]
#render :partial => 'employee_privileges'
end
Currently, when clicking on the checkbox, I receive the error:
Missing template acl/acl/employee_privileges, application/employee_privileges with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in: * "/home/alex/Intranet_update/app/views"
Any help would be appreciated.
Please provide the relative path in the for the partial you want to render.
$("#roles").html("<%= j(render partial: 'employee_privileges') %>");
option like render partial: '/folder_path/employe_privileges'

Categories