Event Listener in Rails Layout? - javascript

I have a question about binding a javascript event listener in a rails 4 layout. Basically I am in-lining the entire script (https://gist.github.com/dsulli99/5d8309046e5ec1ae55dd), at least for the purpose of getting things running.
The entire script is being in-lined right inside the <body> tag of my layout, and I am using the same layout for every single page in my application.
My question is this; it appears that when I click on a link to render any other view using the same layout, that the does not actually execute. It will only execute if it is:
1) The first time that a view using that layout is rendered or
2) If I actually click 'reload' on my broswer.
I would expect that since this is part of the body that the entire script would execute with every page load (i.e. if I click on a link constructed using link_to). Would anybody be able to tell me why the javascript in-lined in the layout itself is not loading with every page implementing that particular layout? I appreciate you taking the time to help me.
Thank you,
Dan

Unless you have removed it, the default Rails 4 Gemfile includes Turbolinks. It's a JS library that intercepts GET requests and replaces the <body> with the result of an XHR to the GET request's location. That means there is no window.onload event for any page after the first.
Your code is relying on window.onload, but it will never come. Listen to page:load as well, the event fired by Turbolinks after it does its loading.

Related

Call JavaScript function when div is loaded in Partial Page in MVC

I have a Partial page in which I am loading div elements. I want to call a JavaScript function when each div is loaded in my partial view.
<p class="m-0" onload="markMessageAsDelivered('#item.isDelivered')">#item.Message</p>
This is the function I have in my JS in my razor page.
function markChatAsDelivered(isDelivered) {
if (!isDelivered)
alert('markChatAsDelivered');
}
This function is not getting called. I tried to put it in windows onload as well but still it is not working. Please let me know what can be done?
The problem I've had with these things is that onload is called before ASP.NET makes its changes to the page. There's two solutions I use:
$(document).ready() with JQuery waits until the DOM is fully loaded and done, so you can migrate some code into there.
function pageLoad(sender, args) is a built-in ASP JS function (like Page_Load in your code behind) that gets called when the page is done being loaded. You can migrate some JS into here like the first answer.
Personally, even though I like to avoid libraries, I like the first option because you can use more than one per page. This is only really useful if you're calling code in your master page though. The second option is good if you only use it once per page, but obviously if you try to use it in both your master page and current page, it won't work properly. So I'd recommend JQuery, but if you must avoid it, pageLoad works too.

Reload Javascript when redirected to other page with turbolink in Rails 4

In my application I display the table page only when the page is completely loaded. There are two such pages in the application. To achieve this I set the 'style="display:none"' for the table in the corresponding view and when the page is completely loaded I show the table through the Javascript file using '$('mytable').show()'. The first page has link to other similar page which should display table, but when I click the link the table on other page remains hidden. I know this happens because the Javascript (which unhides the table)is not executed again. How do share the Javascript between those two pages? Note I have other Javascript code as well which I want to share between these two pages.
Known solution:
Removing 'turbolinks' does the trick for me, but then every time I switch between pages the loading is quite slow. Is there way to make this work so that the performance is not impacted.
My Javascript is located at 'app/assets/javascripts/myscript.js'.
I have a single controller 'mycontroller' and two actions, 'index' with view 'view1' and 'index1' with view 'view2'. Both the views display similar tables with different data.
I tried searching over internet but could not find a relevant post.
Please let me know if I need to share any more details.
Thank you for the help!
Solution: I found the solution on Rails Guide, please see my answer below.
Directly from the Rails guide:
5.2 Page Change Events When writing CoffeeScript, you'll often want to do some sort of processing upon page load. With jQuery, you'd write
something like this:
$(document).ready -> alert "page has loaded!" However, because
Turbolinks overrides the normal page loading process, the event that
this relies on will not be fired. If you have code that looks like
this, you must change your code to do this instead:
$(document).on "turbolinks:load", -> alert "page has loaded!" For
more details, including other events you can bind to, check out the
Turbolinks README.
Just modify that sample to reload the table, instead of an alert.
Try adding this on the bottom of the second page
<script>
$(document).ready(main);
</script>
Read section 5.2 at this link, that worked for me:
When writing CoffeeScript, you'll often want to do some sort of processing upon page load. With jQuery, you'd write something like this:
$(document).ready ->
alert "page has loaded!"
However, because Turbolinks overrides the normal page loading process, the event that this relies on will not be fired. If you have code that looks like this, you must change your code to do this instead:
$(document).on "page:change", ->
alert "page has loaded!"

JavaScript does not work well inside a loaded content in a DIV

