Execution of JS command on load completed of external widget - javascript

In this question i use addthis widget as an example, but it's really true for any widget (if generalization is possible)
addthis is a widget that adds all the social linking to a webpage. However it comes with very limited design customization options. So in order to make it fit to my theme I need to transfer the a tag that are generated by addthis into my own html/css structure.
I tried to use JQuery append method on document ready:
$(document).ready(function(){
var addthis = $("#atftbx");
});
However the array that was returned by $("#atftbx") was empty [], which means jquery didn't find the element on the page. I assume that at the point of execution of $(document).ready the widget hasn't been loaded yet. Is there any event that i can listen to and then execute? is there any other way which it can be done?
Not that it matters but just for reference purposes, here is an example of what the widget generates.
<div class="addthis_custom_follow">
<div id="atftbx" class="at-follow-tbx-element addthis-smartlayers animated at4-show">
<p><span> </span></p>
<div class="addthis_toolbox addthis_default_style addthis_32x32_white_style circular">
<a class="addthis_button_facebook_follow...">
<span class="at300bs at15nc at15t_facebook">
<span class="at_a11y">Follow on Facebook</span>
</span><span class="addthis_follow_label">Facebook</span>
</a>
<a class="......
</a>

Try to use this:
function addthisReady(evt) {
// your jQuery code
}
addthis.addEventListener('addthis.ready', addthisReady);
For more info look at http://support.addthis.com/customer/portal/articles/1365497-addthis-javascript-events
EDIT:
For the general purpose I can assume, that you can use event DOMSubtreeModified to execute your code, when widget will change HTML of widget's container, like that:
var isChanged = false;
$(".widget_container").bind("DOMSubtreeModified", function() {
if (! isChanged) {
isChanged = true;
// your code
}
});
but it's better to use widget's built-in events, because DOMSubtreeModified is buggy in IE 9 (http://help.dottoro.com/ljrmcldi.php)

Related

jQueryTOOLS Overlay lightbox not functioning when HTML/LINK is loaded via ajax

Before starting, I have researched and found this similar, previous question: Reinitialize jQuerytools Overlay on ajax loaded element
However, the "answer" to that question suggests using .live(). I attempted to us jQuery 1.9 .live() is not a function to update using .on().
$(".overlay_load[rel]").on('click', 'a', function () {
$(this).overlay().load();
$(this).overlay().load();
return false;
});
I will admit I don't 100% understand exactly what that is doing other than perhaps re-initializing the newly loaded HTML so that jQueryTOOLS Overlay has 'access' to the newly loaded HTML.
I have a page loading sections of HTML content via AJAX. Here is an example of one DIV that is loaded.
<div class="ajax-returned mytop">
<span class="username"> drkwong </span> <br>
<span class="full-name">Andrew Kwong</span><br>
<span class="action-status">
<span class="mt-icon ut3"></span>
<span class="autoship active">A</span>
<span class="view_profile">
<a href="/member/downline_tree_view/?view=tree_profile&program=1&view_userid=13" rel="#overlay">
<img src="/inc/downline_tree/images/more_info.png" rel="#13">
</a>
</span>
</span>
</div>
<!-- overlayed element -->
<div class="apple_overlay" id="overlay">
<!-- the external content is loaded inside this tag -->
<div class="contentWrap"></div>
</div>
This has a link that should engage a jQuery and then load a jQueryTOOLS Overlay lightbox:
<script>
$(function() {
// if the function argument is given to overlay,
// it is assumed to be the onBeforeLoad event listener
$("a[rel]").overlay({
mask: 'grey',
effect: 'apple',
onBeforeLoad: function() {
// grab wrapper element inside content
var wrap = this.getOverlay().find(".contentWrap");
// load the page specified in the trigger
wrap.load(this.getTrigger().attr("href"));
}
});
});
</script>
This is the jQuery I am using to load an external page into a Light Box: http://jquerytools.github.io/demos/overlay/external.html
It simply feels like it's not triggering the jQuery.
Here's what's in the header:
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript" src="/templates/public/2/downline/js/jquery.browser.min.js"></script>
<script type="text/javascript" src="/templates/public/2/downline/js/jquery.tools.min.js"></script>
The jquery.browser.min.js is required by jQueryTOOLS Overlay to access browsers. https://github.com/gabceb/jquery-browser-plugin
EDIT:
AJAX
var ids=new Array()
var node
var param={"action":"NodeDetailAll","admin":"1"}
var users=new Array()
function get_ids(){
for(var i=0;i<nodes.length;i++){
users.push("child_"+$(nodes[i]).attr("class"))
ids.push($(nodes[i]).attr("class"))
}
}
function get_nodes(){
nodes = $("#chart [myattr*='descendent']")
nodes= jQuery.makeArray(nodes);
$.when(get_ids()).then(function(){
$.each(ids,function(key,value){
param[users[key]]=value
})
})
}
function write_html(response){
$.each(response,function(key,value){
$("."+key).html(value)
})
}
jQuery(document).ready(function() {
$(".spinner-loader").fadeIn(200)
$.when(get_nodes()).then(function(){
$.post("~ajax_url~",param,function(response) {
response=jQuery.parseJSON(response)
$.when(write_html(response)).done(function() {
$(".spinner-loader").fadeOut(600)
$("#chart").css("opacity","1")
// is this where I would add the on()? //
// I tried that, without success. //
// perhaps I need to modify the on() function? //
})
})
})
})
You could call the overlay binding on the callback of your ajax function. The other thing would be is to check your jQuery selectors to make sure you have them configured appropriately and that they are selecting the appropriate element to bind your event to.
As per the jQuery documentation: "Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on()."
so it does seem to me that calling the binding functionality in the callback of your AJAX request would be the way to go! Perhaps if you could provide a simplified version of your code, ajax request included then I could try and take another look :)
Use a different solution. jQueryTOOLS Overlay is no longer active and uses deprecated and even eliminated jQuery functions. Trying to solve all those issues has proven both inefficient and so far as AJAX is related, impossible with the latest versions of jQuery.
As suggested by #sparky FancyBox 2 provided the needed solution. It was simple and intuitive to implement.

