I have a checkout popup I would like to share between different pages (event, video meeting ...), so I thunk creating a shaded element /views/shared/_checkout.html.erb, and insert <%= render "shared/checkout" %> in my pages.
Uncaught ReferenceError: popup_payment is not defined
All the html and javascript is this shared page.
I just can't understand why from my pages (event, video ...) I can not call the javascript from this shared component.
the html and the javascript is present when I check the source. I was excepting that render / render partial was acting some code injection, am I wrong ?
How could I preserve the DRY - Don't repeat Yourself - in ERB ?
And have the elements / javascript communicate betweek page and included javascript ?
Here is some pseudo code example :
pageA.html.erb
<%= link_to image_tag('pinandchip.png', size: '18x18'), '#', onclick: 'popup_payment();', class: "btn flat" %>
...
view/shared/_popup.html.erb
<script>
function popup_payment() {
}
</script>
You could try adding the class payment-popup-button to your button and create a new file in app/assets/javascripts/shared called popup.js.
In that file you can do something like:
$(document).ready(function(){
$('payment-popup-button').click(function(e){
e.preventDefault();
$('#popup_payment_div').show();
});
});
This assumes that you're using jQuery, and that you've already rendered the popup code somewhere on the page, but it's hidden.
If you need to render a fresh form every time or populate the form with dynamic data you'll probably have to create controller actions that respond_to and render js.erb to get you the right markup.
It's hard to say exactly without seeing more code.
Are you ensure that your javascript function is loaded in all pages?
On this question answer how to have global javascript functions on rails projects.
i found a solution with this gem :
https://github.com/komposable/komponent
it fulfill my needs : create external components
Related
below is code in file 'app_erb.js.erb'
$(function(){
$('.add_more_element').click(function(e){
e.preventDefault();
$(this).siblings('.remove_this_element').show('slow');
$(this).hide('slow');
$(this).closest('.form-group').add('<%=j render 'resumes/resume_certification' %>');
});
});
and i have partial views/resumes/_resume_certification.html.erb
but when i load my app it gives me
NoMethodError at /resumes/new
undefined method `render'.
What i am missing in the whole process for rendering a partial using javascript.
JS
I believe the problem you have is that you're trying to load an ERB / Rails method from your asset pipeline.
Although the documentation does say you can use ERB preprocessing in your asset pipeline, it is scant on how to implement this feature:
The asset pipeline provides a framework to concatenate and minify or
compress JavaScript and CSS assets. It also adds the ability to write
these assets in other languages and pre-processors such as
CoffeeScript, Sass and ERB.
It's my understanding that including ERB / Rails code directly in your asset pipeline is a no-no because of the dynamic complexities it brings (at least that's been my experience). Instead, you'll want to keep your JS as "native" as possible
--
Ajax
Secondly, you have to realize something very important - Javascript is front-end. It's designed to bind events to your DOM elements, and does not interact with the Rails back-end directly.
As such, you're going to need to use AJAX to pull the data you need from the server:
#config/routes.rb
resources :resumes do
collection do
get :resume_certification
end
end
#app/controllers/resumes_controller.rb
Class ResumesController < ApplicationController
def resume_certification
render "resumes/resume_certification"
end
end
#app/assets/javascripts/app.js
$(function(){
$(document).on("click", ".add_more_element", function(e){
e.preventDefault();
$(this).siblings('.remove_this_element').show('slow');
$(this).hide('slow');
$.get( "resumes/resume_clarification", function( data ) {
$(this).closest('.form-group').add(data);
});
});
});
The best option I see is to avoid loading the partial directly into a string, but to load said page trough ajax (that would also avoid you loading said partial without using it until the function is called!)
$(function(){
$('.add_more_element').click(function(e){
e.preventDefault();
el = $(this);
el.siblings('.remove_this_element').show('slow');
el.hide('slow');
$.get("<%= resume_certification_path %>", function(data) {
el.closest('.form-group').add(data);
});
});
});
I replaced the $(this) with a new var to avoid messes inside the ajax call. Obviously this solution requires you to create a new get route, and set
render :layout => false
inside the new action you'll use to render that partial.
I have a Rails app that uses javascript (Backbone) to show user specific data on each users profile page /views/users/show.html.erb. I do this by passing <%= #user.id %> as a data parameter to Backbone's fetch function, however, the only way I know how to get the <%= #user.id %> into Backbone's fetch function is by embedding the javascript in each views/users/show.html.erb page, which therefore allows Backbone to load different user specific info for each views/users/show.html.erb page. Although this works, it seems like the wrong way to do it, as I have read that I should not embed javascript like this. Furthermore, I am going to have to do it a lot, because I wish to display a lot of different kinds of data, more than you see below. So the show.html.erb page will be filled with javascript to make the app work the way I wish.
Question: how might I get #user.id into Backbone's fetch function for each user's show page without embedding javascript in the way that I've done. In the comments, someone suggest I use app/assets/javascripts/user.js, but I don't know how to get <%= #user.id %> into that file. #user.id is readily available in show.html.erb
<script type='text/javascript'>
$(document).ready(function() {
app.collections.awardCollection.fetch({ data: $.param({ user_id: <%= #user.id %> }) }).complete(function(){
app.views.awardCollection = new app.Views.awardCollection({ collection : app.collections.awardCollection});
app.views.awardCollection.render()
});
});
</script>
In order to understand how the views works, is that you can add as many extensions to a view as you want, and they will be parsed by the right library.
If you create a view like
my_view.haml.erb
It will be first parsed with ruby (erb), and then with haml, and will end in a html page.
You can create many views for js, usually you want to archive that when you do ajax, so you can end having a js view like:
my_view.js.erb
First ruby will be parsed (all the <% %> tags), that will end as plain text, and then the server will serve the .js file. But that's usually a common task for ajax.
If you have to render a html page where you want to put some js and you need some ruby code on it, what I usually do is to put the data in the html content with a hidden div.
You can put in any view (even on your layout if you want it to be globally available), something like:
<div id="user_id" style="display: none;"><%= #user.id %></div>
And then on a js (or coffeescript or whatever) you can just check the content of that div:
<script type="text/javascript">
var user_id = $("#user_id").html();
</div>
that's really useful when you want to debug or create tests for your js files, since its plain js and won't throw syntax errors.
I see the comment of Luís Ramalho and Gon is a good option, but I recommend use the following approaches:
If the from the variable is not going to change, print it with <%= %> under .js.erb files located in app/assets/javascripts (note that it will be cached until you restart your app)
If you need server variables the best way is to use Ajax
You can define functions on .js files on app/assets/javascripts and call those functions from the views
If you really don't want any Javascript code in the view, you can create the functions on a .js on app/assets/javascripts (corresponding to the view, for order), and use events and/or store the variables in hidden fields (or even use the data attribute from HTML5)
I'm currently ajaxifying my Rails app as follows.
JS
application.js
$("a").live("click", function() {
$.getScript(this.href);
//do something
return false;
});
Views
index.js.erb
$("#core").html("<%= escape_javascript(render 'index') %>");
index.html.erb
<%= render 'index' %>
_index.html.erb
#my partial
So when a user clicks a link, it will be intercepted and the corresponding js file will be executed, which renders a partial in a div. This means that, for each action, I will need 3 views, say index.js.erb, _index.html.erb, and index.html.erb.
This is painstaking to set up, and the index.html.erb file is somewhat useless, it just renders the partial (perhaps there's a way to render a full view from another view directly, hence eliminating the need for a partial?).
Is this the best way to do things? How do you usually imbricate Ajax with Rails?
Thanks.
Javascript MVC seems like it works well with MVC style backends. It standardizes ajax calls, controllers and views in a similar way that you are showing above:
http://javascriptmvc.com/
I am learning Ruby on Rails, and I am very confused on how the controller-model-view relationship works for my application.
What I have now is a table full of comments (posts) users have made. What I want to do is let users click on a comment to see more information in a separate panel (ie, other database fields that weren't initially shown, for example the user_id of the person who posted the comment).
In my _post.html.erb, I have something like:
<div class="post" id="<%= post.post_id %>" onclick = ?? >
<p>post.text</p></div>
What should go in onclick? I need a way for the onclick to call a helper/controller method which can load more information, and then put that in another div on a page (I've tried variations of using the controller and helper to call javascript which inserts html into the site, but that seems messier than it should be). From what I understand, I should create some kind of partial _postdetails.html.erb file that handles the actual displaying of the html, but I have no idea how to specific where that partial would go in the page.
Any help would be appreciated, thanks!
You can achieve what you want either by using Rails helpers or by writing the AJAX calls yourself.
Personally I manually write all my AJAX calls using jQuery.
You can also use Prototype which ships with Rails.
That being said you can do.
In your JS file :
$("div.some-class").click(function()
{
$.ajax(
{
url:"url/to/controller/action",
type:<GET>/<POST>,
data://If you wish to sent any payload
});
});
In your controller :
def some_action
#some computation
render :update do |page|
page["id_of_div_to_be_refreshed"].replace_html :partial => "some_partial"
end
end
I have a menu control on Index page rendered as <% Html.RenderPartial("MenuUserControl"); %> where MenuUserControl is something like
<li><%= Html.ActionLink("Link1","Index") %></li>
<li><%= Html.ActionLink("Link2", "Index")%></li>
<li><%= Html.ActionLink("Link3", "Index")%></li>
Now I wan to load three different form in Index page itself onclick of these links, with first form being loaded on Page load. How can I do this. Any help is appreciated.
If you need to pass information about links to RenderPartial
<% Html.RenderPartial("MenuUserControl", new[]{"link", "link"}); %>
however it's better to pass a custom model (class object) rather than array of strings.
Use Ajax.ActionLink to load form without page reload.
To load first form either do this in the Index page itself (add HTML tags or call RenderPartial to render form, or use RenderAction), or add script to the menu partial like this
<script type="text/javascript">
$(function(){ $("a").eq(0).click(); }
</script>
This requires jQuery, though.
If you don't know what I'm talking about then you better prepare to learn a lot.
You will need some sort of JavaScript library like jQuery to do this, the rest is imagination:
-You can pre-load the 3 forms on pageload and then hide the last two on DOM ready (PageLoad). i ll wrap this in div just for convenience.
<script type="text/javascript">
$(document).ready(function () { //This is like DOM ready
//here we hide the the last 2 forms
$('#div_id_form2').hide();
$('#div_id_form3').hide();
//Next set the events for the links (on click show form)
//on link 2 click
$('#link2').click(function(){
//show the second form
$('#div_id_form2').show();
});
//on link 3 click
$('#link3').click(function(){
//show the third form
$('#div_id_form3').show();
});
});
</script>
The other option is go the Ajax way but requires more code and knowledge in jQuery.
If you are interested refer to http://docs.jquery.com/ thats the API reference for jQuery.
If you are moving to MVC, I recomend you to learn any JavaScript library to help you with this kind of behaviors that some call DHMTL (Dynamic HTML).
First do the Non Ajax Version.
Have 1 page Index with 3 partials in it. Each partial has only the html for the form to display in it.
In your actions set the ViewModel (here Action Link1)
model.IsForm1Visible = true;
In your View use the model to display partials
<div id="linkContainer">
<% if(Model.IsForm1Visible){%>
<%= Html.RenderPartial("Form1")%>
<%}%>
<% if(Model.IsForm2Visible){%>
<%= Html.RenderPartial("Form2")%>
<%}%>
<% if(Model.IsForm3Visible){%>
<%= Html.RenderPartial("Form3")%>
<%}%>
</div>
If you need Ajax you can continue from there.