How can I use the YouTube API inside an AMD module? - javascript

The YouTube API expects certain functions to be attached to the window object. Which seems simple enough:
requirejs(function() {
console.log('i am being loaded')
window.onYouTubeIframeAPIReady = function() {
console.log('ready')
}
});
In this case, 'i am being loaded' is logged, but 'ready' is never shown.
I can see the correct function appears on window.onYouTubeIframeAPIReady from the browser console.
However a script tag works:
<script>
window.onYouTubeIframeAPIReady = function() {
console.log('ready from script tag')
}
</script>
Logs correctly.
What am I doing wrong? How can I use the YouTube API inside an AMD module?

Related

Loading Maps API with the jsapi loader is deprecated

Recently I see this message in the console logs:
Loading Maps API with the jsapi loader is deprecated.
This is the code which causes it:
connected: function() {
...
},
initComponent: function() {
var me = this;
google.load('maps', '3', {
other_params: 'key=YOUR_API_KEY',
callback : me.connected
});
...
}
Loading it statically this is not really an option for me, because callback=connected will call back to window.connected() instead of me.connected():
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=connected"></script>
What is the alternative to google.load(), while calling back into the local scope? The documentation at Loading the Maps JavaScript API only offers static loading.
When adding this function in the global scope:
window.connected = function() {
console.log("Maps API connected");
};
It shows that it is connected, long before the application even launched:
Maps API connected
Util.js:747 [V] the Application was launched.
So this probably is a non-issue. All I have to do is to call it afterender:
listeners: {
afterrender: function() {
appdata.items.panel.Maps.connected();
}
},

Google login for server-side apps

I'm following the Google guide for signing in with Google and sending the access code to a server:
Guide here: https://developers.google.com/identity/sign-in/web/server-side-flow#step_6_send_the_authorization_code_to_the_server
I have two really simple questions:
How does the closure in the jQuery click event know about auth2? If you run this code in Chrome, you'll get an error saying auth2 is undefined. How would I go about fixing that error?
Run from onload:
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({...});
});
}
jQuery click handler
(function($) {
$('#signinButton').click(function() {
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(signInCallback);
});
})(jQuery);
How is signInCallback passed information? Is this part of the callback process?
The code:
function signInCallback(authResult) {
if(authResult['code']) {
$.ajax({...});
} else { ... }
}
Loading the client api at the top of the HTML file:
<script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
and then initializing:
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({...});
});
}
also in the header will do the trick. The guide says this, but neglects to state that it won't really work otherwise.

Native JavaScript document.ready - How to use bindReady()

I am looking for a native JavaScript solution to jQuery's document.ready(). Looking at this thread, CMS suggested to just use the code that jQuery used to implement their document.ready(). I am looking at bindReady() but am unsure how I would incorporate that into my code. I currently have something such as:
$(document).ready( function() {
console.log('foo');
});
Basically when you need to do is replace the lines that have
jQuery.ready();
with the name of the function you want to call. If you want something that works like jQuery's ready registering method, build a function that makes a queue. Loop through the queue when the "ready" is triggered.
You asked for more info so here is a quick and dirty example not using a timeout. This is NOT production ready, just a basic POC.
(function () {
var ready = {
_readyQueue: [],
_hasRun: false,
_docReadyCalled : function() {
this._hasRun = true;
this._execute();
},
_execute: function () {
var func;
while (this._readyQueue.length) {
func = this._readyQueue.shift();
func();
}
},
register: function (func) {
this._readyQueue.push(func);
if (this._hasRun) {
this._execute();
}
}
}
window.docReady = ready.register.bind(ready); //use what ever global namespace you want here
function bindReady() {
/* This would be that jQuery code, I am just use window load here so not so much code */
//Not all browser support this, quick and dirty for example
window.addEventListener('load', ready._docReadyCalled.bind(ready), false);
}
bindReady();
})();
/* waiting for DOM to be ready */
docReady(function () { console.log("here"); });
docReady(function () { console.log("there"); });
/* Showing what happens when you call docReady after it is ready */
docReady(function () { console.log("registering ready again"); docReady(function () { console.log("I am here!"); }); });
Your best bet is to probably avoid using DOM events entirely. It gets really complicated when you want to load as early as possible but want to be certain it isn't too early. This is an easy and 100% reliable technique to execute code as soon as the DOM has completed loading:
<html>
<head>
<!-- head content, blah, blah, blah -->
<script>
var ready = function() {
// Put everything in this function that you want to run when the page loads
nowTheDomIsLoaded();
console.log('foo');
};
</script>
</head>
<body>
<!-- page content, blah, blah, blah -->
<script>ready();</script>
</body>
</html>
Basically you put everything you want run in a function (e.g. ready()) and the very last thing you do before the closing </body> tag is you execute that function. Because everything in the <body> has been parsed you know the DOM is loaded, and this doesn't take any special library.

