AJAX doesn't override already loaded scripts? - javascript

I'm using a version of jquery-ui-widget, 1.10.3, that works well with ajax-loaded page fragment#1 but triggers an error with page fragment#2 if fragment#2 was loaded after fragment#1.
This is strange because even if I try and override 1.10.3 with 1.8.21 when ajax-loading fragment#2 (yes I realize this is a bad hack), the code that uses the widget factory still tries to use 1.10.3 and so causes an error.
Note that this is not a problem during normal page load as 1.8.21 is outside of my ajax div id="ajax_content" and so is loaded every time.
How can I override 1.10.3 during ajax?
<html>
<div id="ajax_content">
Page fragment #1 content
<script src="jquery-ui-widget.1.10.3.js"></script>
</div
<script src="jquery-ui-widget.1.8.21.js"></script>
</html>
VS.
<html>
<div id="ajax_content">
Page fragment #2 content
<script src="jquery-ui-widget.1.8.21.js"></script>
//having this script here or not has no effect if 1.10.3 was already loaded
</div>
<script src="jquery-ui-widget.1.8.21.js"></script>
</html>

version of jquery-ui-widget won't have an effect. Rather the cause of your problem is that the script added to the innerHTML of your div id="ajax_content" will not execute.
A script added dynamically (which maybe received as a response of an ajax request or that dynamically added to the innerHTML using js or jQuery) doesn't execute. Also it is not recommended as per #Kevin B's comment. I worked around the same problem by either of the two solutions below:
Load entire script initially
Load a new page with the script in the head tag
You may disagree with the second solution here saying that the question was about the script received as a ajax response while I am suggesting you to rework your approach and use a separate page instead. This may not be appropriate to do in your scenario due to various reasons but if the only reason preventing you from doing so is that this will cause code duplication then you may explore using something like jsp:include.

Related

Javascript not working on content pulled from another source

I'm pretty sure this is a dumb issue, but I searched and could not find a similar/equal scenario.
So, I have a main PHP page in which I include several Javascript files in the head section of the HTML. Then at some point I grab content (HTML + Javascript) from an outside source via file_get_contents and output it to the main page.
This new output will pick up the CSS styles from the main page normally, but any Javascript code that relies on the ones loaded at the main will not work. Even if I put the Javascript needed inside a document.ready in the main page, it will still not work.
Just to exemplify the code:
<html>
<head>
<link href="style.css" rel="stylesheet">
<script src="somejslib.js"></script>
</head>
<body>
Some HTML here generated by PHP
<?php
$content = file_get_contents('http://whatever/page');
echo $content;
?>
</body>
In the grabbed content I will have something like:
<div>
<form>
<input type="text" id="bla">
</form>
</div>
<script>$('#bla').datepicker({ somecodehere });</script>
The datepicker was included in the libs loaded in the main page, but will not work, no matter where I put this code.
Any hints?
P.S: the only way it DOES work is if I include - again - all the Javascript libs inside the new content, which of course is not a solution.
make sure you attach the listeners after the external content is loaded or use the on() event handler
http://api.jquery.com/on/
P.S. I now see your code is actually missing the document.ready and thus not waiting for the document to be loaded before executing. I'm not sure which of these applies to your actual code as you only posted an example. If you pull the content in via an ajax for example apply the first solution otherwise just wrap things up in a document ready
Solved.
Apparently it was my mistake all along. I was loading Jquery multiple times (different versions, also).
It seems that not all versions of jQuery can take care of this situation.

Why I have to put all the script to index.html in jquery mobile

