jquery get. i can't replace content of a div in ie with dynamically loaded html - ajax

i have a problem.
just tryin to load some html in a div...everything works fine in every browser except ie.
$('a[rel*=ajax]').click(function(e)
{
ajaxLink = $(this).attr('href')+"?ajax=true";
theDiv = $(this).parents(".post");
$.get(ajaxLink,function(data, textStatus){ $(theDiv).replaceWith(data); });
});
if i try to alert(data) in the .get callback i can read some html, but when i try to "inject" it in theDiv, i get a blank page.
thanks a lot in advance :)

can you try live instead of click and it should work fine.
sometimes in IE the DOM might not be ready
$(a[rel*=ajax).live('click', function() {
});

... but when i try to "inject" it in theDiv, i get a blank page.
You need to cancel the default action of the link; otherwise, the link will be followed. Either add return false to the end of your click handler, or add e.preventDefault(); to it. E.g., this:
$('a[rel*=ajax]').click(function(e)
{
ajaxLink = $(this).attr('href')+"?ajax=true";
theDiv = $(this).parents(".post");
$.get(ajaxLink,function(data, textStatus){ $(theDiv).replaceWith(data); });
return false; // This both prevents the default and stops bubbling
});
or
$('a[rel*=ajax]').click(function(e)
{
ajaxLink = $(this).attr('href')+"?ajax=true";
theDiv = $(this).parents(".post");
$.get(ajaxLink,function(data, textStatus){ $(theDiv).replaceWith(data); });
e.preventDefault(); // This just prevents the default, doesn't stop bubbling
});
Separately:
The quoted code is using ajaxLink and theDiv variables from the parent scope (if they're not declared anywhere, they're implicit global variables). Could it be that you're changing the value of theDiv after the shown code runs but before the ajax call completes? That would mean when the ajax call completes, it's using the new value of theDiv rather than the old one.
In any case, there doesn't seem to be any reason that code should be using variables from the parent scope, I'd recommend making them local to the function:
$('a[rel*=ajax]').click(function(e)
{
var ajaxLink = $(this).attr('href')+"?ajax=true";
// ^-- This is the new bit, the `var`
var theDiv = $(this).parents(".post");
// ^-- And this one
$.get(ajaxLink,function(data, textStatus){ $(theDiv).replaceWith(data); });
});
As a separate issue, are you sure you want replaceWith (which will replace the parent that has the class post) rather than html (which will only replace its contents)?
There's also no reason for calling $ on theDiv again; parents already returns a jQuery object. So:
$('a[rel*=ajax]').click(function(e)
{
var ajaxLink = $(this).attr('href')+"?ajax=true";
var theDiv = $(this).parents(".post");
$.get(ajaxLink,function(data, textStatus){ theDiv.replaceWith(data); });
// ^-- No need for $ here
});
And finally: You might look at the load function, which loads HTML from the server and updates the content of an element with the result.

unfortunately there was a wich was not closed..
and ie seems to be not very flexible with this kind of problem.

Related

Prototype.js event observe click intercept and stop propagation

I have a page that is built around a wrapper with some very defined logic. There is a Save button on the bottom of the wrapped form that looks like this:
<form>
... my page goes here...
<input id="submitBtnSaveId" type="button" onclick="submitPage('save', 'auto', event)" value="Save">
</form>
This cannot change...
Now, I'm writing some javascript into the page that gets loaded in "...my page goes here...". The code loads great and runs as expected. It does some work around the form elements and I've even injected some on-page validation. This is where I'm stuck. I'm trying to "intercept" the onclick and stop the page from calling "submitPage()" if the validation fails. I'm using prototype.js, so I've tried all variations and combinations like this:
document.observe("dom:loaded", function() {
Element.observe('submitBtnSaveId', 'click', function (e) {
console.log('Noticed a submit taking place... please make it stop!');
//validateForm(e);
Event.stop(e);
e.stopPropagation();
e.cancelBubble = true;
console.log(e);
alert('Stop the default submit!');
return false;
}, false);
});
Nothing stops the "submitPage()" from being called! The observe actually works and triggers the console message and shows the alert for a second. Then the "submitPage()" kicks in and everything goes bye-bye. I've removed the onclick attached to the button in Firebug, and my validation and alert all work as intended, so it leads me to think that the propagation isn't really being stopped for the onclick?
What am I missing?
So based on the fact that you can't change the HTML - here's an idea.
leave your current javascript as is to catch the click event - but add this to the dom:loaded event
$('submitBtnSaveId').writeAttribute('onclick',null);
this will remove the onclick attribute so hopefully the event wont be called
so your javascript will look like this
document.observe("dom:loaded", function() {
$('submitBtnSaveId').writeAttribute('onclick',null);
Element.observe('submitBtnSaveId', 'click', function (e) {
console.log('Noticed a submit taking place... please make it stop!');
//validateForm(e);
Event.stop(e);
e.stopPropagation();
e.cancelBubble = true;
console.log(e);
alert('Stop the default submit!');
return false;
submitPage('save', 'auto', e);
//run submitPage() if all is good
}, false);
});
I took the idea presented by Geek Num 88 and extended it to fully meet my need. I didn't know about the ability to overwrite the attribute, which was great! The problem continued to be that I needed to run submitPage() if all is good, and that method's parameters and call could be different per page. That ended up being trickier than just a simple call on success. Here's my final code:
document.observe("dom:loaded", function() {
var allButtons = $$('input[type=button]');
allButtons.each(function (oneButton) {
if (oneButton.value === 'Save') {
var originalSubmit = oneButton.readAttribute('onclick');
var originalMethod = getMethodName(originalSubmit);
var originalParameters = getMethodParameters(originalSubmit);
oneButton.writeAttribute('onclick', null);
Element.observe(oneButton, 'click', function (e) {
if (validateForm(e)) {
return window[originalMethod].apply(this, originalParameters || []);
}
}, false);
}
});
});
function getMethodName(theMethod) {
return theMethod.substring(0, theMethod.indexOf('('))
}
function getMethodParameters(theMethod) {
var parameterCommaDelimited = theMethod.substring(theMethod.indexOf('(') + 1, theMethod.indexOf(')'));
var parameterArray = parameterCommaDelimited.split(",");
var finalParamArray = [];
parameterArray.forEach(function(oneParam) {
finalParamArray.push(oneParam.trim().replace("'","", 'g'));
});
return finalParamArray;
}

jQuery hashchange how to do?

I have made a jQuery thing; with will load content without refreshing the page. The code for that is:
$(document).ready(function(){
// initial
$('#content').load('content/index.php');
// handle menu clicks
$('#navBar ul li ').click(function(){
var page = $(this).children('a').attr('href');
$('#content').load('content/'+ page +'.php');
return false;
});
});
Now I want to have a sort of history thing in that, the code for that is:
(function(){
// Bind an event to window.onhashchange that, when the hash changes, gets the
// hash and adds the class "selected" to any matching nav link.
$(window).hashchange( function(){
var hash = location.hash;
// Set the page title based on the hash.
document.title = 'The hash is ' + ( hash.replace( /^#/, '' ) || 'blank' ) + '.';
// Iterate over all nav links, setting the "selected" class as-appropriate.
$('#nav a').each(function(){
var that = $(this);
that[ that.attr( 'href' ) === hash ? 'addClass' : 'removeClass' ]( 'selected' );
});
})
// Since the event is only triggered when the hash changes, we need to trigger
// the event now, to handle the hash the page may have loaded with.
$(window).hashchange();
});
Found on: http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
My Question is: how can i make the second code working with the first?
Since you haven't gotten an answer yet I will write it. You need the plugin jQuery hashchange for the code to run.
https://github.com/cowboy/jquery-hashchange
To implement a cache you could do something like
$('#content').load('content/index.php');
//create a cache object
var cache = {};
// handle menu clicks
$('#navBar ul li ').click(function(){
var page = $(this).children('a').attr('href');
//check if the page was already requested
if(cache[page] === undefined){
//if not fetch the page from the server
$.get('content/'+ page +'.php', function(data){
$('#content').html(data);
//save data in cache
cache[page] = data;
}else{
//use data from cache
$('#content').html(cache[page]);
}
return false;
});
Use History JS. It works for HTML5 pushState and also falls back to HTML 4 hashtags. Also works for keeping the state model when the page is refreshed.

jquery mobile ajax sends both GET and POST requests

Here is the problem:
By default jQuery Mobile is using GET requests for all links in the application, so I got this small script to remove it from each link.
$('a').each(function () {
$(this).attr("data-ajax", "false");
});
But I have a pager in which I actually want to use AJAX. The pager link uses HttpPost request for a controller action. So I commented the above jQuery code so that I can actually use AJAX.
The problem is that when I click on the link there are two requests sent out, one is HttpGet - which is the jQuery Mobile AJAX default (which I don't want), and the second one is the HttpPost that I actually want to work. When I have the above jQuery code working, AJAX is turned off completely and it just goes to the URL and reloads the window.
I am using asp.net MVC 3. Thank you
Instead of disabling AJAX-linking, you can hijack clicks on the links and decide whether or not to use $.post():
$(document).delegate('a', 'click', function (event) {
//prevent the default click behavior from occuring
event.preventDefault();
//cache this link and it's href attribute
var $this = $(this),
href = $this.attr('href');
//check to see if this link has the `ajax-post` class
if ($this.hasClass('ajax-post')) {
//split the href attribute by the question mark to get just the query string, then iterate over all the key => value pairs and add them to an object to be added to the `$.post` request
var data = {};
if (href.indexOf('?') > -1) {
var tmp = href.split('?')[1].split('&'),
itmp = [];
for (var i = 0, len = tmp.length; i < len; i++) {
itmp = tmp[i].split('=');
data.[itmp[0]] = itmp[1];
}
}
//send POST request and show loading message
$.mobile.showPageLoadingMsg();
$.post(href, data, function (serverResponse) {
//append the server response to the `body` element (assuming your server-side script is outputting the proper HTML to append to the `body` element)
$('body').append(serverResponse);
//now change to the newly added page and remove the loading message
$.mobile.changePage($('#page-id'));
$.mobile.hidePageLoadingMsg();
});
} else {
$.mobile.changePage(href);
}
});
The above code expects you to add the ajax-post class to any link you want to use the $.post() method.
On a general note, event.preventDefault() is useful to stop any other handling of an event so you can do what you want with the event. If you use event.preventDefault() you must declare event as an argument for the function it's in.
Also .each() isn't necessary in your code:
$('a').attr("data-ajax", "false");
will work just fine.
You can also turn off AJAX-linking globally by binding to the mobileinit event like this:
$(document).bind("mobileinit", function(){
$.mobile.ajaxEnabled = false;
});
Source: http://jquerymobile.com/demos/1.0/docs/api/globalconfig.html

jquery: bind click event to ajax-loaded elmente? live() won't work?

hey guys,
I have an input field that looks for matched characters on a page. This page simply lists anchor links. So when typing I constantly load() (using the jquery load() method) this page with all the links and I check for a matched set of characters. If a matched link is found it's displayed to the user. However all those links should have e.preventDefault() on them.
It simply won't work. #found is the container that shows the matched elements. All links that are clicked should have preventDefault() on them.
edit:
/*Animated scroll for anchorlinks*/
var anchor = '',
pageOffset = '',
viewOffset = 30,
scrollPos = '';
$(function() {
$("a[href*='#']").each(function() {
$(this).addClass('anchorLink');
$(this).bind('click', function(e) {
e.preventDefault();
//console.log('test');
anchor = $(this).attr('href').split('#')[1];
pageOffset = $("#"+anchor).offset();
scrollPos = pageOffset.top - viewOffset;
$('html, body').animate({scrollTop:scrollPos}, '500');
})
});
});
Well, I'm looking for all href's that contain a #. So I know those elements are anchors that jump to other elements. I don't want my page to jump, but rather scroll smoothly to this element with this specific #id.
This works fine when I use bind('click', ... for normal page-elements that have been loaded when the page is opened. It doesn't work for anchors that have been loaded via ajax! If I change the bind to live nothing does change for the ajax loaded elements - they still don't work. However normal anchors that have always been on the page are not triggering the function as well. So nothing works with live()!
When you say "it won't work" do you mean that your function is not been called or that you can not cancel out of the function? As far as I know you can not cancel out live events. With jQuery 1.4 you can use return false to cancel out live event propagation. Calling e.preventDefault() won't work.
Edit: right so this code should in principal work. What it still won't do is, it won't add the 'anchorLink' class to your new anchors. However if the clicks work then let me know and I will give you the right code to add the class too!
var anchor = '',
pageOffset = '',
viewOffset = 30,
scrollPos = '';
$(function() {
$("a[href*='#']").each(function() {
$(this).addClass('anchorLink');
});
$("a").live('click', function(e) {
if ($(this).attr("href").indexOf("#") > -1) {
e.preventDefault();
//console.log('test');
anchor = $(this).attr('href').split('#')[1];
pageOffset = $("#" + anchor).offset();
scrollPos = pageOffset.top - viewOffset;
$('html, body').animate({ scrollTop: scrollPos }, '500');
//nikhil: e.preventDefault() might not work, try return false here
}
});
});

How to execute a page ,that contains JS ,in AJAX ,using innerHTML?

I send GET data with AJAX to another file.And on the another file I have echo "<script>alert('Something');</script>";.This is displayed dynamicly with AJAX ,i.e
var ajaxDisplay = document.getElementById('edit');
ajaxDisplay.innerHTML = ajaxRequest.responseText;
puts the <script>alert('Something');</script> to div with name edit.
But it doesn't alert anything.
How to get it work?
I have mixed html/javascript.
Here is the code.
function ajaxFunctions(){
var ajaxRequest; // The variable that makes Ajax possible!
try{
// Opera 8.0+, Firefox, Safari
ajaxRequest = new XMLHttpRequest();
} catch (e){
// Internet Explorer Browsers
try{
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try{
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e){
// Something went wrong
alert("Your browser broke!");
return false;
}
}
}
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange = function(){
if(ajaxRequest.readyState == 4){
var ajaxDisplay = document.getElementById('edit');
ajaxDisplay.innerHTML = ajaxRequest.responseText;
}
}
var namef = document.getElementById('nameed').value;
var queryString = "?namef=" + namef;
ajaxRequest.open("GET", "try.php" + queryString, true);
ajaxRequest.send(null);
}
Maybe to find the script tags and to eval them?
But how to find the script tags?
Instead of trying to inject a script element in the DOM, just have your script return:
alert('Something');
And then use eval(response); to run it. Or you could add a script element with the src attribute pointing to the page that returns your JavaScript into the <head> (which is the preferred method).
function loadScript(url) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
head.appendChild(script);
}
Keep in mind that this wont work for cross-domain requests--the script has to have the same origin as the page running your code. To get around this, you'll have to use a callback.
It looks like the only purpose of setting innerHTML is an attempt to get the JS to execute. But once the page is loaded, JS won't 'know' that it needs to parse and execute the new text you've changed, so your method won't work. In this case, what you want is a callback function:
http://api.jquery.com/jQuery.ajax/
I haven't used jQuery, but it looks like you'd simply add a 'complete' property to the settings object you pass to the .ajax() call, like so:
$.ajax({
// ......
complete: function(){
alert('Something');
}
// ......
});
In this case, the callback function would execute once the ajax call has completed. You can pick other events, such as on success, on failure, and so on, if you need to attach your code to a different event.
But how to find the script tags?
Well, parent.getElementsByTagName('script') and then evaling the data of the text node inside will do it.
However, inserting content that includes script tags is unreliable and works slightly differently across browsers. eg. IE will execute the script the first time the script node is inserted into any parent, inside the document or not, whilst Firefox will execute script the first time a subtree including the script is added to a node inside the document. So if you're not extremely careful, you can end up executing scripts twice on some browsers, or executing the script at the wrong time, following a further page manipulation.
So don't. Return script that you want to execute separately to any HTML content, eg. using a JSON object containing both the HTML and the JavaScript seperately.

Resources