Trigger click() for dynamically created elements - javascript

Ok, there are a couple approaches to the problem of triggering a click() for a dynamically-generated element. First, this will work for Chrome but not IE or FF:
var href="/myUrl";
var link = $("<a>");
link.prop("href", href);
link[0].click()
So, if the thinking is that using click() on an element that doesn't exist won't work in IE or FF, what's the best approach?
var href="/myUrl";
var link = $("<a>");
link.prop("href", href);
$(document).append(link); // Attach it to the DOM so it exists
link[0].click()
Or is there something even simpler that I'm missing? Thanks for any helpful tips.

You've said you want to trigger the download of a file. Another simple way to do that is to have an invisible iframe on the page:
<iframe src="about:blank" style="display: none" id="downloader"></iframe>
...then when you want to trigger the download:
$("#downloader").attr("src", "/myUrl");
As with your current solution, it's important that the response containing the file have a Content-Disposition header identifying it as an "attachment" (the same header can also suggest a name), to get consistent handling across MIME types.

The following is a function that I've used in production code, it's a bit different from yours but it might be what you need.
function psuedoClick(href, target){
if(!target) target = '_self';
var falseAnchor = $('<a/>').attr({
'href' : href,
'target' : target
}).appendTo('body');
falseAnchor[0].click();
falseAnchor.remove();
};
Just pass in the arguments when you call the function and it'll work.

Related

Suppressing an onclick link event without stopping the actual page re-direct

Is there a way to disable the onclick function but still use the href to re-direct the user to the requested link. Example a header menu there are many links that looks like below :
Phones
I am unable to remove the "DA_A('id', ':per:shop', this.href); return false;" from the HTML page. However using a tag manager how would one go about injecting a snippet of JavaScript code function which will de-activate/mute the "DA_A" function but still make the link work as normal? Is it possible? It seems the function "DA_A" is a function that calls another ".push" function and pass some data.
What are my options? as I am unable to edit the menus in questions?
You can probably remove the onclick from the element if you can run some javascript after the DOM renders:
var anchor = document.getElementById("someId"); // or tagname, querySelector, etc
anchor.onclick = "";
You could also disable the function it calls altogether, depending on whether it is needed elsewhere:
window.DA_A = function() { /* do nothing */ };
The first snippet would need to be run after the DOM was rendered (for example, if you are using jquery then enclose it in a $(function() {})), and the second snippet would need to run after the DA_A function is defined in the first place.
Either of these by themselves should disable the onclick, but still allow the anchor to navigate.
this code snippet will do the trick:
window.onload = function()
{
document.querySelctor("a").removeAttribute("onclick"); // make selector more specific
};

Why does DOM appendChild() fire on('load', ...) but jQuery append() does not?

I have the following to snippets of code:
$(document).ready(function() {
document.head.appendChild(
$('<script />').attr('src', 'source.js').on('load', function() {
...
})[0]
);
});
This will fire the load handler.
Whereas using the normal jQuery append():
$(document).ready(function() {
$('head').append(
$('<script />').attr('src', 'source.js').on('load', function() {
...
})
);
});
This will not fire the load hander.
What am I missing: why does jQuery append() not work?
Is using document.head.appendChild() a bad idea?
NOTE: I can't use $.getScript(). The code will run on a local file system and chrome throws cross site script errors.
Update
Some people had trouble reading the compact style, so I used extra line feeds to clarify which objects where calling which methods. I also made it explicit that my code is inside a $(document).ready block.
Solution
In the end I went with:
$(document).ready(function() {
$('head')[0].appendChild(
$('<script />').attr('src', 'source.js').on('load', function() {
…
})[0]
);
});
I think #istos was right in that something in domManip is breaking load.
jQuery is doing some funny business in its DOM manipulation code. If you look at jQuery's source, you'll see that it uses a method called domManip() inside the append() method.
This domManip() method creates a document fragment (it looks like the node is first appended to a "safe" fragment) and has a lot of checks and conditions regarding scripts. I'm not sure why it uses a document fragment or why all the checks about scripts exist but using the native appendChild() instead of jQuery's append() method fires the event successfully. Here is the code:
Live JSBin: http://jsbin.com/qubuyariba/1/edit
var url = 'http://d3js.org/d3.v3.min.js';
var s = document.createElement('script');
s.src = url;
s.async = true;
$(s).on('load', function(e) {
console.log(!!window.d3); // d3 exists
$(document.body).append('<h1>Load fired!</h1>');
});
$('head').get(0).appendChild(s);
Update:
appendChild() is a well supported method and there is absolutely no reason not to use it in this case.
Maybe the problem is when you choose DOM appendChild, actually you called the function is document.on('load',function(){});, however when you choose jQuery append(), your code is $('head').on('load', function(){}).
The document and head are different.
You can type the code below:
$(document).find('head').append($('<script />').attr('src', 'source.js').end().on('load', function() {
...
}));
You should probably make sure that the jquery append is fired when the document is ready. It could be that head is not actually in the dom when the append fires.
you don't have to ditch jquery completely, you could use zeptojs. Secondly, I couldn't find out how and why exactly this behavior is happening. Even though i felt answer was to be found in links below. So far i can tell that if you insert element before definig src element then load won't fire.
But for manual insertion it doesn't matter. (????)
However, what i was able to discover is that if you use appendTo it works.
Code :http://jsfiddle.net/techsin/tngxnkk7/
var $ele = $('<script />').attr('src', link).load(function(){ abc(); }) ).appendTo('head');
New Info: As is understood adding script tag to dom with src attribute on it, initiates the download process of script mentioned in src. Manual insertion causes page to load external script, using append or appendTo causes jquery to initiate downloading of external js file. But event is attached using jquery and jquery initiates download then event won't fire. But if it's the page itself initiates the download then it does. Even if event is added manually, without jquery, adding via jquery to dom won't make it fire.
Links in which i think should be the answer...
Append Vs AppendChild JQuery
http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/
http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/
https://github.com/jquery/jquery/blob/master/src/manipulation.js#L477-523
http://ejohn.org/blog/dom-documentfragments/