I have used $.mobile.changepage to do the redirect in my phonegap+jquerymobile projects. However what makes me confused is that I need to put the script of all the pages to the same file index.html. If not, the redirect page can not execute the function in its header.
for example, my index.html seem to be
$(document).bind("deviceready",function(){$.mobile.changepage("test.html");})
then, my device will redirect to test.html which seem to be
$("#btnTest").click(function(){alert("123");})
<button id="btnTest">Test</button>
However, the script will never execute in test.html. Then I put the script to index.html, what I expect to be is done. Whatever, if I put all the script to the same page, the project will become harder and harder to be preserved. Appreciated for your help.
Intro
This article can also be found HERE as a part of my blog.
How jQuery Mobile handles page changes
To understand this situation you need to understand how jQuery Mobile works. It uses ajax to load other pages.
First page is loaded normally. Its HEAD and BODY is loaded into the DOM, and they are there to await other content. When second page is loaded, only its BODY content is loaded into the DOM. To be more precise, even BODY is not fully loaded. Only first div with an attribute data-role="page" will be loaded, everything else is going to be discarded. Even if you have more pages inside a BODY only first one is going to be loaded. This rule only applies to subsequent pages, if you have more pages in an initial HTML all of them will be loaded.
That's why your button is show successfully but click event is not working. Same click event whose parent HEAD was disregarded during the page transition.
Here's an official documentation: http://jquerymobile.com/demos/1.2.0/docs/pages/page-links.html
Unfortunately you are not going to find this described in their documentation. Ether they think this is a common knowledge or they forgot to describe this like my other topics. (jQuery Mobile documentation is big but lacking many things).
Solution 1
In your second page, and every other page, move your SCRIPT tag into the BODY content, like this:
<body>
<div data-role="page">
// And rest of your HTML content
<script>
// Your javascript will go here
</script>
</div>
</body>
This is a quick solution but still an ugly one.
Working example can be found in my other answer here: Pageshow not triggered after changepage
Another working example: Page loaded differently with jQuery-mobile transition
Solution 2
Move all of your javascript into the original first HTML. Collect everything and put it inside a single js file, into a HEAD. Initialize it after jQuery Mobile has been loaded.
<head>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=no; target-densityDpi=device-dpi"/>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
<script src="index.js"></script> // Put your code into a new file
</head>
In the end I will describe why this is a part of a good solution.
Solution 3
Use rel="external" in your buttons and every elements you are using to change page. Because of it ajax is not going to be used for page loading and your jQuery Mobile app will behave like a normal web application. Unfortunately this is not a good solution in your case. Phonegap should never work as a normal web app.
Next
Official documentation, look for a chapter: Linking without Ajax
Realistic solution
Realistic solution would use Solution 2. But unlike solution 2, I would use that same index.js file and initialize it inside a HEAD of every possible other page.
Now you can ask me WHY?
Phonegap like jQuery Mobile is buggy, and sooner or later there's going to be an error and your app will fail (including loaded DOM) if your every js content is inside a single HTML file. DOM could be erased and Phonegap will refresh your current page. If that page don't have javascript that it will not work until it is restarted.
Final words
This problem can be easily fixed with a good page architecture. If anyone is interested I have wrote an ARTICLE about good jQuery Mobile page architecture. In a nut shell I am discussing that knowledge of how jQuery Mobile works is the most important thing you need to know before you can successfully create you first app.
Unlike normal ordinary HTML pages, jQuery Mobile uses ajax technology when navigating between pages. So make sure to import all your JS files and libraries in all your html pages.
If you notice closely you will see that JS files from previous page is taken into consideration when loading the second page. But if you force rrefresh the current page then the js files of the current page will be effective.
So as I said earlier make sure to import the js files in all the html files.
Also no need to call deviceready, use following syntax to call your page specific js functions
$(document).on('pageshow', '#YourPageID', function(){
// Your code goes here
});
Jquery Mobile uses ajax to load a "page". A "page" here is a div with data-role=page. If you load a physical page index.html, you can navigate using changePage to any "page" div inside that page.
However, if you want to load a "page" from other physical page, jQM will only load the first "page" div from that page. What actually happen is you do not change page, jQM just load that particular "page" div using ajax and inject it to your current page.
You have two possible architecture where you put all your "pages" in a html page and navigate from there. Or you can have multiple page architecture. You can always mix this.
To physically change page, you need to add rel=external to your link.

How to run scripts loaded dynamically with javascript

