videojs public method access outside ready function and IE - javascript

I built a player on top of videoJS and I'm having trouble accessing public functions inside videoJS .ready(). The thing is that my code appears to be working everywhere except IE (works in chrome, safari, ff, etc.):
var myPlayer = _V_('myvideojsId');
myPlayer.ready(function() {
var player = this;
player.myPublicFunction = function() {
alert("hey!");
}
});
myPlayer.myPublicFunction();
In IE I get
Object does not support this property or method
on the myPlayer.myPublicFunction() line. Are the other browsers letting me get away with bad code or is this IE's fault?
Any help would be great, thank you!
Chris

Referencing their documentation, it shows exactly what Jonathan has said:
https://github.com/zencoder/video-js/blob/master/docs/api.md#wait-until-the-player-is-ready
He's right about IE by the way. As much as we all love to hate it, it has found real issues for me many times.
Just for quicker reference, here's an alternative to your method to getting this done:
_V_("example_video_1").ready(function(){
var myPlayer = this;
// EXAMPLE: Start playing the video.
myPlayer.play();
});

This is likely a problem with timing:
myPlayer.ready(function() {});
myPlayer.myPublicFunction();
Your first line here hands off a function to myPlayer to call whenever the player is ready. This doesn't happen immediately in most cases, so there is most likely a delay. This means your public function isn't added to the myPlayer object immediately, but rather this task will be accomplished whenever the video player is ready.
All of this means that when JavaScript moves on to the second line, the appropriate response from a browser is that the method doesn't exist - because it doesn't. It won't exist until the video player is ready, which isn't until later.
You could use more of a feature-detection approach, and only call the method if it exists:
if (myPlayer.myPublicFunction) {
myPlayer.myPublicFunction();
}
You could also just add the method before-hand:
myPlayer.myPublicFunction = function () { alert("Foo"); };
myPlayer.ready(callback);
myPlayer.myPublicFunction(); // 'Foo'
In the end, I've found that Internet Explorer is not as forgiving (which is good) as some other browsers. If it's acting up today, it's likely because there's a problem in the code.

Related

IE11 script onload not working (sometimes)

I am currently working on a data-intensive web application that frequently communicates with an external API and retrieves JSONP data when returned. The script depends upon a library called head.js v1.0.3. http://headjs.com/ to accomplish this. However, I noticed that in IE 11 for some reason, the onload event for the script sometimes, but not always, fires before the script has actually loaded into the browser. The behavior is demonstrable whether using head.js or not. Alternatively, I may create a script element with the onload event set to capture the returned data. Sometimes it works, and sometimes not. Even more weird is that once it happens the first time, it seems to keep happening for the duration of the browser session.
Any ideas for a workaround?
Here is some example code:
//somejson.js
/*
window["queryResult"] = {blah:'blah'}
*/
function loadScript() {
head.load("/somejson.js", afterScriptLoad)
}
function afterScriptLoad() {
var result = queryResult
//Throws error because window.queryResult is sometimes undefined
}
After a little bit of research, it seems the only way around this bug is to modify the API so that once the variable holding the JSONP is initialized, the script itself triggers the callback. Unfortunately, this would not work as a solution for others if they do not have access to modify whatever API is in use, but it does solve the problem for me.
//somejson.js
/*
window["queryResult"] = {blah:'blah'}; scriptCallback()
*/
function loadScript(callback) {
var c = new afterScriptLoad(callback)
window["scriptCallback"] = c
head.load("/somejson.js", c)
}
function afterScriptLoad(callback) {
var retrieved = false
return function () {
if (!retrieved) {
retrieved = true
callback(queryResult)
}
}
}
function myCallback(response) {
//do something
}

Callback for a popup window in JavaScript

