Which one happens first? WebComponentsReady or dom-change? - javascript

I just started on Polymer. There seems to be two events indicating content is ready:
// Listen for template bound event to know when bindings
// have resolved and content has been stamped to the page
app.addEventListener('dom-change', function() {
console.log('Our app is ready to rock!');
});
// See https://github.com/Polymer/polymer/issues/1381
window.addEventListener('WebComponentsReady', function() {
// imports are loaded and elements have been registered
});
I wonder if it is necessary to wrap them together and put the code inside, to make sure that the document is fully loaded before doing any script, for example:
app.addEventListener('dom-change', function() {
window.addEventListener('WebComponentsReady', function() {
// scripts go here
});
});
However, I don't know what is the correct way to do so in all browsers. If WebComponentsReady happens before dom-change, the inside script never execute.
Heck, this might not even be necessary because the polymer-starter-kit doesn't wrap them together. In that case, which types of script should go inside dom-change event and which types of script should go inside WebComponentsReady event?

Use the native ready callback as described here.
<script>
(function() {
Polymer({
is: 'example-element',
properties: {...},
ready: function() {
// access a local DOM element by ID using this.$
this.$.header.textContent = 'Hello!';
}
});
})();
</script>

Related

javascript custom listener - when element is loaded

I have anonymous function where I wrapped all javascript code inside (main.js). I pass global variable to one of function inside. But the problem is that variable is created after main.js is loaded. I could use jQuery document ready, but I don't want to wait entire document to be loaded.
main.js
(function(){
function example(){
alert(globalVariable)
}
})();
and phtml file that is loaded after
<script>var globalVariable = 'example'</script>
Is there any way to create custom listener and when this is created example() should be forced? Something like that (just as example to show what I need):
main.js
(function(){
listen(mycustomlistener){
function example(){
alert(globalVariable)
}
}
})();
phtml file
<script>
var globalVariable = 'example'
create listener(mycustomlistener)
</script>
Where is the trigger that you expect from? Is it triggered by you or from an event or from a change?
If it is listener/observer design u are looking for. You could implement your own or use the one available in backbone.wreqr
http://zen-and-art-of-programming.blogspot.in/2013/12/backbonewreqr-jumpstart.html
Also from the above code even though you create a listener your example function wont be called since it is just a functon declaration inside and not the call i.e make it
var eventAggregator = new Backbone.Wreqr.EventAggregator();
//Subscribe for the event!
eventAggregator.on('eventName', function() {
(function example(){
alert(globalVariable)
})(); //observe the call i ve made here which is absent in urs!!!
});
//Raise the event!
eventAggregator.trigger('eventName');
You could also use jquery observer and observable
https://gist.github.com/addyosmani/1321768
This should help you out in what you want.
http://jsbin.com/mugage/1/edit?html,js,output

JavaScript global callback functions are not called?

