another day, another night spent banging my head over JS and JQuery.
I want to call a page via HTML (and show the route in the header), but have it also load a js.erb script. Or alternatively, I want to call the js.erb script remotely, but also change the http header to indicate the new route.
I want this because:
a) I want to learn and this is frustrating me
b) currently, when the user refreshes, his current page doesn't come up, but the one from which the remote => true call came in;; it's confusing for the user to go back to a page he doesn't remember.
I'm implementing the JQuery.pageless plugin. I call the user/show page remotely and this is what goes into my show.js.erb file:
$(function(){
$("#container").html("<%= escape_javascript(render '/users/show') %>");
$('#relationship_list').pageless({ totalPages: "<%= #reviews.count %>"/5+1
, url: '/reviews'
, params: {id: "<%= params[:id] %>"}
, loaderMsg: "loading"
});
});
Now this code is A-OK. it works when called remotely from show.js.erb. The problem is that I want to load the "user show" page via html, and not remotely. That means that this script doesn't get loaded. I need to find another, unobtrusive way to load it.
I want to reiterate: there is no bug in the code.
Hopefully someone can help. Also please note: someone wrote about using the gon gem to address the issue. Not for me - I really want to figure this out without gems.
It sounds like you have the page load working via a remote call (I'm assuming an AJAX GET request after clicking a link or button), which works properly, but the URL doesn't update in the address bar?
You're looking for the HTML5 pushState() method.
Update your show.js.erb file like so:
$("#container").html("<%= escape_javascript(render '/users/show') %>");
history.pushState(null, "Page Title", "<%= user_path(#user) %>");
Related
First of all, sorry for the lame question (probably). I tried to search for an answer but I'm not finding everything I need for my issue.
So... I have a bootstrap website and I am trying to change the page URLS to appear like this :
For example : www.site.com/AboutUs.html - to appear as www.site.com/about-us
I am using the pushState method for this as it follows:
var stateObj = { AboutUs: "about-us" };
history.pushState(stateObj, "About Us", "about-us");
So I get the needed URL address there (www.site.com/about-us).. so far so good. But on page refresh it throws an error stating "The requested URL /about-us was not found on this server."
If I hit the back browser button it goes to www.site.com/AboutUs.html again.(and it is supposed to go on the home page)
My question is :
What am I missing, am I supposed to make a controller and how ?
I am not using C#, I can probably use some help with PHP because I am not good at it. JavaScript / jQuery are welcomed.
Thanks in advance and sorry for the dumb question.
Happy days!
The point of pushState is to be able to say: I have modified the page with JavaScript, the new state is what you would get if you just asked the server for this URL.
You shouldn't use JavaScript for this problem at all. You just want to have a page appear at a particular URL.
You need to configure the server to serve up the content you want on the URL you want.
What am I missing, am I supposed to make a controller and how ?
You need something on the server to handle the URL /about-us.
"A controller" is something you would probably use if you were using the MVC architecture on the server … and it doesn't sound like you are.
More likely you will be wanting to use an Alias, a tool like mod_write, or simply moving the static file to a directory called about-us and renaming it index.html.
Using:
C# MVC5 and Jquery
I have a filter screen that potentially uses multiple different filters. Based on what the user selects I make a call to the server and I load a partial view into a bootstrap modal as follows:
$.ajax({
url: filterUrl,
contentType: 'application/html',
success: function (filterContent) {
$("#divReportFilterModalBody").html(filterContent);
LoadFilterScript(SCOPESTRINGS[currentReport.Scope]);
},....
The next step is to load the necessary javascript for that filter page because you cant have scripts on a partial view. For this I also request the script from the server as follows:
$.getScript(scopeString + "FilterJavaScript",
function () {
The mvc controller:
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult ScopeFilterJavaScript()
{
return
File(System.IO.File.ReadAllBytes(Server.MapPath("~/Scripts/.../filterPartial.js")), "text/javascript");
}
Because the user can only use one filter at a time and may or may not use multiple filters my questions are:
The scripts aren't big, is it better practice to load them all upfront rather then fetch them as required? The reason I load them as required is because they might not get called and didn't want to load a bunch of scripts that will not get used
Is not caching them a good idea because the user can use the same filter multiple times and in my current case the script will get loaded each time? OR should I rather cache the script and figure out a way not to load it again?
I'm also not 100% clear on script caching. What happens to the script in this case after it was loaded? If I make a call to the server I can see that it gets loaded again, was the previous scripts removed? Because when I look at the script tab on firebug they are all still listed there? Will this cause conflicts on the page?
What would best practice be in this scenario?
Thanks
Edit: I've been researching the topic a bit further and found this article (Old but still very relevant in my opinion). enter link description here
It's always a good idea to only load stuff if you actually need it. When the files arent that huge, maybe you can combine them and include them in the first place.
OR should I rather cache the script and figure out a way not to load it again?
yup.
When you load a script (without any queries) the browser caches it. But this has nothing to do with what happens when you load a script again. Either the servers delivers it "again" or the browser uses the cached one. Nevertheless, the script then executes again. Even if you remove it from the dom - once loaded scripts are just there.
Maybe you can wrap your scripts like so:
if (!window.foobarLoaded) {
// your script content
window.foobarLoaded = true;
}
Then you can load the script as many times as you like - it only "executes" once.
I have a rails app that gets requested cross domain (I use rack-cors to accomplish this cross domain request without jsonp) through this ajax: It responds with html
//to ensure cache=true gets passed
$.ajaxPrefilter('script', function(options) {
options.cache = true;
});
//ajax requests html
$.ajax({
beforeSend: function (xhr) {
xhr.setRequestHeader ('Authorization', api_key);
},
dataType: 'html',
type: 'GET',
url: url+'/gwsearch/ajax_search?d1='+d1_val+'&d2='+d2_val,
crossDomain: true,
success:function(result){
$("#display").html(result);
},
error: function(result) {
$('#display').html('Unauthorized client.');
}
It responds with HTML that is displayed in #display. It has this script tag included in the html
<script src="http://localhost:3000/assets/application.js" type="text/javascript"></script>
I have input buttons on the newly displayed rails app, they look like this:
<%= form_tag plans_collapse_plans_path, :method => 'post', :remote => true do %>
<%= hidden_field_tag(:plangroup_id, plangroup.id) %>
<%= image_submit_tag "collapse.png" %>
<% end %>
Clicking on the input button does a POST. The problem is that the input button will POST as many times as I've requested the cross domain rails app. If I've requested the app 5 times, when I click an input button on the app, it will POST 5 times.
No matter how many times I send the initial ajax request, I still only have one application.js present; it is not physically cached more than one time.
EDIT:This is what my cache looks like, as you can see, only one application.js:
The collapse_tplans POSTs all correspond to the same application.js file, same line. If i had loaded the initial ajax request 6 times, I would have 6 collapse_tplan POSTs from application.js
My guess is that the script tag in the html page being sent is initializing a new version of jquery (since jquery is contained within application.js) and also, possibly duplicates of other things that are being loaded in application.js each time it is sent through the script tag. With that said, under Network in Chrome, I can only see application.js being requested once, no matter how many times I execute the ajax request.
Any ideas? I need my input button to only POST once, like it should be doing. I'm truly stumped with this one.
As #natedavisolds said, I guess your application.js script is executed 5 times, and the click hanlder of your button or the submit handler of your form is attached 5 times.
The fact that application.js is requested only once does not tell you how many times it is executed.
Try adding the following line at the beginning of the application.js script :
console.log('application.js executed');
and check your browser console to see how many times the message appears.
From your script's name, application.js, I guess it is meant to initalize the whole page, while your ajax request looks like it is only filling the #display node with search results.
You will have to refactor your application.js file :
Read the code in your application.js file, and split the code in two parts : the part that concerns setting up the #display div, and the remainder.
Move the first part in a separate results.js (or whatever name you see fit).
Remove the <script src="application.js"> node from the response to the /gwsearch/ajax_search request, and replace it with a <script src="results.js"> node instead
Since you are using remote:true on the form, my theory is that rails.js is attaching a delegated event on the document element each time the script is loaded. 5 loads = 5 events = 5 ajax calls.
To fix it you could:
Remove the remote true and roll your own making sure it only happens once.
Remove the delegated events on document before loading a new script.
Try: (I am guessing here)
success:function(result){
$(document).undelegate('submit.rails');
$("#display").html(result);
},
Explanation:
Every time rails.js runs, a submit.rails event is added to the stack of events on document. When you insert your html into the page, the rails.js code runs. So, we undelegate the events first, then load the event back in.
The answer to this problem was to stop my application from serving application.js and host it on the client. I did this by the following:
app/views/layout/application.html.erb
I commented out the portion that serves application.js
<!--# <%= javascript_include_tag "application" %> -->
In my client, I added
<script src="https://myapp.herokuapp.com/assets/application.js"></script>
So the client serves application.js, and the rails html response gets sent without application.js. Hope this makes sense to everyone, this took me a while to piece together!
I have a js file called create.js.erb that is in my view folder. It's supposed to be called when I try to create a record, but it isn't being called. I can't figure out why, and to be totally honest, don't even know how my app calls a js file in the view folder, so I'm not sure what code to paste here to help debug the problem.
Can anyone explain to me how js in a view folder is executed, and when I would want to put a js file in my view folder instead of in the asset pipeline?
*.js.erb files are rendered when you are using AJAX/JS with your controller actions. By default, when you call the create method, Rails will respond using HTML. This will load a new page. Sometimes you want to use AJAX instead, and that's why you create js.erb files in the view folders.
For this to work, the form and/or link_to objects you are using must be AJAX enabled (they should have a :remote => true attribute on them) If they are not specified as remote forms, they will execute the HTML instead of the JS and the create.js.erb file will never be called.
Your controller method also needs to know how to respond to js requests. You need something like:
respond_to do |format|
format.js
end
That code tells Rails to look for a file called "method".js.erb in your view folder, so in this case, create.js.erb.
These files are completely different from regular JS files you put in the asset pipeline -- these are view templates to be rendered as the result of a controller action.
You might find some Rails/AJAX tutorials helpful...here's a pretty good one that walks you through this whole process:
http://net.tutsplus.com/tutorials/javascript-ajax/using-unobtrusive-javascript-and-ajax-with-rails-3
Hope that helps, if you need more assistance please post the code for your controller and any of the view files...
I am new to Rails but I come from PHP, in which it was almost always the case that whenever I have an HTML AJAX response, I can always load it in a container(any element) using jquery's .load()
I did that with Rails too, but recently came into another approach: use .js.erb files. Use getScript() to a controller action, then the js.erb file will respond to the js (ajax) request, the do the loading in the .js.erb file.
given general.js:
$.getScript(url, function(){});
given index.js.erb:
$('#products').html("<%= escape_javascript(render_cell :products, :index, {:products => #products})%>");
but this appears to be quite repetitive when I can do the loading in general.js! Fire an ajax request to this template that a controller has and load that in a container(I can use jquery .load()'s selector to just select the elements I want, and I can use an application_controller condition to not render the layout):
<ul>
<%= render_cell :products, :index, {:products => #products} %>
</ul>
Is there any way I can make more effective use of .js.erb files in this case?
Note: I had to use the 2nd approach because I am using twitter-bootstrap tabs. I initially used the first approach but I think the 2nd way is more "the Rails way". This is a learning project so why not? XD