I am creating an application with Symfony2, where I have a main menu of options depending on the option selected dynamically opens a tab at a lower div with the content for that option. Content is loaded with load() of Jquery in the container div.You can see in the picture below:
The first problem was that in the HTML loaded in each tab could not use the js file initially loaded in the index.html, as you can see in this example you should check out a notice when we click the content of each tab, but does nothing .
The solution to this problem was included in each HTML code to load the appropriate script, and it worked properly. But to do it this way, if two HTML carry the same js, when one of the contents some event runs is repetite many times as tabs we have created, that is, if I open two different options (each in its own tab both charge the same js) by clicking on the first event associated performed twice, whereas if I do it in the second only done once. In short, whenever a function of a js used, is repeated as many times as there are dynamically loaded on the tabs.
And I tried event.preventDefault();orevent.stopPropagation(); and it does not solve the problem.
Would it be okay that it js is included twice in the overall structure of HTML? (Included in the initial head and then the container div)
Dynamically loading HTML + JavaScript is not the best approach for this case. I suggest that you use some JavaScript SPA framework, like AngularJS or ReactJS. Both are very big and well supported projects, so you can find tons of documentation and tutorials. You'll most likely end up using Symfony only as a RESTful service and Angular/React taking care of the rest (template loading, sending request to server, etc). Also, js frameworks will take care of deep linking and in the end you'll have a better working, easier to maintain application.
It is a bit more work initially, especially until you bootstrap the application, but then it gets easier to maintain and implement new functionality, so it pays off in the end. With your current approach you soon will find yourself in a big mess full of 100s of templates, js callbacks, inclusions, etc. I'm saying this from a personal experience!
Well...
Jquery works like this: when you attach an event to html, if the html does not exist, the event is attached to nothing. If the element exists then the event is correctly attached. It attaches only to existing elements when the on function is execute. That is a correct behaviour. In the past it used to exist a .live method that did exactly what you want: you attached an event and if you create the element after the attachment, the new element also contained the event.
Adding the js twice is not the solution. As you said after a click the button will be executed twice.
Why do not attach the events after loading the content? If you load it in the page start you can do in the main file:
$(function(){ // will force to execute the on method after all the page is loaded.
$('.submenu .button').on ('click', function (){
...
});
});
If you load the menu by ajax, in the callback and after adding the html menu to the main you must use the code I wrote above.

PJAX after AJAX template rendering

I have an application that uses jQuery and pjax (standalone). We're trying to experiment to see if we can use the possibly more flexible and smaller npm pjax over jquery-pjax.
One of my functions sets the html of a div after loading data, and this html includes links that we want as pjax links, for example $('#link-container').html('<a href="/account_detail.html?='+account.id+'" data-pjax >'). However clicking on this link causes a full page reload rather than a pjax request.
Is there a way to reimplement pjax? When I try new PJAX({elements:[a[data-pjax]]}) inside the pjax:success call (whenDOMReady from the project page - https://www.npmjs.org/package/pjax) it uses pjax... but then loads resources twice.
Perhaps the best solution is going with jquery-pjax ($(document).pjax(a[data-pjax] etc.) but I wanted to see if anyone has come across this type of issue before. Perhaps it is rare to include jQuery and non-jQuery pjax, but it seems like this can happen for any asynchronous data query and DOM modification, and I just want to re-PJAX.
I'm using jquery-pjax, and when you use it or configure it wrong - it also refresh the page, so you're experiencing one of the issues I've encountered.
In any way, I'm not sure if it will help your problem or not, but I suggest everyone to use Firefox with Firebug and in the "Console" tab to click on "Persist" you usually find some errors there that might be helpful, and since errors somewhere might cause the page to refresh - sometime you miss it as the console is being refreshed too.
What I learned is that you need to make sure that when you write:
<a href="/account_detail.html?=2" data-pjax>bla</a>
You need to have a container - that PJAX drops the content into, like:
<div id="pjax-container"></div>
And initially you configure PJAX to bind these objects:
<script>
// this is how I define it in jquery-pjax, so adjust it as you use it.
$(document).pjax('a[data-pjax]', '#pjax-container');
</script>
so the key points that I learned that causes refresh with PJAX:
I'm sending a header twice ( back-end code )
The container was suddenly removed from the HTML body ( the div id="pjax-container" ) and when the DOM is missing it doesn't have a
place to drop the HTML - so it just refresh the page.
When I initially bind the a[data-pjax] with jQuery, new DOM object are not automatically re-bind by jQuery ( unless using "live/on"), therefor they act as a regular <a> tag and reload the page with the new URL.
some JS/PJAX syntax error
In your case, if the pjax-container is "#link-container" I'm not sure if it's a good idea to place the tags inside it.

Countdown timer with ajax loaded content (jquery mobile) not working

I am having some trouble getting a countdown timer to work on my jQuery mobile page. If I have it load on a static html page it works as it should (see that page here:http://www.beingproperties.com/match-game). when you hit the start game the timer starts.
I have recently ported this over to the jQuery mobile framework and the timer is not working on that site (see this here by going to the link and clicking the 'multi-page link, then the start game link): http://www.beingproperties.com/match-game/home.html).
I have tied using 'pageshow' as scene below and though I get it to work and throw an alert, once I add in my code to execute nothing happens.
$('#shapesPage').live('pageshow', function () {
I know that it's something regarding the ajax loaded page, though all other jQuery fires on this page except for the countdown timer. I'm at a loss and would much appreciate a kick in the right direction.
I used the inspector and it's not very informative. Any insight to get this resolved, or proper ways to debug these types of issues would be much appreciated. thanks in advance. -Chris
Looking at the source for home.html, it seems that you haven't included js/plugins.js, only js/index.js.
I know you've included it in shapes.html, but JQM is a bit weird about loading external scripts when loading a page via ajax, as stated in the documentation:
The simplest approach when building a jQuery Mobile site is to reference the same set of stylesheets and scripts in the head of every page. If you need to load in specific scripts or styles for a particular page, we recommend binding logic to the pageinit event (details below) to run necessary code when a specific page is created (which can be determined by its id attribute, or a number of other ways). Following this approach will ensure that the code executes if the page is loaded directly or is pulled in and shown via Ajax.
Edit: You can not call any functions that modify the DOM until it is fully loaded. This is signaled in JQM by the pageinit event. Read about scripting and events for more info.
Try surrounding your javascript for shapes.html with
$( document ).delegate("#shapesPage", "pageinit", function() {
...
});

Categories