I was wondering if there is a way to execute script within a ajax dynamically loaded content.
I've searched the web and this forum also an find a lot of answers, like
[Running scripts in an ajax-loaded page fragment
[1]: Running scripts in an ajax-loaded page fragment [1]
But none of this seems to work fine for me.
I'm not experienced as the author of the quoted post, so maybe we can find a solution more simple and quite for everyone.
For now i've implemented a tricky turnaround that smell to much of an hard-coded solution that is:
//EXECUTE AJAX REQUEST LET'S SAY SUCCESSFULLY,
$ajax([..]) //THEN
.ajaxSuccess(function(){
// LOCATE ANY OBJECT PRE-MARKED WITH A SPECIFIC CLASS
$(".script_target").each(function()
{
//DO SOMETHING BASED ON A PRESET ATTRIBUTE OF THIS SPECIFIC ELEMENT
//EXAMPLE: <div class=".script_target" transition="drop_down">...</div>
//WILL FIRE A SCRIPT RELATED TO drop_down CASE.
});
});
I know this is an ugly solution but i didn't came up with nothing better than this.
Can you help to improve this method?
Maybe there's a way to let the browser fire script within the loaded page automatically?
PS. I'm not going to use the eval() method if it's not the last solution, cause both security leak and global slowdown, AND be aware that the script launched need to modify objects loaded in the same fragment of the script.
Thanks in advance.
If I understand you correctly :
you use "load" to retrieve html content from the server, and you add it to the page.
later, you do an ajax call, and on the return of the ajax call, you want to act on the markup you added earlier
but, depending on the markup retrieved, you want to do something different in the ajax callback
So another question : before you load the markup, do you know what logic will be behind it, or do you actually need to "read" the returned HTML to understand what it will be used for ?
Otherwise maybe something like this would work :
In the callback of the "$.load" function, use $.data() to attach more information to created dom object
In the ajax callback, you should be able to access the "added" markup (with a class like you did, or with an id if possible), and read to "data" to known which behavior you should have ?
Hopefully I got your problem right, it could help if you were able to create a jsfiddle or something, just to make sure we understand it.
Hoping this helps.
EDIT : After your comment, it might be related to the selector you use when calling $.load().
There is a "Script Execution" section in the $.load documentation : http://api.jquery.com/load/ , that explains that the scripts are not executed if you add a selector in the url, like this :
$('#b').load('article.html #target');
Could this be your issue ?
Also, if possible, you could try and change your site so that instead of having the js code of each "page" of the gallery inside the page, you put it inside a separate javascript file, that you load at runtime (for example with require js).
This way, "loading" a page would be something along the lines of :
$.load("url_of_a_page_markup.html", function () {
require(["url_of_the_javascript_module.js"], function (TheJsModuleForThePage) {
TheJsModuleForThePage.doSomething();
});
});
If you structure your JS modules in a consistent way, and you define a convention for the name of markup and js files, you can generalize things so that a "gallery" manager deals with all this code loading, and you'll end up with well isolated js modules for each page.
Hoping this helps.
If you want to run a script in a ajax loaded page fragment you can use try to use jQuery.load function.
Have you considered a module loader like require.js or Lab.js?
There are many other people asking similar questions:
does anyone knows good ajax script loader
Where are scripts loaded after an ajax call?
getting jQuery scripts and content through ajax dynamically
dynamic script loader in JS
Edit: I think I misread your question. Will try and come up with a better answer. Sorry!
Best of luck to you!
I came across this same issue when I dynamically loaded some HTML to use inside a JQuery UI dialog (a help function for my application).
$('#helpMessage')
.load('./help/' + helpFile, function () {...do stuff after loading});
To make things simple I wanted to combine the unique script related to the help page within the HTML fragment that I load. Using the examples on the JQuery UI page I created a dialog with a Jquery UI button element.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Button - Icons</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.9.1.js"></script>
<script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
(function() {
$('#myButton') // My button element
.button() // Initialize it as a JQuery UI button object
.click(function (){ // Hook up the button click event
$('#correct')[0].play(); // to play a sound in an <audio> tag
});
});
</script>
</head>
<body>
This is my help file, this is my code. This is for reading, this is for fun.
<button id="myButton">Button Text</button>
</body>
</html>
The dialog would load and the HTML displayed, but the embedded script did not execute.
I realized that one simple change would fix it. The script is embedded in an anonymous function (a best practice and part of the JQuery UI demo code). By immediately invoking the anonymous function the script executed when I loaded the HTML fragment into my main page.
This:
<script>
(function() {
...
});
</script>
Became:
<script>
(function() {
...
})(); // Immediately invoke
</script>
Niceness.

asp.net 2.0 site and location of <script/> tags causing problems/conflicting

I have no idea how to describe this accurately/intelligently because it seems to be completely impossible, yet there must some reason for it.
I am trying to leverage jquery, jquery-ui, qtip (tooltip for jquery) and highcharts (javascript charting), but for purpose of post I could just as easily been only using jQuery and jQuery-UI.
If I include my <script/> tags at the bottom of my <head/> element I get an error trying to call the .slider() extension to configure my sliders. But if I put the <script/> tags right before the closing of my <body/> element then everything works. To illustrate, the following will not work (obviously some pseudo code below):
<head>
<script jquery.js/>
<script jquery-ui.js/>
</head>
<body>
... html ...
<script type="text/javascript">
$(document).ready(function () {
$(".slider").slider( { .. options .. } );
} )
</script>
... more html *including* the .slider elements
</body>
However, if I move the two jQuery script tags to be right above the </body> closing element things work. When the script tags are in the head element and I debug my application, basically the page does appear to have completely loaded and Visual Studio highlights the line calling the .slider() function saying it doesn't know what slider() is. Looking at the call stack, it appears to be correctly calling it from the document ready function...the mark up all appears to be there as well, making me believe the document truly is ready.
Now I didn't include things that are required by asp.net 1.1/2.0 site in my pseudo code, namely a <form/> element with runat="server' and the use of a <asp:ScriptManager/> tag (we needed that for parsing monetary values from different cultures leveraging Microsoft Ajax). I can't believe they would be causing the problem, but maybe they are. Additionally, asp.net injects several of its own script sections (i.e. for validation, post back, etc.)
Regarding the form tag...all the html and document.ready markup would be inside the form tag, while the script tags are always outside of the form tag (either above it, in the head or below it at the bottom of the body).
Obviously I could leave the script tags at the bottom, and I very well may end up doing that, but I am trying to get a clean 'template site' of which to use when creating new client sites and it just feels wrong that I have a restriction forcing me to put those tags at the bottom of the html. I'm sure our framework code (or maybe asp.net's) is simply inserting something that is causing problems/conflicts with jQuery, but I don't really know how to go about debugging/diagnosing what that problem is. So if anyone has any suggestions I'd greatly appreciate it.
It looks like jQuery 1.3.2 is being loaded by ASP.NET (see your second WebResource.axd). The two library versions are overwriting each other. Thus the reason it works when you load 1.6.2 at the end of the page.

