I used to extract the videoid from the target argument as follows:
function onPlayerReady(event) {
var videoid = event.target.d.d.videoId;
var playerid = event.target.d.d.playerid;
// more stuff
}
Unfortunately, these seems to change rather frequently. I also used
event.target.d.id
before it was changed.
I can't seem to find how to get this information consistently. Also, what is d standing for? Is that a kind of debugging variable not considered for the public to use?
At the moment I seem to find it under
event.target.B.videoData.video_id
EDIT: With the suggested solution I'm not able to address custom properties, though.
When I instantiate the player with
new YT.Player(playerid, {
videoId: videoid,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
},
playerid : playerid
});
I'm giving it some properties that I require, here the playerid property. Since this is not a native property it doesn't appear in getVideoData(). Any idea how to store custom data in the object and address it later on consistently? I could address this property with temporary letter from the minification, though.
You're right that the single letters represent the video objects, but the letters are assigned based on whatever minification may have been run recently on the libraries. There is a method you can execute, however, to get the object into one of your own variables; try this:
var videodata = event.target.getVideoData();
Then, you can get the ID with:
videodata.video_id
When it comes to other attributes that you add in yourself, a lot of it depends on what custom data you're including. If it's only the id of the element pf the created player, you could use event.target.getVideoEmbedCode() to return an iframe element that has as its ID the playerID used to create the object. But other arbitrary data will not be exposed via any direct API method. You could always loop through every object attribute ... for (att in event.target) ... but that would require lots of recursion in case the object you need is several layers deep.
If it were me, I wouldn't store the custom data in the player object; I'd create a wrapper object instead, that's keyed to the video ID, allowing you to add as many object params as you'd like:
var myplayers={};
function onYouTubeIframeAPIReady() {
myplayers["M7lc1UVf-VE"] = {"player":new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
playerVars: {
'html5':'1',
'controls': '0'
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
}),
"playerid":"player",
"otherdata":"whatever"
};
}
function onPlayerReady(event) {
console.log(myplayers[event.target.getVideoData().video_id]);
}
If it helps anyone, this is what I ended up going with:
document.onPlayerReady = function(event) {
for( var item in event.target) {
if(event.target[item].id) {
var iFrameID = event.target[item].id;
...
break;
}
}
}
Related
I have built a custom widget that contains lots of other widgets.
The problem I am getting is the this. reference when a widget inside my custom widget calls a function in my custom widget. For example:
$(function() {
$.widget("custom.my_widget",
{
_create: function() {
this.variable = "HI";
var that=this;
// A Custom widget
this.button = $("<button>", {html:"PRESS"})
.button()
.click(this.do_it) // I know I can do a function(){ that.do_it() }) but that is not the point
.appendTo(this.element);
},
do_it: function() {
// With the setup like this, how do I get the correct this. reference
// As it stands, this = the button object
alert("TEST: "+ this.variable);
}
})
});
The problem is that the this in the do_it function does not point to my_custom widget, instead it points to the button widget.
Above is symbolic, please don't point out a bug as my actual widget is over 3000 lines of code and has many references like this. I need to get the my_widget instance inside functions like this when other widgets call my widget's functions.
I have tried putting in another parameter, but with some callbacks in some third party widgets this is not possible.
There must be an easy way to get the correct base this value for my_widget.
jsFiddle for reference : http://jsfiddle.net/jplevene/6e7m2q6h/3/
You can either use bind(), instead of click(), specifying the "context", or just reference a local variable and call the function (e.g. self below):
$.widget("custom.my_widget",
{
// the constructor
_create: function() {
var self = this;
this.variable = "HI";
// A Custom widget
this.button = $("<button>").button().click(function(){
self.do_it();
});
},
do_it: function(e) {
alert(this.variable);
}
JSFiddle: http://jsfiddle.net/ewpgv3mt/1/
The only way I found to do it is as follows:
$(function() {
$.widget("custom.my_widget",
{
_create: function() {
this.variable = "HI";
// A Custom widget
this.button = $("<button>", {html:"PRESS"})
.button()
.click(this.do_it) // I know I can do a function(){ that.do_it() }) but that is not the point
.data("widget", this) // <---- New line here
.appendTo(this.element);
},
do_it: function() {
// Get the parent widget
var that = $(this).data("widget");
alert("TEST: "+ that.variable);
}
})
});
What I did was pass the "this" value to a data value of the object. There must be a better way than this.
I have tried $(this).closest(".my_widget_class"), but I then need the widget from the object
Perhaps this is the wrong approach to my problem, but that is why I'm here. In the code below is a sample of a JavaScript module pattern with sub-modules. As I build this, I realize that some sub-modules need to "call" each other's methods.
I know that it would be wrong to use the full call admin.subModuleB.publicB_2(); but its the only way since the IIFE functions cannot call "themselves" until instatiated, ex. "module" is not available in the primary namespace, etc...
My thought is that this pattern is incorrect for my situation. The purpose of the module encapsulation is to keep things private unless reveled. So what would be a better pattern?
var module = (function($, window, document, undefined) {
return {
subModuleA : (function() {
var privateA = 100;
return {
// We have access to privateA
publicA_1 : function() {
console.log(privateA);
// How do I use a method from publicB_1
// the only way is:
module.subModuleB.publicB_2();
// but I don't want to use "module"
},
publicA_2 : function() {
console.log(privateA);
}
}
})(),
subModuleB : (function() {
var privateB = 250;
return {
// We have access to privateB
publicB_1 : function() {
console.log(privateB);
},
publicB_2 : function() {
console.log(privateB);
// I have access to publicB_1
this.publicB_1();
}
}
})()
}
})(jQuery, window, document);
What you actually have is an issue with dependencies. Sub module A has a dependency on Sub module B. There are two solutions that come to mind.
Define both modules as their own variables inside the function closure, but return them together in a single object.
What you actually want is instantiable classes where Class A has a dependency on Class B.
Since solution #1 is the closest to your current code, let's explore that first.
Define Both Modules Separately Inside the Closure
var module = (function($, window, document, undefined) {
var SubModuleA = function() {
var privateA = 100;
return {
// We have access to privateA
publicA_1 : function() {
console.log(privateA);
// Refer to SubModuleB via the private reference inside your "namespace"
SubModuleB.publicB_2();
// but I don't want to use "module"
},
publicA_2 : function() {
console.log(privateA);
}
};
}();
var SubModuleB = function() {
var privateB = 250;
return {
// We have access to privateB
publicB_1 : function() {
console.log(privateB);
},
publicB_2 : function() {
console.log(privateB);
// I have access to publicB_1
this.publicB_1();
}
};
}();
// Return your module with two sub modules
return {
subModuleA : SubModuleA,
subModuleB : SubModuleB
};
})(jQuery, window, document);
This allows you to refer to your two sub modules using local variables to your module's closure (SubModuleA and SubModuleB). The global context can still refer to them as module.subModuleA and module.subModuleB.
If Sub Module A uses Sub Module B, it begs the question of whether or not Sub Module B needs to be revealed to the global context at all.
To be honest, this is breaking encapsulation because not all the functionality of Sub Module A exists in Sub Module A. In fact, Sub Module A cannot function correctly without Sub Module B.
Given your particular case, the Module Pattern seems to be an Anti Pattern, that is, you are using the wrong tool for the job. In reality, you have two classifications of objects that are interdependent. I would argue that you need "classes" (JavaScript Constructor functions) and traditional OOP practices.
Use JavaScript Constructor Functions ("classes")
First, let's refactor your "module" into two classes:
var module = (function($, window, document, undefined) {
function ClassA(objectB) {
var privateA = 100;
this.publicA_1 = function() {
console.log(privateA);
objectB.publicB_2();
};
this.publicA_2 = function() {
console.log(privateA);
};
}
function ClassB() {
var privateB = 250;
this.publicB_1 = function() {
console.log(privateB);
};
this.publicB_2 = function() {
console.log(privateB);
this.publicB_1();
};
}
// Return your module with two "classes"
return {
ClassA: ClassA,
ClassB: ClassB
};
})(jQuery, window, document);
Now in order to use these classes, you need some code to generate the objects from the constructor functions:
var objectA = new module.ClassA(new module.ClassB());
objectA.publicA_1();
objectA.publicA_2();
This maximizes code reuse, and because you are passing an instance of module.ClassB into the constructor of module.ClassA, you are decoupling those classes from one another. If you don't want outside code to be managing dependencies, you can always tweak ClassA thusly:
function ClassA() {
var privateA = 100,
objectB = new ClassB();
this.publicA_1 = function() {
console.log(privateA);
objectB.publicB_2();
};
this.publicA_2 = function() {
console.log(privateA);
};
}
Now you can refer to module.ClassB using the name within the function closure: ClassB. The advantage here is that outside code does not have to give module.ClassA all of its dependencies, but the disadvantage is that you still have ClassA and ClassB coupled to one another.
Again, this begs the question of whether or not the global context needs ClassB revealed to it.
the following code will often run out of stack space because the type Entity has a property named EntityAspect, which has a property named Entity of type Entity which points to the owning Entity. This recursive definition causes several tools to fail or run incredibly slow, but most notably, knockout. Can anything be done to address this?
var custType = _this.metadataStore.getEntityType("Customer");
var cust1 = custType.createEntity();
var js = ko.toJS(cust1);
I haven't actually tried this yet but I think you can do this
var js = ko.mapping.toJS(cust1, {
ignore: ['entityAspect']
});
I found I needed to ignore both entityAspect and entityType (snippet from custom datasource kendo datasource):
this.entityManager.executeQuery(query)
.then(function (xhr) {
if (self.autoMapToJS) { // Breeze entities contain recursive properties (ugh!) - eliminate those
payload.data = ko.mapping.toJS(xhr.results, {
ignore: ['entityAspect', 'entityType']
});
} else {
payload.data = xhr.results;
}
if (self.inlineCount) {
payload.total = xhr.inlineCount;
}
options.success(payload); // notify the DataSource that the operation is complete
})
.fail(function (rejected) {
payload.error = rejected;
})
.done(); // terminate chain of promises
}
In particular, trying to use with grids (wijmo & kendo), I was forced to map breeze data or enjoy stackoverflows as those controls would iterate through the properties.
I'm trying to write a custom widget in JQuery UI (v 1.9 m8): http://pastebin.com/zua4HgjR
From my site I call it like this: var D = new $.ui.mail({}); Basically it works.
Is there a better method to call doSend on button click?
The question is how to access object instance from function handler?
"this" returns entire html window.
Tried with $.proxy doesn't work: click: $.proxy(this.doSend, this);
Thanks in advice!
Unfortunately if you setup the buttons by using the options member you'll have no reference to the element that you need in order to call doSend. One workaround I was able to come up with is to assign the handler in the _create method where you have the appropriate reference.
_create: function() {
this.options.buttons = [
{
text: 'Send',
click: function(self) {
return function() {
$(self.element).mail('doSend');
};
}(this)
},
{
text: 'Cancel',
click: function() { $(this).remove() }
}
];
this._super(arguments);
}
Live Example - http://jsfiddle.net/hhscm/2/
Spending this weekend finally I finished my plugin: http://agrimarket-blacksea.com/jsc/jquery-mail.js
I decided to call "class function" in classical way: $(this).mail('doSend'), until I'll find something better.
Thanks!
New to zepto (and honestly, far from a jQuery-whiz),
I want to add a custom function.
This is my attempts so far:
//define..
$.fn.doSearch = function() {
alert(this.parentNode.html());
//now xhr..
}
//assign..
$('#resetBtn').click( function (e) {$(this).doSearch()});
and
//define
<script type="text/ja..
function doSearch(obj) {
alert('Ugly way but here I am');
}
//assign..
$('#resetBtn').click( function (e) {window.doSearch()});
And neither works.. I'd rather go the first route, aware that .fn isn't listed in the zepto-docs.
regards,
//t
ok, now I have
//define
var myFunc = {
doSearch: function(obj) {
//just check obj is ok.
alert($(obj.parentNode).html());
}
}
//correct way to extend zepto?
$.extend($,myFunc);
//assign...
$('#searchBtn').click( function (e) {$(this).doSearch(this)});
is this the way to go?
As mentioned in the documents,
(function($){
$.extend($.fn, {
foo: function(){
// `this` refers to the current Zepto collection.
// When possible, return the Zepto collection to allow chaining.
return this.html('bar')
}
})
})(Zepto)