I'm building a small web app with a few other people. I want to allow the other developers to define a couple of functions that are always called when the document is ready.
Our app inserts the following script into the HTML body of every page:
<script type="text/javascript">
(function(){
window.Utils = {
funcs: {}
};
$(document).ready(function(){
alert('Calling funcs...');
var startFunc = Utils.funcs['start'];
if (startFunc != undefined){
startFunc();
}
var finishFunc = Utils.funcs['finish'];
if (finishFunc != undefined){
finishFunc();
}
});
})();
</script>
Then, in a separate .js file, a developer should be able to do the following:
Utils.funcs['start'] = function(){
alert('Starting...');
};
Utils.funcs['finish'] = function(){
alert('Finishing...');
};
But this doesn't work. The functions are never called?
jsFiddle link: http://jsfiddle.net/XvQtF/
jsFiddle's (very surprising) default is to put your code in a window load handler. (You can see this on the left at the top, the second drop-down box says "onload".) That happens very late in the loading process, long after ready has fired. So the functions aren't added until after you've tried to run them.
If the other developers put their functions in Utils.funcs in script elements after your element defining Utils but without waiting for a load event, it's fine: Updated Fiddle
For what it's worth, though, I would lean toward using a pub/sub solution rather than a single function. If you want to have more than one start function, for instance, your current structure doesn't allow it.
jQuery has Deferred and Promise now, which can be used for this. Here's a simple example of that: Live Copy | Live Source
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<meta charset=utf-8 />
<title>Pub/Sub with Deferred and Promise</title>
</head>
<body>
<script>
(function($) {
// Deferred objects for our app states
var start = new $.Deferred(),
finish = new $.Deferred();
window.Utils = {
start: start.promise(), // Only expose the Promise of each
finish: finish.promise() // " " " " " "
};
$(function() {
alert("Calling funcs...");
// Start the app
start.resolve();
// Finish the app (or whatever)
finish.resolve();
});
})(jQuery);
</script>
<script>
// Module 1
Utils.start.then(function() {
alert("Module 1 Started!");
});
Utils.finish.then(function() {
alert("Module 1 Finished!");
});
</script>
<script>
// Module 2
Utils.start.then(function() {
alert("Module 2 Started!");
});
Utils.finish.then(function() {
alert("Module 2 Finished!");
});
</script>
</body>
</html>
Set up Utils in a separate script to be loaded as the very first one. Also, do this unconditionally (not in any callback etc):
/* load as first script, sets up a global container-object for later use */
var Utils = {
funcs: {}
}
Note that it is ok to define a global variable in the global scope.
/* other script */
(function(){
function myFunc() { /*...*/ };
// now store a reference in Utils
Utils.funcs.start = myFunc;
})();
As mentioned in an other answer: Be aware of the loading and calling order of your various scripts / code:
$(document).ready is essentially the "DOMContentLoaded"-event with most browsers (but earlier versions of IE). "DOMContentLoaded" fires, when all inline-resources originally found in the head-section have been loaded and the DOM-structure of the body is present.
Since this does not include any injected content, it is probably granted, that the event is fired before any modular library (which are loading modules by injecting script tags) is fully loaded and present. (Given that these scripts are loading concurrently with images and other inline-stuff using just a handful of network-slots/sockets provided by the browser, they are probably one of the last things to be ready in your whole loading-process.)
Instead of just using
startFunc() and
finishFunc()
try using this
startFunc.apply(this, null) and
finishFunc.apply(this, null)
this will invoke the functions.
also make sure that
Utils.funcs['start']
Utils.funcs['finish']
is getting initialized before they are called.

Scope issue inside a custom object

I think I am having a scope visibility issue I can't figure out exactly: when I log the variable displayatonce I get back the right result, but as I try to use the buttons I get nothing in return. I have also tried to log this.navbuttons but all I get is an empty set... I really don't get what's wrong with this code.
<!-- html code -->
<div id="nav">
Previous
Next
</div>
/* Js Script with jQuery */
(function() {
var NewsNavigator = {
init: function(config) {
this.navbuttons = config.navbuttons;
this.displayatonce = config.displayatonce;
this.counter = 0;
this.showNews();
this.enableNav();
},
showNews: function() {
console.log(this.displayatonce);
},
enableNav: function() {
console.log(this.navbuttons);
this.navbuttons.on('click', function() {
console.log("clicked");
});
}
};
NewsNavigator.init({
displayatonce: 3,
navbuttons: $('div#nav').find('a')
});
})();
That is happening because as you are using (function())(); which executes the function immediately, maybe it's running the code before the dom is ready
everything is working fine in the below demo
DEMO
Put all your code inside document ready or at least call the initialize method inside doc ready block like
$(function(){
NewsNavigator.init({
displayatonce: 3,
navbuttons: $('div#nav').find('a')
});
});
Read more about Javascript self executing Anonymous function here
Javascript self executing function "is not a function"
or
http://markdalgleish.com/2011/03/self-executing-anonymous-functions/
You're using jQuery too soon, specifically before the DOM is ready to be searched.
Here is fiddle demonstrating this: http://jsfiddle.net/w7KaY/ (JavaScript is placed in <head>, so init() is invoked pretty early) while here (http://jsfiddle.net/w7KaY/1/), the call to init() is encapsulated in an event handler for jQuery's DOM-ready event.
Make sure the html elements are there in the DOM. I don't see any issue with the script other than the fact you have to use the bind method for binding to events.
this.navbuttons.bind('click', function() {
console.log("clicked");
});

Revealing module pattern with jQuery not working