ASP.net: ClientScript.RegisterClientScriptBlock fires before jQuery is loaded

Interesting problem here from some inherited code I recently looked at. I'm trying to add a compression module to a project. It is loading all the JS and CSS files, combining them, minifying them, and compressing them. I've tried a number of solutions, but all of them have one fatal problem.
I have some javascript that is being loaded via Page.ClientScript.RegisterClientScriptBlock in the PreRender of the MasterPage. The compression module is loading as a Script Tag link in the MasterPage, but when I run the page... the code from the PreRender is lopped on top and is giving me a '$ is undefined' error, telling me jQuery isn't loaded yet.
Furthermore, I can't seem to get past the same problem when it comes to inline javascript on content pages.
Any ideas as to what is causing this? Enlighten me as I have no clue.
If have done this before with RegisterStartupScript (instead of RegisterClientScriptBlock) and called the $(document).ready(function() from WITHIN that script.
If the script tag link that eventually expands out to jquery is not in the head, but in the body of the page, then $ will be undefined when the script block executes, unless it is included in the html before the opening <form /> tag in the rendered html, which I understand is where RegisterClientScriptBlock spits out its script (just after that opening tag).
If this is not the case, and the joined/minified script is in the head, then I'd use a browser debugger such as Firebug or IE Dev Tools to verify that the jquery script is being correctly included in your combined script.
I know this answer is late to the party, but try calling ClientScript.RegisterClientScriptBlock in your OnPreRenderComplete (rather than OnPreRender) handler. This inserts the code later in the page rendering process.
All your jQuery code should be written inside the DOM-ready function:
$(function() {
// your code here
});
indipendently from where you place it in the page, 'cause the jQuery() function isn't avalaible before.

Categories