Nested Objects With YUI and Javascript - javascript

I am working on a Javascript object that contains some YUI objects. The key thing is, my object needs to contain it's own set of YUI tabs so that I can display multiple instances of my object on the same page and have the tabs control their own object instance.
I set it up as follows:
var Scheduler = function(divid,startDate,mode){
this.tabView = null;
...
this.init = function(){
this.tabView.appendTo(this.calendar_cell);
this.tabView.addTab( new YAHOO.widget.Tab({
label: 'Day',
content:'<div id="'+ this.calendar_day_div +'" style="width:100%; height:auto;"></div>'
}));
var tab0 = this.tabView.getTab(0);
tab0.addListener('click', this.showWeek);
}
this.showWeek(){
alert(this);
}
});
Here's the problem. I would expect the alert(this); in this.showWeek to alert the instance of scheduler. Instead, it's giving me the tab li. I tried alerting this.parent and am given 'undefined' as an answer.
How should I set this up to do what I need to do?

The addListenter method takes a scope argument. So you can change your call to the following to solve your problem (since you are using YUI):
tab0.addListener('click', this.showWeek, undefined, this);

When you attach a function to an event of an object (in this case the object held by tab0) then its usually that object that becomes the this context of the function when it executes.
Adjust your code like this:-
var self = this;
this.showWeek(){
alert(self);
}

Related

find class instance by property in javascript

I'd like to retrieve an instance of some js Class with only the value of a parameter
lets say :
function myClass(id)
{
this.id = id
}
myClass.prototype.sayHello = function()
{
alert('hello');
}
myClass.instanceFromID = function()
{
...
}
var instance1 = new myClass(22);
var instance2 = new myClass(33);
var instance3 = new myClass(232);
var instance4 = new myClass(1533);
I would love to be able to access the instance by some method like
myClass.instanceFromID(33).sayHello();
I've been thinking of 2 solutions but they seam overkill :
First idea:
storing all the instances in an array, (global scope or static to the class) and iterating over all of them to find and return the instance, but this implies to keep track, add and remove the instances from the array.
Second idea:
make each instance listen to a custom event triggered from the document and compare the data emitted with inner parameter to check if it is concerned and emit a signal back to the document.
How can I achieve this in a simple way or is there no other way than these 2?
Based on what you've written, having the class itself keep track of instances with an instance variable seems to be the approach you're looking for. Of course, this means that instances will never be garbage collected unless you explicitly release them. But perhaps that isn't an issue for you. Here's how I would tackle this:
function MyClass(id) {
this.id = id;
MyClass.instances[id] = this;
}
MyClass.instances = {};
MyClass.instanceFromId = function(id) {
return MyClass.instances[id];
}

Retrieve existing object into variable?

On my page I initially declare variable var as which creates an object through plugin using createAll... I'm referring to this plugin: http://kolber.github.io/audiojs/docs/
In order for plugin to work this object needs to be created. So after that I load some contact through ajax and plugin needs to be applied to this new content, so again I create this var as to create object, however now there are two similar objects on a page which conflict. I would like to know it there is a way where I can make var as that gets created after ajax call equal to existing object on a page?
I tried looking at what's inside var as by doing alert(as); This returns [Object object]
EDIT
This is what gets printed out with console log (This is original, first object)
Object
duration: 1
element: HTMLAudioElement
loadStartedCalled: false
loadedPercent: 0
mp3: null
playing: false
settings: Object
source: HTMLAudioElement
wrapper: HTMLDivElement
__proto__: Object
This is how objects are created, but I believe you need to know the plugin well to understand this
// Initialize audio js
audiojs.events.ready(function() {
var as = audiojs.createAll({
});
});
I've tested a working solution. Please note, the code is just to show it works - see my explanation below for specifics.
var as;
audiojs.events.ready(function () {
as = audiojs.createAll();
});
$(document).ready(function () {
setTimeout(function () {
var mp3 = "http://s3.amazonaws.com/audiojs/02-juicy-r.mp3"; // audio.js example
// creating new audio element, yours is probably added via ajax
// [0] used to get DOM element instead of jQuery object.
var audio = $('<audio/>', {id: 'test'}).appendTo('body').attr('src', mp3)[0];
var testAS = audiojs.create(audio); // initialise new audio.js player
as.push(testAS); // add "testAS" object to "as" array of objects
console.log(as); // log "as" - now holds the original objects + "testAS"
}, 5000); // timeout used for testing, above code can be in ajax success function instead
});
The mp3 and audio variables are just used as a demonstration as I don't know your ajax function's structure.
Audio.js has a .create() function which takes a single element as it's argument and returns an object. The original as variable is an array containing all the audio objects so you can just push the new object onto the end.
By defining as outside a function you make it global meaning that everything can access it and any new audio.js objects can be appended.

