Fancybox doesn't work when opened on a consecutive page - javascript

In my project I have apartments and groups of photos that belong to each of the apartment. On an apartment show page I want to create galleries using fancybox. When I open the show page fancybox doesn't work, though if I refresh this page everything works perfectly. As I understand jQuery is called only once when the website is loaded, but not called when just a new page is opened. To try to solve this I've put jQuery on the show page and use $(window).ready(function()), but it still doesn't work. Please help.
Here is my show.html.erb:
<script>
$(window).ready(function() {
$("a.gallery").fancybox({
'padding' : '0',
'cyclic' : true,
'hideOnContentClick' : true,
'transitionIn' : 'none',
'transitionOut' : 'none'
});
});
</script>
<% #pin.pics.each do |x| %>
<%= link_to image_tag(x.image.url(:thumb)),
x.image.url(:large),
:class => "gallery", :rel => "group#{x.pin_id}" %>
<% end %>
<p id="notice"><%= notice %></p>
<p>
<strong>Описание:</strong>
<%= #pin.description %>
</p>
<% if #pin.user == current_user %>
<%= link_to 'Редактировать', edit_pin_path(#pin) %> |
<% end %>
<%= link_to 'Назад', pins_path %>

Related

How to check policies for objects created through AJAX

In my program one Board can have many Sections. On Boards#show I list all Sections for this Board. A user can create, edit and delete Sections for Boards this user has created.
I use Pundit for my authorizations.
My problem is that after having added AJAX to the create Section action, my policy checks don't work anymore. The AJAX call is working fine in that Sections are added but the "Edit" and "Delete" links are only displayed after I reload the page.
Boards#show
<% if policy(#board).edit? %>
<p><strong>Create a new Section</strong></p>
<%= render 'sections/shared/form', board: #board, section: #section %>
<% end %>
<br>
<p><strong>Sections</strong></p>
<div id="sections">
<% #board.sections.order(id: :asc).each_with_index do |section, index| %>
<span><%= "#{index + 1}. #{section.title}" %></span>
<% if policy(section).edit? %>
<%= link_to "Edit", edit_board_section_path(#board, #board.sections[index]) %>
<% end %>
<% if policy(section).destroy? %>
<%= link_to("Delete", board_section_path(#board, #board.sections[index]), method: :delete) %>
<% end %>
<br>
<% end %>
</div>
Form partial
<%= simple_form_for([#board, #section], remote: true, authenticity_token: true) do |f| %>
<%= f.input :title, id: "section_title" %>
<%= f.submit "Save" %>
<% end %>
AJAX call
var newSection = "<span><%= "#{#board.sections.length}. #{#section.title}" %></span><br>";
var sections = document.getElementById('sections');
sections.insertAdjacentHTML('beforeend', newSection);
var sectionTitle = document.getElementById('section_title');
sectionTitle.value = '';
I think the problem is that the newly created Section isn't inserted into the loop and thus the policy cannot be checked. How could I refactor my code to solve this?
You should be able to render you HTML templates into your js.erb file. See the post from the DHH https://signalvnoise.com/posts/3697-server-generated-javascript-responses how to use this properly. It is an older post so maybe some things changed but you should know what to search for. But if it still works this way, you should be able to do something like this:
Extract section to a partial _section.html.erb
<span><%= "#{index + 1}. #{section.title}" %></span>
<% if policy(section).edit? %>
<%= link_to "Edit", edit_board_section_path(#board, #board.sections[index]) %>
<% end %>
<% if policy(section).destroy? %>
<%= link_to("Delete", board_section_path(#board, #board.sections[index]), method: :delete) %>
<% end %>
<br>
Use this partial also in your Boards#show file.
Render your partial in the js.erb file
var newSection = "<span><%=j render #section %></span><br>";
Something like this should work, but I don't use server generated javascripts so they could have changed some things. But hopefully it will help you at least with the direction.

Why does jQuery only enter the function in some links?

I am relatively new to jQuery and JavaScript, so I'm having this issue, hope you can help me through it.
I am making an e-commerce page for selling cloths in Rails 4, so I am focusing more than I used to in the form of displaying forms and all of that, so it can be more attractive to the users. Because of that, I have the forms hidden and I set the values to it via jQuery.
The problem can be divided in two parts:
The first part of the problem is in the cloths#show where the user add the cloth to his cart:
Form:
<%= form_for #order_item, remote: true do |f| %>
<h5>Select a size</h5>
<div class="input-sizes">
<% #sis.each do |si| %>
<%= link_to si.size.letter, "#{si.size_id}", class:"normal-size" %>
<% end %>
</div>
<%= f.hidden_field :size_id, id: "size-input" %>
<h5>Select a color</h5>
<div class="input-colors">
<% #cos.each do |co| %>
<%= link_to "#{co.color_id}", id: "link-circle" do %>
<div id="circle" style="background: <%= co.color.hex %>">
<div id="mini-circle"></div>
</div>
<% end %>
<% end %>
</div>
<%= f.hidden_field :color_id, id: "color-input" %>
...
<% end %>
jQuery:
//Select size
$('a.normal-size').on('click', function(e){
e.preventDefault();
var value = $(this).attr("href");
$('#size-input').val(value);
$(this).removeClass("normal-size").addClass("selected").siblings().removeClass("selected").addClass("normal-size");
});
//Select Color
$('#link-circle').on('click',function(e){
e.preventDefault();
var value = $(this).attr("href");
$('#color-input').val(value);
$(this).children().children().css('opacity', '1');
return false;
});
The set of the size input works perfectly but in the color input the user only can select the first color because if the user wants to select the second, the jQuery function doesn't gets called so it goes to the link (I tried even writing e.preventDefault() and return false at the same time).
The second part of the problem comes in the cart#show when the user can see the summary of all his cloths. In this it is displayed a table with each row being a cloth, here the user can see the image of the cloth, description, selected color, selected size and price. The color and size section is made for the user so he can edit his cloth if he changes his mind and select another size or color. The issue in here is in both size and color and I don't know why. In the color section happens exactly the same as above, but in the size section he can only make one click because if he makes another one the jQuery function doesn't get called. Is like if the click only works once:
Form:
<%= form_for (order_item), remote: true,:url => "/order_items/#{order_item.id}", :html=>{:id=>'item_form_cart'} do |f| %>
<div class="input-colors col-md-1">
<% #cos.each do |co| %>
<% if co.cloth == order_item.cloth %>
<% if co.color_id == order_item.color_id %>
<%= link_to "#{co.color_id}", id: "link-circle" do %>
<div id="circle" style="background: <%= co.color.hex %>;">
<div id="mini-circle" style="opacity: 1;"></div>
</div>
<% end %>
<% else %>
<%= link_to "#{co.color_id}", id: "link-circle" do %>
<div id="circle" style="background: <%= co.color.hex %>;">
<div id="mini-circle"></div>
</div>
<% end %>
<% end %>
<% end %>
<% end %>
</div>
<%= f.hidden_field :color_id, id: "color-input" %>
<div class="input-sizes col-md-2">
<% #sis.each do |si| %>
<% if si.cloth == order_item.cloth %>
<% if order_item.size_id == si.size_id %>
<%= link_to si.size.letter, "#{si.size_id}", class:"selected" %>
<% else %>
<%= link_to si.size.letter, "#{si.size_id}", class:"normal-size cart-el" %>
<% end %>
<% end %>
<% end %>
</div>
<%= f.hidden_field :size_id, id: "size-input-cart" %>
...
<% end %>
jQuery:
//Select size
$('a.normal-size.cart-el').on('click',function(e){
e.preventDefault();
var value = $(this).attr("href");
$(this).parent().next('#size-input-cart').val(value);
$(this).removeClass("normal-size").addClass("selected").siblings().removeClass("selected").addClass("normal-size");
$(this).closest('#item_form_cart').submit();
});
In here I only make the size function because I didn't know how to fix the color one, but this also has a bug, that only gets called the first time. This happens no matter which cloth's size you select, e.i. if I change the first cloth's size works good but if I want to change again the same cloth's size or change the size of another cloth the jQuery function doesn't get called.
Hope you can help me,
Thanks in advance.
Edit:
I have investigated more about why is happening the second problem and I saw that it can be related to Ajax, because in my form if a user changes the size or color it gets done by Ajax, as we can see here. I tried the second solution but it did not work:
$('.well').on('click','a.normal-size.cart-el',function(e){
e.preventDefault();
var value = $(this).attr("href");
$(this).parent().next('#size-input-cart').val(value);
$(this).removeClass("normal-size").addClass("selected").siblings().removeClass("selected").addClass("normal-size");
$(this).closest('#item_form_cart').submit();
});
$('.well').on('click','.link-circle.cart-el',function(e){
e.preventDefault();
var value = $(this).attr("href");
$(this).parent().next('#color-input-cart').val(value);
$(this).siblings().children().children().css('opacity', '0');
$(this).children().children().css('opacity', '1');
$(this).closest('#item_form_cart').submit();
});
And here is render each item in the view:
<div class="order_items">
<% #order_items.each do |order_item| %>
<div class = "well">
<%= render 'carts/cart_row', cloth: order_item.cloth, order_item: order_item, show_total: true %>
</div>
<% end %>
</div>
Your select color function is attached to the id "link-circle". It looks like you're potentially rendering multiple elements with the same id. Your select size function is based on a class which you can have on multiple elements. You cannot however have the same id on multiple elements according to w3 . Try changing "link-circle" to a class like so..
<%= link_to "#{co.color_id}", class: "link-circle" do %>
and the your selector to..
$('.link-circle').on('click',function(e){

Braintree Drop-In UI requires reload to work properly

I'm just getting started with the Braintree drop-in UI. Client side is javascript, server side is ruby on rails.
My system is very simple right now. The user is given a list of invoices that pertain to them. When the invoices have not yet been paid, they can click 'pay' and be taken to a new page that includes the Braintree Drop-In UI. My issue is this: When the user is taken to the 'pay' page, the drop-in UI does not appear. If the user reloads the page, the drop-in UI appears.
Why?
Here's some relevant code. It's pretty vanilla and not done yet - just roughed in.
From invoices/index.html.erb
<td>
<% if invoice.paid %>
<%= 'Paid' %>
<% else %>
<%= link_to 'Pay', payment_path(invoice.id) %>
<% end %>
</td>
From payments_controller:
class PaymentsController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :set_invoice, only: [:pay, :checkout]
def pay
Braintree::Configuration.environment = :sandbox
Braintree::Configuration.merchant_id = 'merchant id'
Braintree::Configuration.public_key = 'public key'
Braintree::Configuration.private_key = 'private key'
gon.client_token = Braintree::ClientToken.generate()
end
def checkout
nonce = params[:payment_method_nonce]
result = Braintree::Transaction.sale :amount => #invoice.amount, :payment_method_nonce => "nonce-from-the-client"
if result.success?
message='Payment processed successfully. Thank you!'
#invoice.paid=true
#invoice.save
else
message='Unable to process payment. Reason = ' + result.message
end
redirect_to invoices_path, notice: message
end
private
def set_invoice
#invoice = Invoice.find(params[:id])
end
end
pay.html.erb:
<h1>Payments</h1>
<div>
<p>Invoice #: <%= #invoice.id %></p>
<p>Date: <%= #invoice.date %> </p>
<p>Description: <%= #invoice.description %> </p>
<p>Amount: <%= #invoice.amount %> </p>
</div>
<div class="form-container radius-box glassy-bg small-10 small-centered medium-8 large-6 columns">
<h2 class="mbs">New Transaction</h2>
<%= form_tag payments_checkout_path do%>
<%= hidden_field_tag 'id', #invoice.id %>
<p>Please enter your payment details:</p>
<div id="dropin"></div>
<%=submit_tag "Pay #{#invoice.amount}$", class: "button mt1" %>
<%end%>
</div>
and layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Actionable Software</title>
<%= include_gon %>
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<script src="https://js.braintreegateway.com/v2/braintree.js"></script>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
</head>
<body>
<%= render 'layouts/header' %>
<div class='container'>
<% flash.each do |name, msg| %>
<%= content_tag(:div, msg, class: "alert alert-info") %>
<% end %>
<%= yield %>
</div>
</body>
</html>
I'm going to guess the script that populates that element isn't written in a way that works with Turbolinks.
Try opting that page or section out of turbolinks. Or just disable it completely and see if it fixes it.
I ran into the same issue in my app.. change on your index page
<%= link_to 'Pay', payment_path(invoice.id) %>
to
<%= link_to 'Pay', payment_path(invoice.id), data: { no_turbolink: true } %>
This should force the pay page to load completeley when you click through.

Tinymce gem, Have to press reload to make tinymce toolbar available

I'm using this guideline to setup tinymce in rails
https://github.com/spohlenz/tinymce-rails
but I have small problem, each time I open page that has tinymce editor, the the text area that has tinymce attached shown blank
I have to reload / refresh the browser to make it available.
is there any tips to fix this
(I'm using rails 4)
thank you.
tinymce.yml
menubar: false
toolbar:
- styleselect | bold italic | undo redo | table
plugins:
- table
news.html.erb
<%= tinymce_assets %>
<%= form_for #news do |f| %>
<%= render 'common/form_errors', object: #news %>
<p>
<%= f.label :isi %><br>
<%= f.text_area :isi, :class => "tinymce", :rows => 7, :cols => 50 %>
<%= tinymce :content_css => asset_path('application.css') %>
</p>
<div class="form-action">
<%= f.submit nil, :class => 'btn btn-primary' %>
</div>
<% end %>
I think I just fixed the issue, it's because of turbolink
so for every link that point to the page that has tinymce attached
I disable turbolink by this option 'data-no-turbolink' => true
<%= link_to "Create News", new_news_path, 'data-no-turbolink' => true %>
Another alternative could be this:
$(document).on('ready page:load', function () {
tinymce.remove();
tinymce.init({selector:'textarea'});
});

How to add link to Magnific Popup's javascript

I have the magnific popup on my app and I need help with adding a action to the lightbox. I have added my code to the javascript and outside of it but it never appears inside the lightbox.
I need to add several pieces to the lighbox such as a link that will allow user to make ProfileImage, messages compose box, and short bio of the user. If I can learn how to do one then I am confident I can do the rest.
The action is <%= button_to('Set as Profile Image', [:avatar, #photo]) %>
show.html.erb:
<h1><%= #user.username %></h1>
<script type="text/javascript">
$(document).ready(function() {
$('.parent-container').magnificPopup({
delegate: 'a',
type: 'image',
gallery:{enabled:true}
});
});
</script>
<div class="parent-container">
<% #user.photos.each do |photo| %>
<%= link_to image_tag(photo.image_url(:thumb)), photo.image_url%>
<% end %></div></p>
Tell Magnific Popup to open inline content (a div with the image and your extra content), e.g.:
<script>
$(document).ready(function () {
$('.parent-container').magnificPopup({
delegate: 'a',
type: 'inline',
gallery: { enabled: true }
});
});
</script>
<div class="parent-container">
<% #user.photos.each do |photo| %>
<%= link_to image_tag(photo.image_url(:thumb)), "#" + dom_id(photo) %>
<div id="<%= dom_id(photo) %>" class="mfp-hide">
<%= image_tag(photo.image_url) %>
<%= button_to('Set as Profile Image', [:avatar, #photo]) %>
</div>
<% end %>
</div>
You will need to style the popup; the documentation link above has some sample CSS.
(Apologies if the Ruby code is broken; I'm not really a RoR person.)
According to the magnific popup documentation, you can load anything you want into the popup (I thought it might have been an image-only "lightbox" plugin)
This means if you place the code you need in your popup div, you should be able to do what you want with it:
<div class="parent-container">
<% #user.photos.each do |photo| %>
<%= link_to image_tag(photo.image_url(:thumb)), photo.image_url%>
<%= button_to('Set as Profile Image', profile_path(photo)) %>
<% end %>
</div>

Categories

Resources