I'm curious how Rails 5 renders partials and if there's a gotcha that I'm not aware of. I have two partials on my page, one that is rendered as part of the html and the other that renders inside the success callback of an ajax request. However, when I refresh the page, the partial inside the ajax request is actually being rendered even when the ajax request is not fired, and EVEN when the call to render the partial is commented out.
I had always assumed that partials render at the time the line of code is run.
Here is the relevant code:
$('body').on("click", ".notif-popup-container", function() {
$.post(
"/notifications/read",
{ notif_id: notifId },
).done(function(data) {
$('#notifUnreadCount').html(data.unread_notifs);
var popover = $('#notificationsBell').data('bs.popover');
popover.config.content = $('.notifications-list').html();
})
$('.notifications-list').html("<%= j (render partial: 'notifications/partials/test_partial') %>"); // this never fails to render, even when commented out
})
<div style="display:none" class="notifications-list">
<%= render 'notifications/partials/popover_notifications' %>
</div>
Here is the console output image. As you can see _popover_notifications.html.erb renders as it should, but then my _test_partial.html.erb also renders, which it shouldn't, since the click handler it's in was not fired.
Any insight appreciated.
I had always assumed that partials render at the time the line of code is run.
The key here is understanding when the code is run. When you dynamically create javascript with js.erb the file is first run through ERB on the server before it is sent to the client which runs the resulting javascript. Your server does not actually parse the javascript so it does not know or care that there is a event handler involved. To Rails its just a string buffer.
This is actually a major conceptual problem with js.erb templates as the context switching between server and client side makes the flow hard to follow.
There are also numerous other problems with this code like the use of the === identity operator and the fact that your performing DB queries in the view which is a huge anti-pattern.
Related
I am doing an HTTP request against a remote API in my controller such as this:
#results= JSON.load(open("http://someendpoint/whatever.json"))
I am then rendering the contents of the response in my view by iterating over the structure provided in the response:
<% #results['result'].each do |result| %>$
This works 100% fine from a technical standpoint. The problem is that the initial JSON load in the controller appears to block the controller's thread (prior to rendering the page). There is additional information on the page that I would like to load quickly (i.e. without the controller thread blocking). Basically what I'd like to do is make the HTTP request asynchronously, and then render the JSON structure via callback. I can put the information in a partial if that would make things easier.
I can definitely use something like an XMLHttpRequest to concatenating the results of this (with interpolated HTML elements) into a string, and then just using DOM insertion methods to place the data into the view. So, I suppose my questions are this:
Is there a good way to do this asynchronously, for example by using a Javascript a callback to render a partial from a variable declared in an XMLHttpRequest? Is it bad to declare variables in the view and then render them in a partial? This just seems like bad design to me. I basically don't want to generate a long HTML string after an XHR request and inject it into the DOM because it seems 'sloppy'.
I appreciate your help.
Would it not be simpler to put #results in it's own controller action with it's own endpoint and load it via AJAX?
I'm confused about ajax request in rails.
I'm submitting a form using ajax and everything was fine. Now I must handle callback, but...
Following some tutorials the hint is to add a
respond_to do |format|
format.js
end
to controler#create and then place in the views folder a "create.js.erb" with the response.
Other tutorials suggest to create a js file in the assets folder and handle the callback from the JS file.
What's the difference? And what's the right way?
Both are different ways for handling callback of Ajax request. I suggest you to use js.erb file to handle ajax callback because this file can recognize the both JS as well as Ruby code and execute.
For example,
in your controller,
def create
...
if something
#foo = true
else
#foo = false
end
in your create.js.erb, it can be done like you want to show/hide some div based on the #foo value, you can write like,
<% if #foo %>
// do something with JS code
<% else %>
// do something else
<% end %>
While if you create a JS file in assets folder then you will not be able to write condition like above because it is a pure JS file and creating js.erb is an easy way to handle ajax response.
They are two very different approaches. For example, assume that all you want to do is display a message confirming the user's submission. If you go down the create.js.erb route then that file might look something like
$('#message').text('<%= j #message %>')
The response to your ajax request is a bit of javascript that does the required changes to the ui. jQuery executes that javascript when it receives it and your javascript doesn't have any visibility into what the response might do.
The other approach would be for your controller just to render some data. This could either be some JSON describing the results of the submission, or a block of html. For example your controller might do
render json: {status: 'success', message: 'Thank you for your submission'}
The javascript making the xhr might look like
$.ajax('/some_url', {dataType: 'json'}).done(function(data){
//data is the json your controller sent
$('#message').text data.message
});
or if you were rendering html
$.ajax('/some_url', {dataType: 'html'}).done(function(data){
//data is the html your controller sent
$('#message').html data
});
So in this case it's your javascript that decides what to do with the returned data.
Personally I dislike the create.js.erb route - I find it makes my javascript harder to read: I can't tell from looking at my form submission code what can/may happen in this callback.
It's also much harder to test if controllers are producing a blob of something that needs to be executed in a different language and its much harder to test your javascript if there are places where it executes arbitrary code sent to it.
I much prefer it behaving like an api, returning structured data, that the client can act appropriately on (the client might not even be a browser all the time, it could be a mobile app).
I have a page I want to load that has sections that are making API calls. I don't the page to wait to load until those are done. I would like the page to load and then the other sections to appear after they are finished.
Right now, this is what I have but it's not getting the results I want and even with this it's still waiting for a lot to process and not loading the page first, even though it seems like it should be.
<script>
$(window).load(function(){
$(".my-div").append('<%= my_function %>');
});
</script>
Assets
Don't use erb code in your asset pipeline
Including that code in your layout or view will be okay, but if you're including in app/assets/javascripts/any_file.js, it won't work
ERB code can only be processed by js in views folders (mainly because of the precompile process of the asset pipeline)
Appending
As pointed out in the comments, you'd be better waiting until the document has loaded, like this:
$(document).ready(function() {
//your code
});
However, if you're using turbolinks, you'd be better using something like this:
var load = function() {
//append code here
};
$(document).ready(load);
$(document).on('page:load', load);
Functionality
Curiously, you've omitted one of the most important aspects of your code -- how you're retrieving the data. If you can reply with your asynchronous function, it will be a great help!
I have a Ruby method nested inside a jQuery onclick event and I want the method to execute when the div is clicked. This works; however, the method is also executing on page refresh. Why does it also execute on page refresh and is there any way to limit it to only onclick?
$(function() {
$('.myDiv').click(function(){
<% foo_bar %>
});
});
I don't see how foo_bar can be executed when you click on the div. Ruby is executed server side, jQuery is executed client side. You cannot execute ruby code from your client.
Your foo_bar is executed on refresh page because the server need to interpret it to give it's result into the <% %> tag. However, when you click on the div, nothing will happen because the jquery function will be empty (since you did not write <%= %>). Even if you wrote <%= %>, the jQuery would only execute the foo_bar result, not the function itself.
Maybe you could explain what you want to do in your foo_bar. If you want interact with the server, you will need something like Ajax.
Please review this blog entry I wrote. In short, the ruby code executes on the server, and the javascript, which runs on the client, sees nothing. To have javascript interact with ruby, you need to initiate a request back to the server via some kind of ajax request. Libraries like jquery help with this.
Please tell me if we can call java inside javascript function ?
<HTML><HEAD></HEAD><BODY>
<SCRIPT>
function getScreenDimension() {
<% System.out.println("Hiiiiiiiii"); %>
}
</SCRIPT>
<FORM>
<INPUT type="button" value="call Java method direct" onClick = "getScreenDimension()">
</FORM>
</BODY></HTML>
While the answer of "No" is technically correct based on the phrasing of the question. You may want to read up on AJAX. It is a way for javascript to make a request to your backend code (in this case Java).
Javascript is client side, meaning it is run by the user's browser. Java is running on your server. In order for the client side javascript to interact with the backend Java, you need to make a request to the server.
My question to you would be, "What are you trying to do, and what do you expect to see?".
You have to realize that there are two different execution contexts. The first is the JSP itself whose code is executed by the JVM on the server-side, and the second is the Javascript that is executed by the browser. So when the code goes to the browser, you'll see: So the System.out.println will cause Hiiiiiiiii to be printed to the server logs, but you won't see anything on the browser. In fact, the Javascript code on the browser will look like this:
function getScreenDimension() {
}
Which is not valid Javascript code. The code in the JSP is run before the Javascript gets run on the browser. So to "run" Java code, you need to make a request to your server either by posting the form or with an AJAX call. This will cause Java code in the appropriate servlet or controller, to run.
UPDATE
After glancing at your code, it appears that you want to call a Java method directly. This is not possible with your current code. You might want to read up on AJAX. This will point you in the right direction.
JSP runs on the server. It generates a document which the server sends to the browser. That is the end of the involvement of JSP in the process. The browser then parses the document and runs any JS.
You can include JSP in a script element, it just has to output valid JavaScript.
You cannot have JSP that runs in response to JavaScript, other then when JavaScript causes the browser to issue a new HTTP request (either setting location.href, submitting a form, adding an image, or using Ajax, etc)
I think you have lack of understanding of what is going on here. Anything in middle of <% %> is executed when the page is first requested. Anything in javascript is executed when the browser calls it. What you have will never happen and there is no way to make it happen. However, you can use AJAX to do something like this but that's a different question.
Yes, you can. Use JSP expressions <%= %>. Example:
<aui:script use="aui-datepicker">
AUI().use('aui-datepicker', function(A) {
new A.DatePickerSelect({
calendar : {
dates : [ '<%="1/1/1970" %>' ],
}
}).render('#myDatePicker');
});
</aui:script>
Yes, you can call Java from Javascript, both if you mean the Java-VM on the server and on the client; i assume you mean the client (the VM in the browser); take a look here:
http://www.apl.jhu.edu/~hall/java/Java-from-JavaScript.html
You can. In JSF you can use PrimeFaces' component p:remoteCommand, which would contain action method. Call that remoteCommand by its name from JS and the java method will get executed.
JSF Page
<p:remoteCommand name='rmt' action="#{bean.doWork()}"/>
In JavaScript
function callJava {rmt();}
Use JSP code
<%
// Respond to the application with 1) result, 2) update, and 3) updateid values
String result = "blablabla";
out.print(result);
%>