So far I've been making an AJAX call to replace the content of a div with another page, using the following code:
<script>
function fetchContainerContent(url, containerid) {
var req = false
if (window.ActiveXObject) {
try {
req = new ActiveXObject("Msxml2.XMLHTTP")
} catch (e) {
try {
req = new ActiveXObject("Microsoft.XMLHTTP")
} catch (e) {}
}
} else if (window.XMLHttpRequest) {
req = new XMLHttpRequest()
} else {
return false
}
req.onreadystatechange = function() {
requestContainerContent(req, containerid)
}
req.open('GET', url, true)
req.send(null)
}
function requestContainerContent(req, containerid) {
if (req.readyState == 4 && (req.status==200 || window.location.href.indexOf("http")==-1))
document.getElementById(containerid).innerHTML = req.responseText
}
</script>
I have tried transforming the above code to work with jQuery as below but it doesn't work. In other words, I am trying to mimic the end result of the above behaviour but it is nowhere near the same. In fact, nothing happens on screen, nothing changes. I should mention that I don't really need the Loading... but since the examples I've seen use it and since I'm not sure how to correctly syntax jQuery, I've left it in.
<script>
function fetchContainerContent(url, containerid) {
jQuery.ajaxSetup ({
cache: false
});
var ajax_load = "loading...' />";
jQuery("#load_basic").click(function() {
jQuery("#"+containerid).html(ajax_load).load(url);
});
}
</script>
Thanks in advance. I'm really new to jQuery so I may have done something really stupid.
After all the comments received (thanks guys!) I have left only the following:
function fetchContainerContent(url, containerid){
var ajax_load = "loading...";
$("#load_basic").click(function(){$("#"+containerid).html(ajax_load).load(url);});
}
but I'm still having problems as it does not update the page. No js error, nothing happens.
Try this:
jQuery("#load_basic").click(function() {
jQuery("#result").html(ajax_load).load(url);
return false;
});
Note the return false statement at the end of the click handler. This will prevent from propagating the click event in case load_basic is a button or an anchor element.
The only fundamental differences I see are:
You're using a hacky-looking loading string "loading...' />". This doesn't smell good.
You're hardcoding the containerid with "#result" instead of using "#" + containerid.
You're defining the click event in JS code rather than (apparently) inline in the element. How did it originally look like?
For the remnant the code looks fine.
Is the issue that it isn't calling your callback method? You have to had the callback to the .load method.
<script>
function fetchContainerContent(url, containerid) {
jQuery.ajaxSetup ({
cache: false
});
var ajax_load = "loading...' />";
jQuery("#load_basic").click(function() {
jQuery("#result").html(ajax_load).load(url, null, requestContainerContent);
return false;
});
}
function requestContainerContent(responseText, textStatus, XMLHttpRequest) {
// do replacement in here
}
</script>
You'll have to adjust the code a bit in your requestContainerContent to do what you need it to do with the arguments provided.
OK, I seem to have gotten it working, even if I'm not too sure about the quality of the code.
var ajax_load = "loading...";
$("#"+containerid).html(ajax_load).load(url);
Related
I am facing very strange thing with AJAX and Unobtrusive JavaScript that I have two pages
ajaxcontent.php
index.php
index.php has
<div id="cont"></div>
<input type="button" id="a" value="load plz.">
<script type="text/javascript">
document.getElementById('a').onclick = function () {
if (window.XMLHttpRequest) {
ari = new XMLHttpRequest();
} else {
ari = new ActiveXObject("Microsoft.XMLHTTP")
}
ari.onreadystatechange = function () {
if (ari.readyState == 4 && ari.status == 200) {
document.getElementById('cont').innerHTML = ari.responseText;
}
}
ari.open("GET","button.php",true);
ari.send();
}
document.getElementById('b').onclick = function () {
alert('a');
}
</script>
And ajaxcontent.php has only
<input type="button" id="b"/>
and the problem is unobtrusive Javascript is not working.
After laoding of ajaxcontent when i click on button it doesn't show alert pop up.
i have tried that i added
document.getElementById('b').onclick = function () {
alert('a');
}
this code on ajaxcontent.php but it still not working.
THe only way to make it work that i have to add inline javascript as
<input type="button" id="b" onclick="hi();"/>
and replace this function with
document.getElementById('b').onclick = function () {
alert('a');
}
with
function hi() {
alert('a');
}
so please help me that how to use unobtrusive js here and please don't give jQuery based answer thanks
First of all document.getElementById('b') can only find an element that is in the DOM at the time you call this function.
Because the element with the id b is in the data you request in the click event, the function will not find any element. You most likely should have seen an error in the console like cannot set property onclick of undefined.
AJAX requests are async by default (and you should not make them sync because this will block the window of the browser).
So you need to place the document.getElementById('b').onclick = ... in the onreadystatechange check right after the document.getElementById('cont').innerHTML = ari.responseText;
Here a simple example how to generalize your request:
function doAjaxRequest(url, complete, error) {
var ari; //<<<< you should define your variables using var otherwise it is set in the global scope
if (window.XMLHttpRequest) {
ari = new XMLHttpRequest();
} else {
ari = new ActiveXObject('Microsoft.XMLHTTP');
}
ari.onreadystatechange = function() {
if (ari.readyState === 4) {
if (ari.status === 200) {
// if complete callback is passed, then call it if request was successful
if (typeof complete === 'function') {
complete(ari.responseText);
}
} else {
// if error callback is passed then call it if request was not successful
if (typeof error === 'function') {
error(ari.status, ari.statusText);
}
}
}
}
ari.open('GET', url, true);
ari.send(null);
}
document.getElementById('a').onclick = function() {
doAjaxRequest('button.php', function( data ) {
document.getElementById('cont').innerHTML = data;
document.getElementById('b').onclick = function() {
alert('a');
}
}, function(errorCode, errorMessage) {
//do something on error
});
}
The onclick event attaches to elements currently in the DOM when the function is triggered. Because the button in ajaxcontent.php is added to the DOM after the function was called, no event is attached.
To rectify this, you can add a snippet inside ari.onreadystatechange to detatch events then attach the event again.
ari.onreadystatechange = function () {
if (ari.readyState == 4 && ari.status == 200) {
document.getElementById('cont').innerHTML = ari.responseText;
// remove events
document.getElementById('b').onclick = null;
// attach events
document.getElementById('b').onclick = function() {
alert('a');
}
}
}
It's important to remove events because it may (although i was using jQuery when i learnt by mistake) cause double execution.
If you add javascript code inside ajaxcontent.php, that code will not be executed unless you extend your ari.onreadystatechange function to scan for javascript and execute it. The way I do this, is I put my javascript in AJAX requested pages in a input with class 'ajax-js' and scan for those input boxes and execute the code one by one, removing the class as I go.
The problem is that the new content will not print (a few more elements).
When the user clicks my print link then I add more html to the document before window.print() is called.
I use ajax to fetch more chapters for a book before printing.
Code:
Print initialized:
var afterPrint = function () {
var timer = setInterval(function () {
afterContentPrint(); // Cleanup html (restore to initial state)
clearInterval(timer);
}, 900);
}
//window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
Event print click:
$("#print-test").click(function (e) {
e.preventDefault();
beforeContentPrint(); // ajax call for additional content, finishing by calling window.print()
});
In function beforeContentPrint():
var jqxhr = $.ajax({
type: "GET",
url: bookURL,
success: function(data) {
.....
.....
$(article).each(function () {
parent.append(article);
});
},
complete: function() {
var timer = setInterval(function () {
window.print();
}, 900);
}
}
The new content is visibly added to the HTML document, so it should work. But only the initial content (before ajax call) is picked up for print.
This solution is for IE and Firefox (onbeforeprint and onafterprint).
Using window.matchMedia('print') seems to work fine in Chrome with this logic.
I don't know why this is happening but there is a working around in mozilla docs; printing a hidden iframe, then you open more chapters of the book with no need to shows up.
Here the link https://developer.mozilla.org/en-US/docs/Printing
Here the code:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>MDN Example</title>
<script type="text/javascript">
function closePrint () {
document.body.removeChild(this.__container__);
}
function setPrint () {
this.contentWindow.__container__ = this;
this.contentWindow.onbeforeunload = closePrint;
this.contentWindow.onafterprint = closePrint;
this.contentWindow.print();
}
function printPage (sURL) {
var oHiddFrame = document.createElement("iframe");
oHiddFrame.onload = setPrint;
oHiddFrame.style.visibility = "hidden";
oHiddFrame.style.position = "fixed";
oHiddFrame.style.right = "0";
oHiddFrame.style.bottom = "0";
oHiddFrame.src = sURL;
document.body.appendChild(oHiddFrame);
}
</script>
</head>
<body>
<p><span onclick="printPage('externalPage.html');" style="cursor:pointer;text-decoration:underline;color:#0000ff;">Print external page!</span></p>
</body>
</html>
1st Attempt : try putting asyn:false in the ajax request of beforeContentPrint, so that the elements will be added first then the print will be called.
var jqxhr = $.ajax({
type: "GET",
url: bookURL,
async:false,
success: function(data) {
.....
.....
$(article).each(function () {
parent.append(article);
});
},
complete: function() {
var timer = setInterval(function () {
window.print();
}, 900);
}
}
2ndAttempt: Take a look Here how to force execution of one function after another.
Hope this helps.
As the elements added aren't shown it can be a little hard to pinpoint the exact problem, but adding elements via appending/inserting into document doesn't always work that well for all browsers and in worst case you will need to add those elements manually by code (document.createElement(), appendChild() etc.).
In an attempt to create a work-around you can try to use MutationObservers to track changes for your article element which can hopefully help you trigger print when DOM is updated properly. The support is fairly good in new browsers (you may have to use prefix in some, f.ex. WebKitMutationObserver) and for older browsers you can provide a fallback - which of course then only get you so far.
This will monitor a target element for changes and fire a callback.
Generic example based on this article:
var article = document.querySelector('#articleID'),
doPrint = false, // must be available in global/parent scope
o,
useFallback = (typeof MutationObserver !== 'undefined');
if (!useFallback) {
o = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// you can do additional filtering here
// using the mutation object (.name, .type, ...)
if (doPrint) {
doPrint = false;
window.print();
}
});
});
var cfg = { attributes: true, childList: true, characterData: true };
o.observe(article, cfg);
}
Now that the observer is running you can do this modification in your success callback:
var timer; // keep track of setTimeout so we can cancel it
success: function(data) {
...
...
$(article).each(function () {
parent.append(article);
});
// after last element is added, add a "dummy" element
doPrint = true;
if (useFallback) {
// fallback to setTimeout or other solution
}
else {
parent.append('<br />');
}
}
I made an online demo here which sets up the observer and adds some elements. Open console to see actions. The demo is probably too limited data-wise to simulate your situation but can be useful to see the process.
The mechanism used here for triggering print dialog itself can be discussed if is the best - I just provide one for sake of example.
But you can see the observer is triggered when something is added to article. This way you know the DOM has been updated and it should be available for printing. Only the last element added need to trigger the print, hence the doPrint flag.
If you still have no success you will need to consider adding the elements manually the code way or perhaps predefine some elements that you inject when needed (as said, without knowing the full scenario here it has to be with the guess).
It looks like the setInterval, clearInterval is what is messing you up. Change to a setTimeout and get rid of the clearInterval in your afterprint function. I made a fiddle that works in FF and IE9. Fiddle
complete: function() {
var timer = setTimeout(function () {
window.print();
}, 900);
}
I'm working on a chrome extension, and I set window.title in the onload handler. It seems, though, that the page I'm modifying sets the document title dynamically as well. There's a huge collection of scripts being linked. Is there any way for me to prevent anyone else from modifying document.title or any of its variants, without knowing where the modification is coming from? Alternatively, is there a quick way for me to see where the change is coming from?
I had same problem, some external scripts are changed my page title by document.title = "..."
I've made own solution for it:
try {
window.originalTitle = document.title; // save for future
Object.defineProperty(document, 'title', {
get: function() {return originalTitle},
set: function() {}
});
} catch (e) {}
See the answer to how to listen for changes to the title element?. Notably:
function titleModified() {
window.alert("Title modifed");
}
window.onload = function() {
var titleEl = document.getElementsByTagName("title")[0];
var docEl = document.documentElement;
if (docEl && docEl.addEventListener) {
docEl.addEventListener("DOMSubtreeModified", function(evt) {
var t = evt.target;
if (t === titleEl || (t.parentNode && t.parentNode === titleEl)) {
titleModified();
}
}, false);
} else {
document.onpropertychange = function() {
if (window.event.propertyName == "title") {
titleModified();
}
};
}
};
This SO answer suggest a technique for how to listen for changes to the document title.
Perhaps you could use that technique to create a callback which changes the title back to whatever you want it to be, as soon as some other script tries to change it.
i am working on this fiddle with cookies. Here is the link. but it works fine with Mozilla for the first time. when i delete all the cookies but when ever i reopen the page it goes directly to the second div which has to be displayed after the button click from the first div. as well as the second div must be shown and first div must be hidden when refreshed. and even this does not work for chrome in any ways. any idea or suggestions to improve. thanks in advance.
here is my code:
$('#sbut1').click(function() {
$('.cont1').show();
$('#log1').hide();
$.cookie('shown', true);
});
$(function() {
if ($.cookie('shown')) {
$('#sbut1').click()
}
});
Update:
there was a slight syntax error in my answer (forgot closing parentheses for IIFE). Anyway, here's an updated fiddle, and (for completeness) here's the code. I've optimized it some more, but it's basically the same thing:
$(function()
{
(function(sbut1)
{
(function(log1, cont1)
{
sbut1.on('click',function()
{
cont1.show();
log1.hide();
$.cookie('shown', true);
$(this).off('click');
});
}($('#log1'), $('.cont1')));
if ($.cookie('shown'))
{
sbut1.trigger('click');
}
}($('#sbut1')));
});
There's a couple of things that might seem irrelevant (like binding and unbinding the event listeners), but the comments in the fiddle explain why I'm doing this. The main reason is to clean up any references to the DOM, in order for them to be flagged for garbage collection.
Again, this code works just fine for me in both FF and chrome
In response to my last comment, same thing, only vanillaJS:
window.addEventListener('load', function l()
{
var cookie = (function(trueUndef)
{
var clean = (localStorage || document.cookie);
return function(name, val)
{
if (val === trueUndef)
{
if (clean === localStorage)
{
return clean.getItem(name);
}
val = clean.split(name + '=')[1];
return val ? val.match(/^[^;]+/)[0] : trueUndef;
}
if (clean === localStorage)
{
return clean.setItem(name, val);
}
return !!(clean = name + '=' + val);
};
}()),
sbut1 = document.getElementById('sbut1');
sbut1.addEventListener('click', (function clickHandler(log1, cont1)
{
return function(i)
{
log1.style.display = 'none';
for(i=0;i<cont1.length;i++)
{
cont1[i].style.display = 'block';
}
cookie('foo', true);
sbut1.removeEventListener('click', clickHandler, false);
};
}(document.getElementById('log1'), document.getElementsByClassName('cont1'))), false);
if (cookie('foo') === 'true')
{
sbut1.dispatchEvent(new Event('click'));
}
window.removeEventListener('load',l, false);
}, false);
I've had a look at your fiddle, and changed the code to this:
$(function()
{
$('#sbut1').click(function()
{
$('.cont1').show();
$('#log1').hide();
$.cookie('shown', true);
});
if ($.cookie('shown'))
{
$('#sbut1').click()
}
});
Which works like a charm, for me (with option no wrap - in head) as you can see here
Just a side-note, you're using a lot of DOM selectors, which is calling functions all over the place, and queries the DOM way too much. Your code could be a lot more efficient if you assigned a reference to these DOM nodes somewhere:
$(function()
{
(function(sbut1, log1, cont1)
{
sbut1 = sbut1 || $('#sbut1');//safety-net
log1 = log1 || $('#log1');
cont1 = cont1 || $('.cont1');
sbut1.click(function()
{
cont1.show();
log1.hide();
$.cookie('shown', true);
});
if ($.cookie('shown'))
{
sbut1.click();
}
}($('#sbut1'), $('#log1'), $('.cont1')));
});
The IIFE is optional, of course, but it wraps the DOM references in a scope, so they're only available to those parts of your script that actually need them.
There's a lot of ways to improve on this code, still, but excess DOM queries are easy to avoid, so I thought I'd suggest you taking care of those.
This is my code, which sometimes works and sometimes doesn't.
var resolve_ajax_login=function(){
$.ajaxSetup({cache:false });
var loginvar=$("#inputlogin").attr("value");
var senhavar=$("#inputsenha").attr("value");
$.post("../model/php/login_ajax.php",
{login:loginvar, senha:senhavar},
function(responseText){
if (responseText=="ok"){
window.location="areatrab.php";
}else{
$("#inputlogin").attr("value","");
$("#inputsenha").attr("value","");
$("#divmensagem").html("<span style='color:red;font-size:70%;'>"+responseText+"</span>");
}
}
);
return false;
};
Ok. It's in portuguese but I think you get the general picture. Sometimes this works, no problem, but some other times (only in IE, no problem whatsoever in Firefox) it throws a javascript error in my jquery.js file (minified). The error description is as follows:
Object doesn't support this property or method: jquerymin.js line 123 character 183..
which amounts to...
{return new A.XMLHttpRequest}
somewhere in the middle of the jquery.js file. It seems to be very IE-specific, as I had no such problems on Firefox. This guy apparently had the same problem as I did, but got no responses yet.
Has anyone else seen this? Thanks in Advance
P.S.: I run IE 8
Have you tried using a full URL instead of ../model...? For example: http://www.mysite.com/model/login_ajax.php
Also, maybe try modifying the 'xhr' property using jQuery's .ajax method... something like:
var loginvar = $("#inputlogin").val();
var senhavar = $("#inputsenha").val();
var ajax_obj = null;
var resolve_ajax_login = function() {
if(ajax_obj !== null) {
try {
ajax_obj.abort();
} catch(e) {
}
}
ajax_obj = $.ajax({
type: 'POST',
cache: false,
url: '../model/php/login_ajax.php',
data: {login:loginvar, senha:senhavar},
dataType: 'text',
timeout: 7000,
success: function(data)
{
if(response == 'ok') {
alert("right on!");
} else {
alert("not ok");
return;
}
},
error: function(req, reqStatus, reqError)
{
alert("error");
return;
},
'xhr': function() {
if(ajax_obj !== null) {
return ajax_obj;
}
if($.browser.msie && $.browser.version.substr(0,1) <= 7) {
return new ActiveXObject("Microsoft.XMLHTTP");
} else {
return new XMLHttpRequest();
}
}
});
}
It's something to do with the order in which you try all the different types of browsers in order to create the right kind of XMLHTTP REQUEST object.. I'll explain it in more detail in the following page:
AJAX inconsistency in IE 8?