Javascript / Jquery functions

Not sure if I am being totally wrong here but I want to do something like this:
Have an external js page (on an external server)
Include the page - OK that is easy etc...
Have a Jquery function on the external page - well actually many functions
Call those functions directly onto the page.
All a bit like this:
External js page:
$(document).ready(function() {
function testit() {
$('#test').load('page.php');
}
function testit_1() {
$('#test_1').load('page_1.php');
}
function testit_1() {
$('#test_2').load('page_2.php');
}
});
Then on the actual page just call:
<script type="script/javascript">
testit();
</script>
<div id="test"></div>
Am I wrong or should that not work?
You dont need to define the functions within the ready function, but you have to call it within the ready function.
$(document).ready(function() {
testit();
});
function testit() {
$('#test').load('page.php');
}
function testit_1() {
$('#test_1').load('page_1.php');
}
function testit_2() {
$('#test_2').load('page_2.php');
}
Otherwise testit() will be called before the document is loaded. And at that moment the function doesn't even exist yet in your example.
Your functions are local to the scope of the anonymous function passed as the argument to $(document).ready(). Here's a simple example showing the behaviour you're seeing:
(function() {
function foo() {
alert("It shouldn't alert this...");
}
})();
foo();
To fix it, simply move your function declarations outside of the ready function:
function testit() {
$('#test').load('page.php');
}
function testit_1() {
$('#test_1').load('page_1.php');
}
function testit_2() {
$('#test_2').load('page_2.php');
}
And use the ready function (shorthand $(function() { ... })) in your main js file:
$(function() {
testit_1();
});
I'm not sure if I'm understanding you wrongly, but will you load an external page of an external server? This is not possible on normal browser security settings. You cannot perform a succesful XMLHttpRequest for a document that resides on a different server. Nearly all browsers will block this and leave you with nothing. You would have to write a server-side proxy that fetches the document and serves it back to the client.
That should work fine. Just be sure to include the external JS file in your page and execute testit() inside another $.ready() call:
<script type="script/javascript" src="http://someurl.com/external.js"></script>
<script type="script/javascript">
$.ready( function() {
testit();
} );
</script>
<div id="test"></div>
The location of a JS file is irrelevant. Once it is loaded into your page, it is executed in the context of that page.

how to invoke a dynamically loaded javascript function

I was implementing a on-demand script controller based on jquery's getscript, it looks like this:
function controller = function(){
var script = function(){
var scripts = {};
return {
load: function(jsurl){
$.getScript(jsurl, null);
},
run: function(js){
window[js].apply(this,null);
}
}
};
return {
script: script()
};
}
var ctlr = controller();
then here is a remote script with a function to be loaded - remote.js
function remotefunc(){
alert( 'remotefunc invoked' );
}
and here is how the whole thing supposed to work, in the main script:
ctlr.script.load( 'remote.js' ); // remote script successfully loaded
ctlr.script.run( 'remotefunc' ); // got an error, window['remotefunc'] undefined
but as you can see, 'remotefunc' is defined in the global 'window' scope, so the window object is supposed to be able to 'see' it.
I thought the problem was probably the closure stuff in the 'controller' definition, so I did a direct $.getScirpt without using the 'controller':
$.getScript( 'http://path/to/remote.js', function(){
window['remotefunc'].apply( this, null ); // this worked
} );
strange. So it is about the 'controller' implementation(I kind need it)! Anybody can help me out with this? How to fix the 'controller' implementation so the
window[js].apply(this,null);
can actually work?
Thanx.
The reason it's telling you window['remotefunc'] is undefined is because you are not giving it time to actually download and execute the remote script before attempting to call a function defined in it.
The remote script is loaded asynchronously, which means the script execution isn't paused while waiting for a response.
You will need to either re-implement the getScript method to be synchronous or somehow work your class around the fact that the function will not be available in any determinate amount of time.
EDIT: Just found another possible solution, try calling this before your request
$.ajaxSetup({async: false});
This will make the getScript method synchronous
When using something like getSript, it's important to remember that it is fetching asynchronously. Meaning, the browser fires off the request and while that's happening, code after that line executes without pause.
jQuery provides a callback function parameter to get script that allows you to do something after the asynchronous fetch is finished.
Try this:
var script = function(){
var scripts = {};
return {
load: function(jsurl, callback){
$.getScript(jsurl, callback);
},
run: function(js){
window[js].apply(this,null);
}
}
};
Then, when using it:
ctlr.load( 'remote.js', function(){
// remote script successfully loaded
ctlr.run( 'remotefunc' );
});
Could this be a timing issue?
In your working example you call the function in a callback which jQuery will not invoke until the script is loaded. In your non-working example, you call the function immediately after getScript which is asynchronously loading the script.

Categories