How can I tell if a page has jumped to the anchor (#) in JavaScript?

I have some JavaScript that can appear on many different pages. Sometimes those pages have been accessed via a URL containing an anchor reference (#comment-100, for instance). In those cases I want the JavaScript to delay executing until after the window has jumped. Right now I'm just using a delay but that's pretty hackish and obviously doesn't work in all cases. I can't seem to find any sort of DOM event that corresponds to the window "jump".
Aside from the simple delay, the only solution I've come up with is to have the JS look for the anchor in the URL and, if it finds one, watch for changes in scrollTop. But that seems buggy, and I'm not 100% sure that my script will always get fired before the scrolling happens so then it would only run if the user manually scrolled the page. Anyhow, I don't really like the solution and would prefer something more event driven. Any suggestions?
Edit to clarify:
I'm not trying to detect a hash change. Take the following example:
Page index.php contains a link to post.php#comment-1
User clicks the link to post.php#comment-1
post.php#comment-1 loads
$(document).ready fires
Not long later the browser scrolls down to #comment-1
I'm trying to reliably detect when step 5 happens.
You can check window.onhashchange in modern browsers. If you want cross compatible, check out http://benalman.com/projects/jquery-hashchange-plugin/
This page has more info on window.onhashchange as well.
EDIT: You basically replace all anchor names with a similar linking convention, and then use .scrollTo to handle the scrolling:
$(document).ready(function () {
// replace # with #_ in all links containing #
$('a[href*=#]').each(function () {
$(this).attr('href', $(this).attr('href').replace('#', '#_'));
});
// scrollTo if #_ found
hashname = window.location.hash.replace('#_', '');
// find element to scroll to (<a name=""> or anything with particular id)
elem = $('a[name="' + hashname + '"],#' + hashname);
if(elem) {
$(document).scrollTo(elem, 800,{onAfter:function(){
//put after scroll code here }});
}
});
See jQuery: Scroll to anchor when calling URL, replace browsers behaviour for more info.
Seems like you could use window.onscroll. I tested this code just now:
<a name="end" />
<script type="text/javascript">
window.onscroll = function (e) {
alert("scrolled");
}
</script>
which seems to work.
Edit: Hm, it doesn't work in IE8. It works in both Firefox and Chrome though.
Edit: jQuery has a .scroll() handler, but it fires before scrolling on IE and doesn't seem to work for Chrome or Firefox.
To detect when the element appears on the screen, use the appear plugin:
$('#comment-1').appear(function() {
$(this).text('scrolled');
});

Adding an event listener to an iframe

Is it possible to add an event listener to an iframe? I've tried this code, but it doesn't seem to work:
document.getElementsByTagName('iframe')[0].contentWindow.window.document.body.addEventListener('afterLayout', function(){
console.log('works');
});
I've also just tried using getting the element by id and adding my listener via the JavaScript framework I'm using, like this:
Ext.fly("iframeID").addListener('afterLayout', function(){ alert('test'); });
I can call functions in the iframe, so I don't think security is an issue. Any ideas?
I never tried to handle 'afterLayout' event but for more browser compatible code
you'll use (iframe.contentWindow || iframe.contentDocument) instead of iframe.contentWindow .
try something like
var iframe = document.getElementsByTagName('iframe')[0],
iDoc = iframe.contentWindow // sometimes glamorous naming of variable
|| iframe.contentDocument; // makes your code working :)
if (iDoc.document) {
iDoc = iDoc.document;
iDoc.body.addEventListener('afterLayout', function(){
console.log('works');
});
};
Hope it'll help.
If you are doing serious iframe work in Ext, you should look into the ManagedIFrame user extension:
http://www.extjs.com/forum/showthread.php?t=40961
It features built-in events and cross-frame messaging, as well as many other benefits.
Reasons for failure could be:-
The URL to which the iframe is directed from a different domain as the container, hence code is prevented by cross-domain script blocking.
The code is running before the frame content is loaded

Reload an IFRAME without adding to the history

I'm changing an IFRAME's src in order to reload it, its working fine and firing the onload event when its HTML loads.
But it adds an entry to the history, which I don't want. Is there any way to reload an IFRAME and yet not affect the history?
Using replace() is only an option with your own domain iframes. It fails to work on remote sites (eg: a twitter button) and requires some browser-specific knowledge to reliably access the child window.
Instead, just remove the iframe element and construct a new one in the same spot. History items are only created when you modify the src attribute after it is in the DOM, so make sure to set it before the append.
Edit: JDandChips rightly mentions that you can remove from DOM, modifiy, and re-append. Constructing fresh is not required.
You can use javascript location.replace:
window.location.replace('...html');
Replace the current document with the
one at the provided URL. The
difference from the assign() method is
that after using replace() the current
page will not be saved in session
history, meaning the user won't be
able to use the Back button to
navigate to it.
Like Greg said above, the .replace() function is how to do this. I can't seem to figure out how to reply to his answer*, but the trick is to reference the iFrames contentWindow property.
var ifr = document.getElementById("iframeId");
ifr.contentWindow.location.replace("newLocation.html");
*Just learned I need more reputation to comment on an answer.
An alternative method to recreating the iframe would be to remove the iframe from the DOM, change the src and then re add it.
In many ways this is similar to the replace() suggestion, but I had some issues when I tried that approach with History.js and managing states manually.
var container = iframe.parent();
iframe.remove();
iframe.attr('src', 'about:blank');
container.append(iframe);
One solution is to use the object tag rather than the iframe tag.
Replacing this:
<iframe src="http://yourpage"/>
By this:
<object type="text/html" data="http://yourpage"/>
will allow you to update the data attribute without affecting the history. This is useful if you use a declarative framework such as React.js where you are not supposed to do any imperative command to update the DOM.
More details on differences between iframe and object: Use of Iframe or Object tag to embed web pages in another
Try to use this function to replace old iframe with new iframe which is copied from old one:
function setIFrameSrc(idFrame, url) {
var originalFrame = document.getElementById(idFrame);
var newFrame = document.createElement("iframe");
newFrame.id = originalFrame.getAttribute("id");
newFrame.width = originalFrame.getAttribute("width");
newFrame.height = originalFrame.getAttribute("height");
newFrame.src = url;
var parent = originalFrame.parentNode;
parent.replaceChild(newFrame, originalFrame);
}
Use it like this:
setIFrameSrc("idframe", "test.html");
This way will not add URL of iframe to browser history.
Use the replace method to bypass the addition of the iframe's URL to history:
HTML:
<iframe id="myIframe" width="100%" height="400" src="#"></iframe>
JavaScript:
var ifr = document.getElementById('mIframe')
if (ifr) {
ifr.contentWindow.location.replace('http://www.blabla.com')
}
JDandChips answer worked for me on a cross origin iframe (youtube), here it is in vanilla JS (without JQuery):
const container = iframe.parentElement;
container.removeChild(iframe);
iframe.setAttribute('src', 'about:blank');
container.appendChild(iframe);
The most simple and fast loading solution
Use window.location.replace to not update the history when loading the page or the frame.
For links it looks like this:
<a href="#" onclick="YourTarget.location.replace ('http://www.YourPage.com');">
The targeted Link</a>
or
<a href="javascript:YourTarget.location.replace ('http://www.YourPage.com');">
The targeted Link</a>
But if you want it not to act from link but to act automatically when loading the frame then from the iframe you should put this in the iframe file body section:
onload="window.location.replace ('http://www.YourPage.com');"
If for some reason the onload does not load in the iframe then put your target frame name instead of window in the syntax like this:
onload="YourTarget.location.replace ('http://www.YourPage.com');"
NOTE: For this script all onclick, onmouseover, onmouseout , onload and href="javascript:" will work.
#JDandChips has a great answer above, but the syntax should be updated from parent() to parentElement:
var container = iframe.parentElement;
iframe.remove();
iframe.attr('src', 'about:blank');
container.append(iframe);

Categories