How to lazy-load an inline javascript?

I want to load a banner ad script only when specific div is reached. For example - banner div at the bottom of the page.
I can load external scripts by using jquery lazy script:
var options = {
type: "visible",
id:"mydiv", //div Id
scripts: [
"1.js",
"2.js",
"3.js"
],
success: function () {
}
};
$.lazyscript(options);
But how to load inline scripts?
Thanks.
The entire html document is parsed top to bottom, script tags included. So in that sense, your inline javascript is "loaded." I may be misunderstanding your question.
If you didn't want your inline script to be executed as soon as it was parsed you would need to use some kind of event listener in the inline script.
For example, assuming your inline banner ad code is wrapped in a function
<script>
loadBannerScriptAd()
</script>
you would need to write something like
<script>
$(document).on("loadBannerScript", loadBannerScriptAd)
</script>
which you could trigger at any point by
$(document).trigger("loadBannerScript")
All of this is assuming you have jquery based on your code sample you gave above. Check out http://api.jquery.com/trigger/ for detailed information on how you could trigger custom events via jquery.
You can try my project jquery-lazyload-any
Html
<div id="you-want-lazyload">
<!--
<script>doSomething();</script>
-->
</div>
JavaScript:
$('#you-want-lazyload').lazyload(options);
or
other one jquery-appear
Html
<div id="you-want-to-detect">
</div>
JavaScript
$('#you-want-to-detect').bind('appear', doSomething); // you have to unbind event if you want to trigger only once

Override default javascript functionality with jQuery