I hope I did my homework well, searching the Internets for the last couple of hours and trying everything before posting here, but I'm really close to call it impossible, so this is my last resort.
I want a simple thing (but seems like hard in JavaScript):
Click button -> Open Window (using window.open)
Perform an action in the popup window and return the value to parent (opener)
But I want to achieve it in a systematic way, having a callback defined for this popup; something like:
var wnd = window.open(...)
wnd.callback = function(value) {
console.log(value);
};
I've tried defining the callback property in popup window JS code:
var callback = null;
Unfortunately, that does not work, as...
$('#action').click(function() {
console.log(callback);
});
... returns just that "null" I set initially.
I've also tried setting the callback in a parent window after window load (both thru window.onload=... and $(window).ready()), none worked.
I've also tried defining some method in child window source code to register callback internally:
function registerCallback(_callback)
{
callback = _callback; // also window.callback = _callback;
}
But with the same result.
And I don't have any more ideas. Sure, it would be simple setting the value using window.opener, but I'll loose much of a flexibility I need for this child window (actually an asset selector for DAM system).
If you have some ideas, please share them.
Thank you a million!
HTML5's postMessage comes to mind. It's designed to do exactly what you're trying to accomplish: post messages from one window and process it in another.
https://developer.mozilla.org/en/DOM/window.postMessage
The caveat is that it's a relatively new standard, so older browsers may not support this functionality.
http://caniuse.com/#feat=x-doc-messaging
It's pretty simple to use:
To send a message from the source window:
window.postMessage("message", "*");
//'*' is the target origin, and should be specified for security
To listen for messages in a target window:
window.addEventListener
("message", function(e) {
console.log(e.data); //e.data is the string message that was sent.
}, true);
After few more hours of experiments, I think, I've found a viable solution for my problem.
The point is to reference jQuery from parent window and trigger a jQuery event on this window (I'm a Mac user but I suppose, jQuery has events working cross-platform, so IE compatibility is not an issue here).
This is my code for click handler on anchor...
$(this).find('a[x-special="select-asset"]').click(function() {
var evt = jQuery.Event('assetSelect', {
url: 'this is url',
closePopup: true,
});
var _parent = window.opener;
_parent.jQuery(_parent.document).trigger(evt);
});
... and this is the code of event handler:
$(document).bind('assetSelect', function (evt) {
console.log(evt);
});
This solution is fine, if you don't need to distinguish between multiple instances of the asset selection windows (only one window will dispatch "assetSelect" event). I have not found a way to pass a kind of tag parameter to window and then pass it back in event.
Because of this, I've chosen to go along with (at the end, better and visually more pleasant) solution, Fancybox. Unfortunately, there is no way - by default - to distinguish between instances either. Therefore, I've extended Fancybox as I've described in my blog post. I'm not including the full text of blog post here, because is not the topic of this question.
URL of the blog post: http://82517.tumblr.com/post/23798369533/using-fancybox-with-iframe-as-modal-dialog-on-a-web

Can't execute code from a freed script

I have a function that in a different frame that I need to override. In addition, I need to call the original function from within my override. To do so, I'm using the following:
myFrame.SomeFunction = (function () {
var originalSomeFunction = myFrame.SomeFunction;
return function(arg1, arg2, arg3) {
alert('In override!');
originalSomeFunction(arg1, arg2, arg3);
};
})();
When I execute this code, I get "Can't execute code from a freed script".
Thoughts? Is there a better way to do this? Testing in IE 6,7,8 and 9.
You cannot do that in IE, you've discovered. You need to make sure that any objects you pass between frames are native things like strings. Even "Date" instances have caused me problems, though that was on obscure versions of Windows 2000 back in the day.
By "freed script" what IE means is that your the page context where an object was "born" has been overwritten by a new page.
If you're comming here from google and are looking for an easy solution to fix this problem in IE:
In our case the problem occured, because we were working with events inbetween iframes. By doing so it was possible that, upon changing the iframe contents combined with a triggered event it would attempt to call the script on the now changed iframe document. this raised the exception in question.
by adding
$(window).on("unload", function(){
$(target).off(eventname, handler);
});
the problem would cease to be raised. Finally no try/catch because of IE.
I figured out the solution.
Basically, you take all of the code I previously posted, and the execute it from within the context of the target frame using the eval() function. So...
myFrame.eval("SomeFunction = (function () {var originalSomeFunction = SomeFunction; return function (arg1, arg2, arg2) {alert('Inside override!'); originalSomeFunction(arg1, arg2, arg3);};})();");
Because the code is now within the target frame, it doesn't go out of scope, and we don't get the "freed" error anymore.
I know this question is quite old but in case you run into this I'd suggest you use JSON.parse to create an object on the parent frame rather than eval because eval is evil (causes security issues, I think it's disabled by default in some browsers too nowadays)
for example, if you want to call someFunction on frame 1, passing it a JSON object, use something like the below:
var frame = window.frames[1];
frame.someFunction( frame.JSON.parse( '{ "attr": 7 }' ) );

