Reputation: 97
I have a tableView that is populated from a remote source. I add several buttons on each row dynamically, buttons and content of each row are in a for loop. I have an alert dialog box listener within the button listener. Once this appears if confirm (YES) is selected I want to be able to change the button title.
I receive the following error:
Uncaught TypeError: Cannot set property 'title' of undefined.
This is the source of the error:
btn[i].title = "Finish"
Sorry I don't have access to the code at the moment and haven't gave much to work with but any help/ideas would be greatly appreciated...
EDIT:
Dummy code:
var btn = new Array();
btn[i] = Ti.UI.createButton({
backgroundImage: '/images/button.png',
title:'Start',
top: 0,
left: 0,
height: '20%',
width: '20%'
});
btn[i].addEventListener('click', function(e){
var alert = Titanium.UI.createAlertDialog({
title : 'Dialog',
message : 'Change Title',
buttonNames : ['Yes', 'No']
});
alert.addEventListener('click', function(e) {
if(e.index == 0) {
btn[i].title = "Finish";
}
});
alert.show();
});
tableViewRow.add(btn[i]);
Upvotes: 1
Views: 121
Reputation: 28850
Somewhere you have a for
loop like this:
for( i = 0; i < btn.length; i++ ) {
// do stuff with btn[i]
}
Change it to:
for( i = 0; i < btn.length; i++ ) {
addButton( btn[i] );
}
function addButton( button ) {
// do stuff with button
}
The body of the addButton()
function will be all of the code that was in your for
loop with one difference: everywhere you have btn[i]
change it to button
.
By moving this code into a function, you create a "closure" which preserves the value of the button
variable as long as needed, unlike the original code where btn[i]
becomes invalid after the loop finishes running.
Remember that event listeners are called long after the original code that sets them up finishes. If you use a loop index in the event listener, that index value is not the one you expect. The closure fixes this in a very clean and simple way.
You mentioned in a comment that you need the loop index as well. In that case you could do this:
for( i = 0; i < btn.length; i++ ) {
addButton( i );
}
function addButton( i ) {
// do stuff with btn[i]
}
In fact, now you don't have to change any of the code in the loop body/function body. You can still use btn[i]
as before.
Or, you can do it this way:
for( i = 0; i < btn.length; i++ ) {
addButton( button, i );
}
function addButton( button, i ) {
// do stuff with button (instead of btn[i]) and i where needed
}
Now you can replace all the btn[i]
references inside the addButton()
function with button
as in the first example, and you still have i
available when you need it.
Upvotes: 1
Reputation: 19294
you are creating a closure on i within a for loop. When the loop exit, all created functions will have a closure on the very same var i, which value will be "length" for all functions, hence the undefined.
Upvotes: 0