I am trying to overwrite a JavaScript on change event in the below code with jQuery however I believe that the inline JavaScript is taking priority over the jQuery functionality declared. Essentially I am trying to have an AJAX version of my site which includes an additional JavaScript file. I need this functionality to still work without the additional AJAX version, but I am not sure as to whether I should include it in the main JavaScript file or leave it inline like it is right now. Any suggestions and information regarding them would be greatly appreciated! Thanks!
<form action="/cityhall/villages/" method="post" name="submit_village">
<select name="village" onchange="document.submit_village.submit();">
<option value=""></option>
</select>
</form>
I am trying to use the jQuery Form Plugin to submit the posts to the PHP to handle the requests as follows:
var bank_load_options = {
target: '#content',
beforeSubmit: showRequest,
success: showResponse
};
$('form.get_pages').livequery(function(){
$(this).ajaxForm(bank_load_options);
return false;
});
I modified the code as following:
<form action="/cityhall/villages/" method="post" id="submit_village" name="submit_village">
<select name="village" class="get_pages" rel="submit_village">
<option value=""></option>
</select>
</form>
<script>
# main JavaScript
$('.get_pages').live('change',function(e){
var submit_page = $(this).attr('rel');
$("#"+submit_page).submit();
});
# ajax JavaScript
var bank_load_options = {
target: '#content',
beforeSubmit: showRequest,
success: showResponse
};
$('.get_pages').live('change',function(){
var submit_page = $(this).attr('rel');
$("#"+submit_page).ajaxForm(get_pages_load_options);
return false;
});
</script>
However now it only runs every other option when I change it.
Does your non-ajax version also have to be non-jQuery? If not then I also suggest (as #nnnnnn did) that you do away with the onxyz attributes and use jQuery throughout.
As other posters have suggested, inline events are inadvisable and should be done away with.
If your non-ajax version has to use onxyz then I'd suggest the following:
Setup a variable that will store whether this version is to be ajax or not (how you determine this is down to you and your app context):
var is_ajax = true;
Then if it is an ajax version try this:
$(function(){
if(is_ajax){
//Unbind the change event from the village select box
$('select[name="village"]').unbind('change');
//As an extra measure, remove the onchange attribute
$('select[name="village"]').removeAttr('onchange');
//Re-bind the click event to execute your new ajax functionality
$(document).on('change','select[name="village"]',function(){
//Do ajax stuff for on-change event here
});
}
});
Because it sits in the document.ready function of jQuery this code should fire after the html dom (and it's associated onchange attributes) have been rendered. Therefore I'd imagine it'd effectively strip off the old event and re-bind a new one.
Demo:
http://jsfiddle.net/foxwisp/hdL5R/
If you can do away with the inline events then I imagine you'd want to do this in your initial javascript file:
$(document).on('change','select[name="village"]',function(){
document.submit_village.submit();
});
And then the following in your ajax file to be included later:
$('select[name="village"]').removeAttr('onchange');
$(document).on('change','select[name="village"]',function(){
//Do ajax stuff here
});
As long as both are in the same scope and timeframe such that they're executed one after the other then the above should work.
It is good practice to have all your Javascript in one place (not one file specifically, but not half inline, half in a file), as such I would remove all inline Javascript.
This would also your help with priority issue as you can manage it all from the same location.
Where you put your javascript is (largely) a choice of style. Much like CSS, putting javascript in the page source (inline) or in the page head is good practice for writing your page initially but bad practice for production pages.
That being said, I am a bit confused as to why you would double up your onchange events. Are you trying to use jQuery for the select element too?
I am not sure what the general behavior is for inline vs separate javascript, but I would venture to say that, similar to inline CSS, the in-page javascript will take precedence over an external file.
In this particular case, you could, in your AJAX version, forego the submit that has been triggered.
$('[name=submit_village]').on('submit', function(e) {
e.preventDefault();
//...Maybe other AJAX code...
});

Click event not processed when using prototype (with lowpro)

I have JS code that uses lowpro (prototype extension) to reorder a set of dynamically generated questions. So when I click a.move-up I want to move that element's parent up. And a.move-down suppose to move it down.
I'm using lowpro since the elements are generated after dom:loaded.
http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype
JS code:
document.observe('dom:loaded', function() {
Event.addBehavior( {
'a.move-up:click': function(event) {
alert('Moving up!')
//moveUp(this);
//event.stop();
},
'a.move-down:click': function(event) {
alert('Moving down!')
//moveDown(this);
//event.stop();
}
});
});
I have two links for each element (div.question) that allow that element to be moved up or down. However these click events don't get processed.
<div id="questions">
<div class="question">Q1 stuff
<a href="#" class="move-up" />Up</a>
<a href="#" class="move-down"/>Down</a>
</div>
<div class="question">Q2 stuff
<a href="#" class="move-up" />Up</a>
<a href="#" class="move-down"/>Down</a>
</div>
</div>
As part of debugging I've cut down the code to bare minimum, just trying to make sure event handling works. I don't even see the alert pop-up when I click the JS-backed links. So the "click" event isn't being handled properly.
What am I doing wrong???
Thank you!
After doing some reading/research I realized that elements that are generated dynamically...
wait for it...
are not registered/bound after DOM loads, thus the addBehavior needs to be reload()-ed for it to pick up new elements.
So after dynamically generating new elements, there has to be a call to
Event.addBehavior.reload();
After that call, new dynamically-generated elements can be moved up/down just like I want.
I knew it had to be something as simple and obvious as that... sigh

Activate jquery ui widgets within dynamically loaded form

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.

Categories

Resources