So as many others I have a problem dealing with scripts from external pages I load with ajax.
Im trying to set up a page with an "admin panel" on top of it. I want to be able to navigate to several admin pages within the panel. The different admin pages have both internal <script>and external js-files that they include. The scripts are loaded as they should but they seem to stack up or are not being managed in a good way.
I made a small test on one of the admin pages:
$('.left-col').click(function () {
alert();
});
Here, whenever I return to this page it will bind another click to it so I then get two alerts each time I click the div. I can solve this easily by running $('.left-col').unbind(); in my ajax.success.
However for some admin pages there are tons of .click/.change/.live etc and I'm not even sure what they are (i.e. from external plugins). So can I somehow unbind/remove all of the scripts loaded from each of my ajax-loaded page without having to specify each elements? I know I can use selectors with unbind but it doesnt seem very effective to loop over each div/img/input etc and unbind, and I'm not even sure if it will work.
This is how I load the admin pages:
<script type="text/javascript">
$(document).ready(function() {
function reloadAdminPanel(url) {
if(typeof(url) === "undefined") {
var url = '/admin/panel/dashboard/';
}
$.ajax({
'success': function (data, textStatus) {
var jData = $(data);
// override links in admin to run reloadAdminPanel()
jData.find('a').each(function() {
var newUrl = $(this).attr('href');
$(this).click(function(e) {
reloadAdminPanel(newUrl);
return false;
});
});
$('div.panel__inner').remove();
$('body').prepend(jData);
delete jData;
},
'url': url
});
}
reloadAdminPanel();
});
</script>
Any help is appreciated, cheers!
The structure of the page:
<html>
<body>
<div class="panel__inner"> <!-- admin panel --> </div>
<!-- rest of project site -->
</body>
</html>
Maybe itd help if you show us the structure of the elements, but from the definition of "Remove" in Jquery, it should remove the element, its children, all events and any data associated to it.
Is div.panel__inner located inside your body tag? I see that you are doing a remove on the div, but prepending the data to $('body'). Can you remove the body contents itself?
Related
I'm trying to build an FAQ page and wish to have the user click a question and only then an answer will side down under the question.
I have code that will work this when I put it all on one page. However I wish to use a div to load various files (the FAQ div is only one of a few files I wish to add into the div). So when I use the div and an 'window onload event' the div loads but all questions and answers are fully opened and exposed.
The script to dropdown answers, placed in the HEAD section of the MainPage.html also a call to jQuery.
<script type="text/javascript">
$(document).ready(function() {
$('#faqs h1').each(function() {
var tis = $(this), state = false, answer = tis.next('div').hide().css('height','auto').slideUp();
tis.click(function() {
state = !state;
answer.slideToggle(state);
tis.toggleClass('active',state);
});
});
});
</script>
The FAQ.html
<div id="faqs">
<h1>+ Question</h1>
<div>
<p><br>Answer Here</p>
</div><br>
<h1>+ Question</h1>
<div>
<p><br>Answer Here</p>
</div><br>
</div>
The script to load the div, placed in the HEAD section of the MainPage.html
<script>
window.onload = function(){
$('#target').load('FAQ.html');
}
</script>
The div, placed in the BODY section of the MainPage
<div id="target"></div>
I have tried placing the javascript in various place on the page but still the same result. Repeat: If I place the code of FAQ.html directly in the BODY section of the MainPage it all works properly.
I have researched this also under 'conflicting jQuery' but with no success. Suggestions appreciated please.
It looks a lot like $(document).ready is run before $('#target').load finishes.
To avoid that, take the entire function you pass to $(document).ready and pass it as a last argument to $('#target').load instead, so that it gets called when loading of FAQ.html has completed:
window.onload = function(){
$('#target').load('FAQ.html', function() {
$('#faqs h1').each(function() {
var tis = $(this), state = false, answer = tis.next('div').hide().css('height','auto').slideUp();
tis.click(function() {
state = !state;
answer.slideToggle(state);
tis.toggleClass('active',state);
});
});
});
}
I assume it's because of the
$(document).ready()
callback. You're specifying a function to happen when the DOM is loaded, but by the time you've loaded in the faq.hmtl file, that's already happened. See what happens if you remove the first and last lines inside your script tags.
Also, unrelated, you're using <h1> tags incorrectly. You should only have one <h1> tag per page, as a rule. The <dl> tag is probably the most semantically meaningful in this situation.
I have a problem with my code , iam using Html 5 history and its work fine in getting contents and changing url but when i refresh the page its show only the content without full page with css and here my code :
<script type="text/javascript">
$(function() {
$('.menuAnchor').click(function(e) {
href = $(this).attr("href");
loadContent(href);
// HISTORY.PUSHSTATE
history.pushState('', 'New URL: '+href, href);
e.preventDefault();
});
// THIS EVENT MAKES SURE THAT THE BACK/FORWARD BUTTONS WORK AS WELL
window.onpopstate = function(event) {
console.log("pathname: "+location.pathname);
loadContent(location.pathname);
};
});
function loadContent(url){
// USES JQUERY TO LOAD THE CONTENT
$.get(url, {}, function (data) {
$(".contn_btm_mid_bg").html(data);
//$.validator.unobtrusive.parse(".contn_btm_mid_bg");
});
// THESE TWO LINES JUST MAKE SURE THAT THE NAV BAR REFLECTS THE CURRENT URL
$('li').removeClass('current');
$('a[href="'+url+'"]').parent().addClass('current');
}
</script>
I use history.js to change my URL using ajax and it works fine for me. Your CSS shouldn't really change if you have it linked in your document. Are you overwriting it?
Declare your CSS in the head of the page that you're doing the ajax call on and on ajax load only update the DIV or whatever element with the contents of the ajax call. I do that with this plugin and it works great for me. My CSS is always there even on page refresh.
<html>
<head>
<link rel="stylesheet" type="text/css" href=" linktoyourfile.css" media="screen">
<!--js files etc -->
</head>
<body>
<div class="contn_btm_mid_bg"><!--ajax contents--></div>
</body>
</html>
EDIT:
Since I can't see your HTML or structure I will just tell you how I might do it based on your comment.
Don't call the whole page. Just call the div that contains the content you want to import via ajax. Not the whole page. Link the CSS on all your included pages in the header. Then use a DIV to hold the content, when you call that page, just call the id of the DIV not the entire page. example
Your other pages:
Then in your ajax call if your divs have the same class in all the pages you can do this below. Make sure you link your CSS in your other pages too.
function loadContent(url){
// USES JQUERY TO LOAD THE CONTENT
$.get(url, {}, function (data) {
$(".contn_btm_mid_bg").html($(data).find('.contn_btm_mid_bg').html());
//$.validator.unobtrusive.parse(".contn_btm_mid_bg");
});
// THESE TWO LINES JUST MAKE SURE THAT THE NAV BAR REFLECTS THE CURRENT URL
$('li').removeClass('current');
$('a[href="'+url+'"]').parent().addClass('current');
}
I am trying to import multiple HTML External pages into a single div.
Example: I am page1.HTML, page2.html and so on. I have this piece of JQuery:
<script type="text/javascript">
$(document).ready(function() {
$('.main').load('page1.html');
});
</script>
This works fine except I am not sure how to add multiple pages to become imported into the same div on page load.
Thank my friends.
If you want multiples then you cant use load. Use $.get instead and specify the callback to add them to the div:
var pages = ['page1.html', 'page2.html', etc..],
$main = $('.main'),
doLoad = function () {
if(pages.length > 0) {
// use shift to get the next page off the array
$.get(pages.shift(), function(content) {
// append content to .main
$main.append(content);
// call do load to get the next entry
doLoad();
});
}
};
doLoad();
var pages=["page1.html","page2.html","page3.html"],
mainDiv=$(".main");
$.each(pages, function(i,page){
var newDiv=mainDiv.append("div");
newDiv.load(page);
});
load() will be easier than get() if you only want to load page fragments (which is usually the case if you deal with complete pages that include head tags).
Create an array of HTML-files to load, and iterate through the array with an ajax call for each page, and then use jQuery prepend() to put the contents into your element.
What is the best practice of activating jquery ui widgets for html loaded and inserted into the document by ajax?
I am an advocate of unobtrusive javascript and strongly believe that all functionality accessed by javascript should be also accessible without it. So in the ideal case, each form which opens in a popup, should also have its separate page and links to them should be replaced with javascript-based ajax loading.
I find this pattern very useful for loading and inserting a part of another page into the current document:
$('#placeholder').load('/some/path/ #content>*');
Or to make it more generic:
$('a.load').each(function() {
$(this).load($(this).attr('href') + ' #content>*');
});
However, I would also like to activate the javascripts from the dynamically loaded page, so that different widgets function correctly.
I know, I could add those javascripts to the current document and activate all of them in the callback of .load(), or I could use $.get() to get some JSON with html and javascripts separately, but I guess, there might be a more elegant generic solution to this.
What would you recommend?
BTW, I am using Django in the backend.
The question is how you're activating your javascript currently. If you're doing something like:
$(document).ready(function() {
$('a.foo').click(function() { ... });
})
You could consider changin things to:
$(document).ready(function() {
$('a.foo').live('click', function() { ... });
})
That way when new DOM objects are loaded the event handlers are attached.
What I've done is used the "load" option that is specifiable by jquery.ui widgets. Unfortunately, this isn't well documented, so you won't see the option here: http://jqueryui.com/demos/tabs/#options for example, but you will see it here: http://jqueryui.com/demos/tabs/#method-load
For the most part, each of the methods you invoke have an initial option that can be set, which is what prompted me to try using the load.
In my own application, I have 3 levels of nested tabs that are being created dynamically via AJAX. In order to have the javascript for each of the tabs applied dynamically, I have nested load functions that are first initiated when the document is loaded.
So my template file has:
<script type="text/javascript" src="{{ MEDIA_URL }}js/tabs.js"></script>
<script type="text/javascript">
$(function() {
$('.overall_tabs').tabs({
load: initializeOverallTabs
});
});
</script>
My tabs.js file has:
function initializeOverallTabs(event, ui){
...
$('.lvl_two_tabs').tabs({
load: initializeTabLevel2
});
...
}
function initializeTabLevel2(event, ui){
...
// So on and so forth
...
}
Also, I recommend when working inside the loaded areas to make your references be specific to that pane. This was extremely important when working with tabs. The best way I found to do this is below.
In your tabs.js file:
function initializeOverallTabs(event, ui){
$panel = $(ui.panel);
$panel.find('lvl_two_tabs').tabs(...);
}
I found this question strangely coincidental! I recently explained my solution to a few developers to the same situation with the same Jquery/Django Environment. I hope that helped!
One way I decided myself for handling widgets from external pages is parsing the HTML of the other page, searching for scripts and executing them in the current page.
For example, there is a form with autocomplete widget on another page which is loaded and inserted to this page. The autocomplete widget should be activated with specific properties, like available choices:
<script type="text/javascript">
//<![CDATA[
$(function() {
$("#colors").autocomplete({
source: ['red', 'green', 'blue', 'magenta', 'yellow', 'cyan']
});
});
//]]>
</script>
Then in the current page I can have the following script which loads HTML and additionally collects all javascripts within it and executes them:
var oRe = /<script\b[^>]*>([\s\S]*?)<\/script>/gm;
$('#placeholder').load(
'/some/path/ #content>*',
function(responseText, textStatus, XMLHttpRequest) { // <-- callback function
var sScripts = "";
responseText.replace(
oRe,
function($0, $1) {
sScripts += $1;
return $0;
}
);
eval(sScripts);
}
);
One drawback here is that the current document should initially be loading all the libraries which might appear in the included forms. For example, in this case, it would be the jquery-ui including the autocomplete widget. I guess I could extend the code by searching for script tags which load external scripts and loading them in the current document if they are not present.
I have a page that has multiple links with various attributes (these attributes will be pulled in from a database):
index.php
<html>
<head>
<script type='text/javascript' src='header.js'></script>
</head>
<body>
My_Link_1
My_Link_2
<div id='my_container'> </div>
</body>
</html>
My header.js file has:
$(document).ready(function(){
$('.link_click').click(function(){
$("#my_container").load("classes/class.project.php", {proj: $(this).attr('id')} );
return false;
});
});
class.project.php is pretty simple:
<?php
echo "<div id='project_container'>project = ".$_POST['proj']." : end project</div>";
?>
This loads and passes the ID variable (which actually comes from a database) to class.project.php. It works fine for the first link click (either link will work). Once one link is clicked no other links with this div class will work. It feels like javascript loads the class.porject.php and it will not refresh it into that #my_container div.
I tried running this as suggested by peterpeiguo on the JQuery Fourm, with the alert box for testing wrapped inside .each:
Copy code
$(document).ready(function() {
$('.link_click').each(function() {
$(this).click(function() {
alert($(this).html());
});
});
});
This seems to work fine for the alert box. But when applying it to .load() it does not reload the page with the new passed variable. As a matter of fact, it doesn't even reload the current page. The link performs no function at that point.
The example site can be viewed here: http://nobletech.net/gl/
I looked at the link you posted, and the problem is that when you're doing load you're replacing the elements on the page with new ones, thus the event handlers don't work anymore.
What you really want to do is target the load. Something like:
$("#project_container").load("classes/class.project.php #project_container", {proj: $(this).attr('projid')} );
This only loads stuff into the proper container, leaving the links and other stuff intact.
Ideally, the php script should only return the stuff you need, not the whole page's markup.
BTW- Caching shouldn't be an issue in this case, since .load uses POST if parameters are passed. You only have to worry about ajax caching with GETs
Sounds like the request is getting cached to me.
Try this:
$.ajaxSetup ({
// Disable caching of AJAX responses */
cache: false
});
Sorry but this might be completely wrong but after examining your XHR response I saw that you are sending back html that replaces your existing elements.
So a quick fix would be to also send the following in your XHR response (your php script should output this also):
<script>
$('.link_click').each(function() {
$(this).click(function() {
alert($(this).html());
});
</script>