I am creating some views in a loop iterating over list of objects. Now I want to register event with each view, which does something on the current object of the list.
for (var vs = 1; vs < 4; vs++) {
iMovie = moviesList[vs];
if (!iMovie) {
break;
}
var loopView = Ti.UI.createView({
....
});
loopView.addEventListener("click", function(e) {
var mv = iMovie;
Ti.API.info("Movie: " + mv);
if (mv) {
// do something
}
});
}
This code is not working, the log which is printed is : Movie: undefined.
So my question is how I can use the loop variable in the event listener?
Try the following code
var loopView - [];
var iMovie;
for (var vs = 1; vs < 4; vs++) {
iMovie = moviesList[vs];
if (!iMovie) {
break;
}
loopView[vs] = Ti.UI.createView({
_iMovie : iMovie
});
loopView[vs].addEventListener("click", function(e) {
var mv = e.source._iMovie;
Ti.API.info("Movie: " + mv);
if (mv) {
// do something
}
});
}
Well, first I'll start that what you are doing in the code above could potentially cause a memory leak since you are holding a reference to the iMovie variable.
what you should try doing is:
var mv = e.source;
this will return the source object that fired the click event.
Related
I have a slideshow on my website with left and right buttons.
Like this (http://i.prntscr.com/863ad10cfd4e4f1ea9b90721cc6582e8.png).
I am using angular to change the image on left and right.
As you can see in the function I increase the value
/*SlideShow Pictures*/
$scope.picture_1 = "./images/photos/watch.jpg";
$scope.picture_2 = "./images/photos/watch.jpg";
$scope.picture_3 = "./images/photos/watch.jpg";
$scope.picture_4 = "./images/photos/watch.jpg";
$scope.picture = $scope.picture_1;
$scope.picture_value = 1;
$scope.image_change_right = function () {
if ($scope.picture_value < 4)
{
$scope.picture_value = $scope.picture_value + 1;
$scope.picture = ('$scope.picture_' + $scope.picture_value);
console.log($scope.picture_value);
}
else{
$scope.picture_value = 1;
$scope.picture = ('$scope.picture_' + $scope.picture_value);
console.log($scope.picture_value);
}
}
Above is the function called for button right press.
The function increases the variable by 1 and adds it to the string to call the new variable. In the console log it looks great! However I think it is only showing as a string --- it is not actually setting the value of scope.picture to the variable.
How can I set this to not be a string but as a valid variable?
Thanks everyone!
A better way would be like this:
The Controller:
// The array of picture links.
$scope.pictures = [
"./images/photos/watch.jpg",
"./images/photos/watch.jpg",
"./images/photos/watch.jpg",
"./images/photos/watch.jpg"
];
$scope.current = 0; // Initialize the current pictures place in the array.
$scope.picture = $scope.pictures[$scope.current]; // Set the current picture.
// The direction is either 1 or -1;
$scope.changePicture = function (direction) {
$scope.current += direction; // add or remove one depending on direction.
$scope.current %= $scope.pictures.length; // Normalize the number based on the length of the pictures array.
console.log($scope.picture);
}
The Html:
<img src="{{picture}}">
<button ng-click="changePicture(1)">Next</button>
<button ng-click="changePicture(-1)">Previous</button>
Why don't you use an array with image links like this?
/*SlideShow Pictures*/
$scope.pictures = ["./images/photos/watch.jpg", "./images/photos/watch.jpg", "./images/photos/watch.jpg", "./images/photos/watch.jpg"];
$scope.picture = $scope.pictures[0];
$scope.picture_value = 0;
$scope.image_change_right = function () {
if ($scope.picture_value < 4)
{
$scope.picture_value = $scope.picture_value + 1;
$scope.picture = $scope.pictures[$scope.picture_value];
console.log($scope.picture_value);
}
else{
$scope.picture_value = 0;
$scope.picture = $scope.pictures[$scope.picture_value];
console.log($scope.picture_value);
}
}
Alright, so, hopefully this is a simple enough question. I'm sure that it has to be something simple and stupid that I am not doing right. I'm building an app to program my exercise routine into so I can keep track of it every week (and to learn app development using Cordova). Within the code, each time I come back to the exersetup screen I want to read the saved exercise file, parse it back to an array of objects, convert those objects back into exercise objects, then display them on the screen. I have a loop that is supposed to check each element of the array to process the information, then display, then repeat until it has done this for each element in the array. It works perfectly fine for the first item, then stops. If I manually run the loop multiple times, it functions perfectly. Not listed is the code for the function addRow(), which simply adds a row of formatted dropdown selectors for input, then increments rowNum to keep track of which row it is operating on. Any help you guys can offer is appreciated. If I need to submit more information I would be happy to do so. Here's the loop in question:
EDIT: Fixed some things to the suggestions in the comments below. Code still functions the same. Works perfectly fine on first run through loop, then stops. If I continue to run the loop manually (declaring it over and over again in console) it works fine, but it will not, for some reason, run the "for" loop. I've also included the rest of the function that the for loop is nested in, in case that helps.
function readRout()
{
console.log("Reading routine...");
document.addEventListener('deviceready', getFile, false);
function getFile()
{
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function(dir)
{
console.log("got main dir",dir);
dir.getFile("exerciseroutine.txt", {create:true}, function(file)
{
console.log("got the file", file);
exerLog = file;
console.log(exerLog);
});
});
document.addEventListener('deviceready', logOut, false);
}
function logOut()
{
setTimeout(readLog, 50);
}
function readLog()
{
exerLog.file(function(file)
{
var reader = new FileReader();
reader.onloadend = function(e)
{
console.log(this.result);
exerRoutine = JSON.parse(this.result);
//console.log(exerRoutine);
//console.log(exerRoutine[0]);
var looper = exerRoutine.length + 1;
for (var i=0; i<looper; i++)
{
console.log("Loop count is: " + i);
console.log(looper);
exerRoutine[i] = new exercise(exerRoutine[i].type, exerRoutine[i].name, exerRoutine[i].sets, exerRoutine[i].reps, exerRoutine[i].pace);
console.log(exerRoutine[i]);
console.log(exerRoutine[i].description());
console.log(exerRoutine[i].type);
console.log(exerRoutine[i].name);
console.log(exerRoutine[i].sets);
console.log(exerRoutine[i].reps);
console.log(exerRoutine[i].pace);
addRow();
setTimeout(fillExer, 50);
console.log(exerRoutine);
}
console.log(looper);
};
reader.readAsText(file);
}, fail);
}
function fillExer()
{
var typeRow = "typeSel" + rowNum;
console.log(typeRow);
console.log(document.getElementById(typeRow));
var nameRow = "nameSel" + rowNum;
var setsRow = "setsSel" + rowNum;
var repsRow = "repsSel" + rowNum;
var paceRow = "paceSel" + rowNum;
fillType(typeRow);
setTimeout(fillName, 10, nameRow);
fillSets(setsRow);
fillReps(repsRow);
fillPace(paceRow);
}
function fillType(typek)
{
for (var k=0; k<document.getElementById(typek).options.length; k++)
{
//console.log(document.getElementById(typek).options.length);
console.log(exerRoutine[rowNum-1].type);
if(document.getElementById(typek).options[k].value == exerRoutine[rowNum-1].type)
{
document.getElementById(typek).selectedIndex = k;
//console.log(document.getElementById(typei).selectedIndex);
var quer = "#" + typek;
//console.log(query);
var typeInput = document.querySelector(quer);
//console.log(typeInput);
TypeSelect(typeInput);
return;
}
}
}
function fillName(namek)
{
for (var k=0; k<document.getElementById(namek).options.length; k++)
{
//console.log(document.getElementById(namek).options.length);
console.log(exerRoutine[rowNum-1].name);
if(document.getElementById(namek).options[k].value === exerRoutine[rowNum-1].name)
{
document.getElementById(namek).selectedIndex = k;
//console.log(document.getElementById(namei).selectedIndex);
return;
}
}
}
function fillSets(setsk)
{
for (var k=0; k<document.getElementById(setsk).options.length; k++)
{
console.log(exerRoutine[rowNum-1].sets);
if(document.getElementById(setsk).options[k].value === exerRoutine[rowNum-1].sets)
{
document.getElementById(setsk).selectedIndex = k;
//console.log(document.getElementById(setsk).selectedIndex);
return;
}
}
}
function fillReps(repsk)
{
for (var k=0; k<document.getElementById(repsk).options.length; k++)
{
console.log(exerRoutine[rowNum-1].reps);
if(document.getElementById(repsk).options[k].value === exerRoutine[rowNum-1].reps)
{
document.getElementById(repsk).selectedIndex = k;
//console.log(document.getElementById(repsi).selectedIndex);
return;
}
}
}
function fillPace(pacek)
{
for (var k=0; k<document.getElementById(pacek).options.length; k++)
{
console.log(exerRoutine[rowNum-1].pace);
if(document.getElementById(pacek).options[k].value === exerRoutine[rowNum-1].pace)
{
document.getElementById(pacek).selectedIndex = k;
//console.log(document.getElementById(pacek).selectedIndex);
return;
}
}
}
}
I want to create a recursive JavaScript loop which can display all the Frames (either using IFRAMES Tag or using FRAME Tag). The result should give FrameName, NestingLevel, FrameURL, etc.
For example, when we open 'Developer Tools' in Google Chrome, we can see in all the FRAMES(even nested Frames too) in the console tab.
Please give a recursive loop with error handling (iframe security issue) for the same.!
Sample Code:
function getFramesInfo(oWin) {
arrFrames = oWin.frames;
//alert(arrFrames.length);
if (arrFrames.length == 0) {
alert('document do not have frame(s)');
} else {
for (i = 0; i < arrFrames.length; i++) {
console.log(i + ' ' + arrFrames[i].location.href);
if (arrFrames[i].document) {
getFramesInfo(arrFrames[i]);
}
}
}
}
//Calling This Function
getFramesInfo(window);
Alternate / Improved Code:
function getAllFrames(frame, allFrameArray) {
allFrameArray.push(frame.frames);
for (var i = 0; i < frame.frames.length; i++) {
getAllFrames(frame.frames[i], allFrameArray);
}
return allFrameArray;
}
//Usage:
var allFramesArray = getAllFrames(window, new Array());
console.log(allFramesArray.length); // number of frames in array
for (var i = 0; i < allFramesArray.length; i++) {
console.log('\n\n No.'+ (i+1) + '.');
try {
console.log(allFramesArray[i].id);
console.log(allFramesArray[i].name);
console.log(allFramesArray[i].location.href); // location of first frame in array}
} catch (e) {
console.log('Error in Accessing Frame No.' + (i+1) ); // location of first frame in array}
}
}
After googling and exploring I have found a simple solution, but I think this answer should be improved to avoid any possible errors (i.e. precise error handling should be done to avoid cross-domain frames issue):
Sample Solution:
// first parameter is frame (window) in which to get sub frames
// second is the array to build on
function getAllFrames(frame, allFrameArray) {
allFrameArray.push(frame.frames);
for (var i = 0; i < frame.frames.length; i++) {
getAllFrames(frame.frames[i], allFrameArray);
}
return allFrameArray;
}
Usage:
var allFramesArray = getAllFrames(window, new Array());
console.log(allFramesArray.length); // number of frames in array
for (var i = 0; i < allFramesArray.length; i++) {
try {
console.log(allFramesArray[i].location.href); // location of first frame in array}
} catch (e) {
console.log('Error in Accessing Frame No.' + i); // location of first frame in array}
}
}
Here is another one (shortcut example)
var i = new Array;
function wow(a, n) {
t = '';
for (i[n] = 0; i[n] < a.length; i[n]++) {
try {
t += a[i[n]].name + ' \n';
} catch (e) {
t += 'Error \n';
}
if (a[i[n]].frames.length) t += wow(a[i[n]].frames, n + 1);
}
return t;
}
//Usage:
console.log(wow(top.frames, 0));
While browsing for a code, I recently have learnt a new code, using this code which takes a javascript window object as input and returns all its nested windows (including multiple levels of nesting). This function however is an efficient/elegant way that can be used to grab a reference to all the windows (objects) and all the child windows (objects). I have checked this function and found that it works well, it could be understood that making/writing this function completely recursively, as the DOM object tree is actually an n-ary, not binary.
function getAllNestedWindows(window) {
var windows = [window];
if (window.length === 0) {
return windows;
} else {
for (var i = 0; i < window.length; i++) {
windows = windows.concat(getAllNestedWindows(window[i]));
}
}
return windows;
}
Edit: I am also open to other suggestions on what I could do.
How can I update my window with the onChange event? My solution works, but I need the groups to collapse when not visible.
w.DD.onChange = function() {
switch (this.selection.text){
case 'Headline':
if(w.visiblegroup)
w.visiblegroup.visible = false;
w.visiblegroup = w.texted;
w.texted.visible = true;
break;
}
}
I have tried to use w.show, w.update(with documentation, still not sure what .update actually does) after adding the elements in the case itself. But I can't figure this out.
w.DD.onChange = function() {
switch (this.selection.text){
case 'Headline':
w.add('checkbox', undefined, 'User-Color');
//w.show();
w.update();
break;
}
}
Does anyone have a clue how this might work?
I generally avoid using LayoutManager and do all teh maths by myself which I trust better but that's my humble opinion…
var w = new Window("dialog");
w.preferredSize = [200,200];
w.DD = w.add( 'dropdownlist', undefined, ["A","B"] );
w.DD.selection = 0;
w.DD.alignment = ["fill","top"];
//Setting a stacked group to items overlay
w.gp = w.add('group');
w.gp.orientation = 'stack';
w.gp.alignment = ["fill","top"];
w.gp.alignChildren = ["fill","top"];
w.gp.p1 = w.gp.add('panel',undefined, "A");
w.gp.p2 = w.gp.add('panel',undefined, "B");
//dummy text to show "collapsing"
w.st = w.add('statictext',undefined, "Collapse ?");
w.DD.onChange = function() {
w.gp.p1.visible = w.DD.selection==0;
w.gp.p2.visible = !w.gp.p1.visible;
w.gp.p2.size.height =100;
w.gp.size.height = w.gp.p1.visible? 50 : 100;
w.st.location.y = w.gp.location.y+w.gp.size.height+10;
}
w.onShow = function() {
w.gp.p2.visible=false;
w.gp.size.height = w.gp.p1.size.height = 50;
w.st.location.y = w.gp.location.y+w.gp.size.height+10;
}
w.show();
Loic
To collapse the groups and window you will need to use the layout() method of your window. This will load the LayoutManager that controls the automatic layout behavior for a window or container. The LayoutManager has a method called layout() too, this method invokes the automatic layout behaviour and invoked automatically the first time the window is displayed. Thereafter, the script must invoke it explicitly like so:
window.layout().layout();
An example of how to use the layout manager by Gerald Singelmann:
function main() {
var win = new Window("dialog");
var maingroup = win.add("panel");
maingroup.orientation = "column";
add_group( maingroup );
var show_btn = win.add("button", undefined, "show");
show_btn.onClick = function() {
var txt = "";
for (var n = 0; n < maingroup.children.length; n++) {
txt += maingroup.children[n].edit.text + "\n";
}
alert("Da steht: \n" + txt );
}
win.show();
function add_group( maingroup ) {
var group = maingroup.add( "group" );
group.edit = group.add("edittext", [undefined, undefined, 200, 20], maingroup.children.length );
group.plus = group.add("button", undefined, "+");
group.plus.onClick = add_btn;
group.minus = group.add("button", undefined, "-");
group.minus.onClick = minus_btn;
group.index = maingroup.children.length - 1;
win.layout.layout( true );
return group;
}
function add_btn ( e ) {
add_group( maingroup );
}
function minus_btn ( e ) {
var ix = this.parent.index;
maingroup.remove( maingroup.children[ix] );
win.layout.layout( true );
}
}
source
I'm trying to combine a few similar functions into a single functions, which need to make calls to different arrays / variables, but I'm not quite getting it right. Here's my code:
var initialPreloadArray = ['scenes/icons_orange.png','scenes/icons_blue.png','scenes/icons_green.png','site/pedestal_h.png']; //These must be loaded before we advance from the intro screen
var initialPreloadCounter = 0;
var secondaryPreloadArray = ['site/restart-black.png','site/back_black.png','interludes/city.png','interludes/town.png','interludes/country.png']; //These must be loaded before we can advance from the initial decision scene
var secondaryPreloadCounter = 0;
var vehiclesPreloadArray = ['vehicles/vehicles.png','site/close.png']; //These must be loaded before we can display the vehicles
var vehiclesPreloadCounter = 0;
var arrName; //Store the variable name of the array for the stage of preloading we're in
var arrCounter; //Stores the variable name of the counter for the stage of preloading we're in
function setPreloadStage(preloadStage){
if (preloadStage == initial){
arrName = initialPreloadArray;
arrCounter = initialPreloadCounter;
} else if (preloadStage == 'secondary'){
arrName = secondaryPreloadArray;
arrCounter = secondaryPreloadCounter;
} else if (preloadStage == 'vehicles'){
arrName = vehiclesPreloadArray;
arrCounter = vehiclesPreloadCounter;
}
preloadImages(preloadStage);
}
//Recurse through scene xml and populate scene array
function preloadImages(preloadStage) {
console.log(arrName[arrCounter]);
var img = new Image();
img.src = 'images/' + arrName[arrCounter];
if(!img.complete){
jQuery(img).bind('error load onreadystatechange', imageComplete(preloadStage));
} else {
imageComplete(preloadStage);
}
//$j.preloadCssImages({statusTextEl: '#textStatus', statusBarEl: '#status'});
}
function imageComplete(preloadStage){
arrCounter++;
var preloadLength = arrName.length-1;
if (arrName && preloadLength && arrName[arrCounter]) {
if (preloadLength == arrCounter){
if (preloadStage == 'initial'){
initialImagesLoaded();
} else if (preloadStage == 'secondary'){
secondaryImagesLoaded();
} else if (preloadStage == 'vehicles'){
vehiclesLoaded();
}
}
preloadImages(preloadStage);
}
}
Anybody have an idea what I'm doing wrong?
Actually, here’s an even more obvious problem:
jQuery(img).bind('error load onreadystatechange', imageComplete(preloadStage));
You would have to do this:
jQuery(img).bind('error load onreadystatechange', function () {
imageComplete(preloadStage)
});
I suggest that you should use an array to manage state.
define an array holding your stages, like this:
var stages = [
{
label : 'initial',
imgs : [ 'img/whoobee.png', ...more here...],
doneSoFar: 0,
allDone: function(){}
},
{ label : 'secondary', imgs : .....},
{ label : 'whatever', imgs : ....}
];
NB: You will need to set the "allDone" fn for each stage appropriately.
Then a fn that kicks off one stage:
function kickoffPreloadOneStage(stage) {
console.log ("preloading stage " + stage.label);
preloadNextImage(stage);
}
function preloadNextImage(stage) {
var img = new Image();
img.src = 'images/' + stage.imgs[stage.doneSoFar];
if(!img.complete){
jQuery(img).bind('error load onreadystatechange', function() {
imageComplete(preloadStage);
});
}
else {
imageComplete(preloadStage);
}
}
function imageComplete(stage){
stage.doneSoFar++;
var preloadLength = stage.imgs.length-1;
if (stage.doneSoFar == preloadLength) {
stage.allDone(); // call the allDone function. may want to pass stage back
}
else {
preloadNextImage(stage);
}
}
To do all stages, use code like this:
var i;
for(i=0; i < stages.length; i++) {
kickoffPreloadOneStage(stages[i]);
}
You can also go OO, defining those functions as members of a Stage() class, but ....what I suggested is a reasonable simplification without getting too complicated.