Appcelerator - Javascript - losing the reference - javascript

I have the following code on my app to add widgets:
while(i < rc_length) {
console.log(i);
mooncards[i] = Alloy.createWidget("moonCards");
mooncards[i].on('close',function(){
$.dashboard_scroll.remove(mooncards[i].getView());
});
$.dashboard_scroll.add(mooncards[i].getView());
i++;
}
So I can add mooncards on my scrollview and add a function to be triggered inside the widget to remove itself.
That was the idea, but unfortunately the only widget removed is the last one. Clearly the reference remove(mooncards[i]) is lost while adding new widgets.
I'm still learning about Javascript, so I don't what I'm doing wrong here.
How can I add a lot of widgets and remove each one specifically, without losing the reference?
Please, let me know If I need to be more clear.

You have a classic javascript binding issue.
I would try changing:
$.dashboard_scroll.remove(mooncards[i].getView());
to
$.dashboard_scroll.remove(this.getView());

You can use bind:
mooncards[i].on('close',function(){
$.dashboard_scroll.remove(this.getView());
}.bind(mooncards[i]));
bind will replace this in your function with the first parameter that you give to it. Consider this example:
x = function() { console.log(this); }
// outputs the window context if running in browser
// because the value of 'this' is the context where
// where the function was executed
x();
// outputs a String object, 'hello' because the value of
// this has now been bound to the string 'hello'
x.bind('hello')();
If your users are in IE8 and below, you will need to use the polyfill provided in the link above.

Related

Using "this" as an argument