I've been playing around with the revealing module patter. I originally started using the Singleton pattern but from reading around the module pattern seems to be the better option.
So i've tested the following:
var test = (function() {
var init = function () {
alert('hello');
};
return {
init: init
};
})();
and this works fine when calling
<script>test.init();</script>
However, i want to use jQuery so i tried:
var test = (function($) {
var init = function () {
$("#samplediv").html('test');
alert('hello');
};
return {
init: init
};
})(jQuery);
but this doesn't work. It does work when using:
<script>$(function() { test.init(); });</script>
How can i get it to work without the added jQuery when calling it?
Usually, anything that touches the DOM needs to done in the $(document).ready(fn) callback. $(fn) is a shortcut for this.
So the reason it doesn't work is because you are searching for DOM elements that don't exist yet. So you have 2 choices. Either you must use the $() wrapper, or find another way to run your code only after the DOM elements exist. Another way to do this is to move your script tag the bottom of the body tag so that the DOM elements can exist when it's ran.
<body>
<!-- your page elements here -->
<script>test.init();</script>
</body>

Execute local Javascript after remote javascript loads?

I have a page where I am using jquery/ajax to pull down a chunk of HTML/JS from another component and injecting it into the page. That HTML references additional JS files, and I need those referenced JS files to be loaded before I run my javascript.
The HTML/JS that is being injected looks something like this:
<script type="text/javascript" src="http://myserver/js/ABunchOfStuff.js"></script>
<div>
blah blah blah
</div>
<script type="text/javascript">
//"sourceList" is defined in the ABunchOfStuff.js above, but it's not available by the time this executes.
$("input#autocomplete").autocomplete({
source: sourceList,
minLength: 2
});
</script>
Normally I would just hook into a window load event or a $(document).ready() or whatever, but in this case the window and document have already been completely loaded, and now we're adding additional content after the fact.
One possiblity would be to put a recursive setTimeout call in that would keep firing until the referneced javascript was available, but that's pretty ugly.
So is there any clean way to trap the event of a referenced javascript has been loaded and to execute code at that time?
Thanks
You can also use getScript and do your autoComplete in the success callback:
jQuery.getScript( 'http://myserver/js/ABunchOfStuff.js', function(data, textStatus) {
$("input#autocomplete").autocomplete({
source: sourceList,
minLength: 2
});
} );
The big question is, how do you inject this script ?
If you using "standard" script tag insertion, you can go and watch for the onload event (onreadystatechange in IE).
var scr = document.createElement('script');
scr.type = 'text/javascript';
scr.src = 'somewhere/somename.js';
scr.onload = scr.onreadystatechange = function() {
if( /complete|loaded/.test(scr.readyState) ) {
// do something
}
else {
// do something
}
};
What you are doing wrong here is not waiting for the DOM to load.
If you change your .autocomplete to only execute once the DOM is loaded through $(document).ready it will have executed the ABunchOfStuff.js
Like this:
(function($) {
$(document).ready(function() {
$("input#autocomplete").autocomplete({
source: sourceList,
minLength: 2
});
}
}(jQuery));
If you control the http://myserver/js/ABunchOfStuff.js file, then you can call your other JS from it when it first executes. Since it executes when it first loads and when it's available, you have the perfect timing.
If this JS file is used other places too, you could add some generic functionality to it for calling a callback when it executes by adding something like this to it:
try {
if (aBunchOfStuffCallbacks) {
for (var i = 0; i < aBunchOfStuffCallbacks.length; i++) {
aBunchOfStuffCallbacks[i].call(this); // call callback to announce we're loaded
}
} catch(e) {}
And, then in any web page where you want to be called when aBunchOfStuffCallbacks was loaded, you would just do this:
var aBunchOfStuffCallbacks = [];
aBunchOfStuffCallbacks.push(myFunc);
function myFunc() {
// put my code here for when aBunchOfStuffCallbacks is loaded
}
This would allow for multiple callbacks. The simpler version for just one callback looks like this:
try {
if (aBunchOfStuffCallback) {
aBunchOfStuffCallback.call(this); // call callback to announce we're loaded
}
} catch(e) {}
And, it would look like this to set it:
var aBunchOfStuffCallbacks = function () {
// put my code here for when aBunchOfStuffCallbacks is loaded
}

Categories