Overriding native methods and objects INSIDE a particular object

I'm trying to override a native method called "localStorage" for functions INSIDE an object.
Here's a gist of what I'm trying to do:
function SomeObject(){
this.localStorage = "aaa"; //block access to localStorage for functions INSIDE this object.
... (some more code here)
_testRun(){
window.testA = localStorage; //chose to store the instance on a window (global-like) object
}
this.testRun = function(){ _testRun(); };
this.testRun2 = function(){ window.testB = localStorage;};v
}
var a = new SomeObject();
a.testRun();
a.testRun2();
(after this, when I look up window.testA and window.testB, they both point to the Native localStorage, not the custom one inside the SomeObject.)
BTW, I don't want to override a native function for the whole document.
(i.e. might use native localStorage OUTSIDE the object)
Any suggestions/solutions on how I can do this? thanks!
Try to add window.localStorage and this.localStorage instead of just localStorage
function SomeObject(){
this.localStorage = "aaa"; //block access to localStorage for functions INSIDE this object.
... (some more code here)
_testRun(){
window.testA = window.localStorage; //chose to store the instance on a window (global-like) object
}
this.testRun = function(){ _testRun(); };
this.testRun2 = function(){ window.testB = this.localStorage;};
}

Can I call a method on other objects created by the same constructor in javascript?

Lets say I have an object constructor that a third-party page developer can insert in their page, called "Widget". It could be something like a tooltip, for example.
var Widget = function(settings, callbacks) {
this.hide = function() {
//some code...
};
this.show = function() {
this.isShowing = true;
//more code...
}
}
When this Widget is shown, I want to hide any other shown Widget. Is there a way the "show" method can call the "hide" method on the other instance(s) of Widget whose "this.isShowing" is true, or on all instances of Widget?
You can, but you need to maintain references to those instances. You could maintain them on a property of the function itself:
var Widget = function(settings, callbacks) {
Widget.instances.push(this);
// More code
};
Widget.instances = [];
And then, just access Widget.instances to get the all the widgets created.
You may want to create some kind of destructor to remove a widget from the list though (myWidget.destroy() or something), because this might generate a memory leak if you instantiate too many of them.

Javascript, passing a variable into a click event?

I really can't figure out how I would do this. It's more of a concept question than a code question so I'll just post an example:
object = $('#div');
function doSomething(object) {
//iterates through a list and creates a UL with items in corresponding to that list.
$(body).append("<li id='clickme'>Hello world</li>");
}
function createModal(object) {
//creates modal dialogue.
doSomething(object);
//more stuff
}
$('#clickme').live("click", function() {
//I need access to object (not the object declared at first,
//the object passed into doSomething) here.
});
Any ideas how I would do such a thing? doSomething would create a set of LIs and have a parameter passed into it. When those LIs the function creates are clicked, they need to interact with the parameter that's passed into doSomething. Is there a way to bind them or something?
Sorry if I didn't make any sense.
You can use jquery data function to associate data to your DOM elements. You then can read those data when handling events.
An alternate way, generally not recommended but useful when you build your html in one big pass and don't have an easy access to the DOM elements, and only have strings (or keys), is to add an attribute and retrieve it later using jquery's attr function. Whenever possible I recommend you to use the data function though.
Store the reference explicitly:
function doSomething(object) {
//iterates through a list and creates a UL with items in corresponding to that list.
$(body).append(
$("<li/>", { id: 'clickme', text: 'Hello world',})
.data('object', object)
);
}
Then the event handler can retrieve the reference:
$('#clickme').live("click", function() {
var object = $(this).data('object');
// ...
});
Also .live() is deprecated:
$('body').on('click', '#clickme', function() {
is the hip new way to bind delegated event handlers.
object = $('#div');
function doSomething(object) {
$(body).append("<li id='clickme'>Hello world</li>");
$('#clickme').click(function(evt) {
// Here you have access to `object`
});
}
function createModal(object) {
//creates modal dialogue.
doSomething(object);
//more stuff
}
This might not be enough. If you are creating multiple links rather than just the single one with id clickme you might have to find a different selector to use when you attach the click-handler. But if you nest the function that way, you have access to the parameter object that was used when the click-handler was created.
Another option would be to declare and attach the handler in a location where the parameter would be in scope, through closures (not tested):
function doSomething(object) {
$(body).append("<li id='clickme'>Hello world</li>").click(function() {
//object is accessible here
});
}

Categories