I have an onclick function to navigate from one "page" to another (it's not actually navigating, just imitates it):
$('.button').on('click', function(){
$('.home').css('display','none');
var newPage = $('.'+this.id);
goTo(newPage);
});
goTo simplified for reference:
function goTo(page){
$(page).css('display', 'block');
}
This works perfectly fine. All of the navigation buttons have the class of button, and also an ID that matches the class name of the different "pages". Click #page1, display .page1, etc.
My problem is now I'm having to rewrite my code to do the same thing for other elements - trying to rewrite this with arguments doesn't work for this in particular.
Here's what I'm trying:
function goToPage(link, destination){
link.click(function(){
$('.home').css('display','none');
goTo(destination);
}
}
and calling it as:
goToPage($('#page1'), $('.page1'));
works fine, however:
goToPage($('.button'), $('.'+this.id));
doesn't.
I suppose I'm misunderstanding how "this" is working in this context. I thought it would only determine what "this" is when the argument is called.
So my question is: can "this" be used as an argument in this way, am I slightly off with the logic or am I a complete idiot?
Fiddle: https://jsfiddle.net/hek0ptca/13/
To explicitly answer your question, no, this cannot be used as an argument in this case because it points to nothing.
goToPage($('.button'), $('.'+this.id));
In this context, this points to "undefined". Try running console.log(this.id);at the same scope of the code mentioned above and check your browser's console. It returns "undefined".
A good way to think about this is that you need something for it to reference. Scope matters. If there is nothing for this to reference, you will always get "undefined" as a value. Typically this is used inside a function where an object has already been referenced, for example, inside your event handler:
$('.button').click(function(){
$('#home').css('display', 'none');
goTo($('.'+this.id));
});
This will work in this case because this will refer back to the object that is being operated on, the .button class.

jQuery Plugins: Unexpected behavior - context of "this" is probably lost

I've written a really basic jQuery plugin that should log the value of a button clicked.
While it basically works, it unfortunately logs the same value for each button on the page. So if there are three buttons on the page, the value of the button clicked is logged three times.
The plugin code looks like this:
(function($) {
$.fn.content = function() {
return this.each(function() {
$('button').click(function() {
console.log($(this).html());
});
});
};
}(jQuery));
$('button').content();
Fiddle
Although I am quite puzzled right now, I am pretty sure that it has something to do with the context of this inside the each loop, but I can't really figure it out.
There are several issues going on here. The this inside of the fn.content function is actually the composed jQuery object. That object was $('button') so it will contain how ever many buttons there are in the DOM at that moment.
Then you iterate that set, and for each item in that set, you attach a click handler again to the $('button') group explicitly. Unfortunately this means that you have assigned a click event handler to that group n times where n is how many buttons there were. 3 buttons, 3 events; 6 buttons, 6 events.
In order to not do that, simply assign the click handler to the original jQuery object.
(function($) {
$.fn.content = function() {
return this.click(function() {
console.log($(this).html());
});
});
}(jQuery));
Keep in mind that click will internally call .each, and that this in our example is $('button') already.
For more information on creating jQuery plugins, please see my post on the utility of jQuery.fn
I'm not sure which scope you actually need access to, but scope of this is different for each function, including anonymous functions that you created. To access this of an outer scope, try something like the following:
function foo() {
this.someVal = 1;
var that = this;
function bar() {
console.log(that.someVal); // you have access to foo's this
}
}

Javascript creating references to native functions

I have written this code (this is a snippet) that doesn't seem to be working. I have isolated it to here.
grab = window.document.getElementById;
grab("blueBox") // i.e. grab("blueBox").onclick [...]
Is it possible to create references to native function in javascript. I am doing something with the grabbed element, I just left it out for example. The grab function doesn't seem to work.
I am using FireFox's most recent version
The way you're doing it will mess up the assignment of the this value for the function.
grab = window.document.getElementById;
grab("blueBox") // i.e. grab("blueBox").onclick [...]
here this will be the global object. Try:
grab.apply(window.document, ["blueBox"])
or in newer browsers:
grab = window.document.getElementById.bind(window.document);
to get directly define what this will be.
The first step here is always the JavaScript console. Firebug is your friend. Tell us the error message if it doesn't mean anything to you.
In the mean time, here is a workaround:
var grab = function(id) { return window.document.getElementById(id); }
function grab(id) {
return window.document.getElementById(id);
}
grab("blueBox");
The reason is because the function getElementById is not being called as a method of document, so its this keyword doesn't reference the right object. Using call as suggested in other answers shows that when this references the document, getElementById works.

dynamically making onClick event?

I realise a similar issue has been asked here Javascript - Dynamically assign onclick event in the loop but I think I was a bit confused and couldn't add a comment.
I'm making a series of divs dynamically, in an array "newdiv".
I want to create an onClick function which will expand the offsetHeight to the scrollHeight.
I'm trying to do this in my for loop as such:
newdiv[i].onclick = function() {expandThis(message_id) };
Where
message_id = message_array[i][0];
(the id column in the array, at message 'i')
The problem is familiar - all the made onClicks refer to the last message_id.
Is there an easy way to make the onClick for newdiv[i] refer to message_array[i][0]?
You could use an anonymous function to create a closure to contain the value to be referred to.
function(message_id) {
newdiv[i].onclick = function() {expandThis(message_id) };
}(message_array[i][0]);
JavaScript is a functional programming language without a let statement. So you have to write the equivalent closure, as ugly as it looks.
You need to break the closure with message_id:
newdiv[i].onclick = (function(id) {
return function() {expandThis(id) };
}(message_id));
There are a million questions like this one, e.g. Do while javascript Problem.
you could create the javascript code dynamically and store in in a var and then use the evalute() function and assign the result to your onclick callback.

mootools "this" in each?

Probably misunderstanding something simple, but i can't seem to get this to work.
I want to: go trough each img element in "wrapper", and strip all html from the title attribute (with stripTags() from mootools more). I get the error:
"this.get is not a function"
here is the code:
$('wrapper').getElements('img').each(function() {
var oldAlt = this.get('title').stripTags();
this.setProperty('alt', oldAlt);
});
Thanks in advance
$('wrapper').getElements('img').each(function(el) {
var oldAlt = el.get('title').stripTags();
el.setProperty('alt', oldAlt);
});
this does not refer to the looping element -- the first argument to the .each callback function is element passed, the second is index (opposite to jquery where index is first).
The other option is to bind the this variable
$('wrapper').getElements('img').each(function() {
var oldAlt = this.get('title').stripTags();
this.setProperty('alt', oldAlt);
}).bind(this);
The extra .bind(this) basically means, in the scope inside the each function, the variable this is bound to whatever value is refers to outside. (like passing the variable into the scope). If you have need to access the normal this pointer as well, as the outside reference, you should go with an option such as #Chetan's answer

Categories