pass an event AND a variable to an anon function in firefox

I come again with my inabilities to comprehend javascript.
I have a draggable library and it has a command that is called like so (the _ag is just namespacing stuff):
_ag.drag(event,targetDiv);
// targetDiv can be a string, btw - converted to an element in the function
so I've got code that looks like so (passing some data with a closure - a new trick to me):
header.onmousedown=function(targetDiv){
return function(){
_ag.drag(event,targetDiv)
}
}(aTargetDiv)
works great! just great! in...IE! SF! Chrome! NOT IN FIREFOX!
No, firefox cannot find the event. Now normally this is easy enough with something like this (formed slightly differently - hope it's still valid):
header.onmousedown=function(event){
alert(event.screenX)
}
However if I decide to pass some parameters in, it blows away event, which I guess is some sort of invisible parameter in FF?
//broken thing 1:
header.onmousedown=function(event){
alert(event.screenX) // somethingToPass in covers event in FF
}(somethingToPassIn)
// broken thing 2:
header.onmousedown=function(event){
alert(event.screenX)
}(event,somethingToPassIn) // event is undefined
SO FIREFOX: How do I send you events? Here's hoping this is a very stupid question, and that hoards of SO folks have the answers! Thanks in advance, I'll be right here banging my head against the wall.
Firefox probably doesn't have support for event, but instead passes it into your function when the event fires. So,
header.onmousedown=function(targetDiv){
return function(e){
e = e || event; //This will give support for global event and passing the event into the function
_ag.drag(e, targetDiv);
}
}(aTargetDiv)
You don't need the closure unless the aTargetDiv variable changes sometime later in the code. Instead, you could do:
header.onmousedown=function(e){
e = e || event;
_ag.drag(e, aTargetDiv);
};

IE8 problem with javascript function that calls itself in setTimeout

i have a locate function defined in javascript
var locID;
function locateMe()
{
if(locID > 0)
{
// i do a jquery post here
}
setTimeout(locateMe, 2000);
}
// my document ready function is here, and inside it, at the end of it
// i do this
locID = 0;
locateMe();
when i test this code in firefox, the locateMe function is called every two seconds and works as expected. when i test the code in IE8 the function is never called (at least it appears to never be called from what i can see using IE's developer tools)
note: there is code defined in a click event handler for the 'zone_row' class that modifies locID. again, in firefox everything works as expected. the strange thing is, in IE when a zone_row is clicked the function WILL be called ONCE. i can see that both on the developer tools and through the result of the action of that jquery post.
i figured there is just some anomly with IE that i am not familiar with yet. what am i doing wrong?
EDIT: changed "locateMe();" to locateMe inside the setTimeout call.
UPDATE: adding more of my code (per request in comments) to show placement (albeit not much more code than my first post).
<script type="text/javascript">
var z_items;
var locID;
function locateMe()
{
if(locID > 0)
{
// my jquery post is here
}
setTimeout(locateMe, 2000);
}
$(document).ready(function()
{
// ... some click events and get requests here ...
locID = 0;
locateMe();
});
</script>
i also tried wrapping the call in a setTimeout (no effect) and changing the DOCTYPE (this actually caused IE to never call the function as opposed to now where it calls it ONCE and never again).
problem solved. i found an answer to another problem i was having from this post:
Prevent browser caching of jQuery AJAX call result
upon adding $.ajaxSetup({ cache: false }); to my document ready function, it solved THIS problem too. it looks like all this time it was a caching issue.
I've found that for IE (even IE9) that if you nest the self-called function in an anonymous function it works. But it does look like Toddeman's problem was related to the ajax part.
So the code would be:
function locateMe()
{
/* ... */
//IE way (still works in Chrome and FF):
setTimeout(function () { locateMe(); }, 2000);
//original: setTimeout(locateMe, 2000);
}
Use
setTimeout( locateMe, 2000 );

Categories

Resources