function iterates through loop and works once but never again - javascript

I'm calling a Titanium modal window to open and then run a function which loops through some data like so;
Window 1:
var win = Ti.UI.createWindow({
url: 'window2.js'
modal: 1
});
win.open();
Window 2: (called from window 1)
win = Ti.UI.currentWindow;
function doLoop() {
Ti.API.info('doLoop fn called');
// I've tracked the issue down to here
var m = 0;
for(var i in list) { m++; }
Ti.API.info(m);
Ti.API.info('finished');
}
win.addEventListener('open', function() {
// list is dynamically generated and passed through successfully from window1.js
doLoop();
});
doLoop() is called successfully each time and list is called each time successfully.
The first time run it works perfectly. The second(any that isn't first) time run it takes time to pause and run the the loop but m is never incremented? After the pause for the loop outputs 'finished'.
Any ideas?
function buildMediaItemsSelectionTable() {
var mediaCount = 0, i;
for(i in mediaItemsSelectionList[0]) { mediaCount++; }
for(i=0,l=mediaCount;i<l;i++) {
addMediaItemsSelectionSongsRow(i);
}
}

There are several issues I see here.
First, the problems with your buildMediaItemsSelectionTable() function
Your for..in loop might catch object properties you don't
There's no need for the double loop
Here's those modifications in place
function buildMediaItemsSelectionTable()
{
var i = 0, p;
for ( p in mediaItemsSelectionList[0] )
{
if ( mediaItemsSelectionList[0].hasOwnProperty( p ) )
{
addMediaItemsSelectionSongsRow( i++ );
}
}
}
The other issue is one I'm having to guess at since you didn't provide enough code. I'm assuming that you're passing list to the modal with Titanium's variable forwarding. Perhaps something like this?
var win = Ti.UI.createWindow({
url: 'window2.js'
, modal: 1
, list: [1,2,3]
});
And something has to repeatedly open the modal, right? Maybe a button
var button = Ti.UI.createButton( {title: 'Modal'} );
Ti.UI.currentWindow.add( button );
button.addEventListener( 'click', function()
{
win.open();
});
But according to your description, list changes so let's make a random list generator and plug it in to our page so the entire thing looks like this
var win = Ti.UI.createWindow({
url: 'window2.js'
, modal: 1
, list: randomList()
});
var button = Ti.UI.createButton( {title: 'Modal'} );
Ti.UI.currentWindow.add( button );
button.addEventListener( 'click', function()
{
win.open();
});
function randomList()
{
// Random return an array with 3, 5, or 7 items
return [[1,2,3],[1,2,3,4,5],[1,2,3,4,5,6,7]][Math.floor(Math.random()*2)];
}
What's wrong here? randomList() is only called once, regardless of how many times you open the modal. Even if window1 is part of a nav or tab group, the code that creates the modal window doesn't re-execute under any circumstances.
If you want a new list to be forwarded to the modal every time, you'll have to generate it fresh every time
button.addEventListener( 'click', function()
{
win.list = randomList();
win.open();
});

Looks like your '}' is in the wrong place. Right now you have a loop with a single (likely unintended) side effect - m counts up to the length of the list and then there is a call to API.info with the length of list.
You probably want :
function doLoop() {
Ti.API.info('doLoop fn called');
// I've tracked the issue down to here
var m = 0;
for(var i in list) {
m++;
Ti.API.info(m);
Ti.API.info('finished');
}
}

Related

How do I get the 'else' condition to show up?

I'm currently working on an app in Code.org and I can't seem to figure out why my if statement isn't working.
What I want my code to do is to check if what the user guesses as the rank position for the song is correct, then the word 'correct' will show in a textbook below. And if it isn't correct then the word 'wrong' should show. But all it does is show 'wrong'.
sorry for the bad explanation, I don't really know how to explain this.
here is a more updated version of my code:
// variables
var songList =getColumn("Viral 50 USA", "Track Name") ;
var artistList = getColumn("Viral 50 USA", "Artist");
var rankList= getColumn("Viral 50 USA", "Position");
// filtered lists
var filteredSongList = [];
var filteredArtistList = [];
var filteredRankList= [];
// first function chooses a random song from the data
function randomSongFunction() {
filteredSongList= [];
filteredArtistList= [];
filteredRankList= [];
for (var i = 0; i < songList.length; i++) {
var song = songList[i];
if (song == songList[i]) {
appendItem(filteredSongList, songList[i]);
appendItem(filteredArtistList, artistList[i]);
appendItem(filteredRankList, rankList[i]);
}
}
}
// displays the actual text of the song and artists name on screen2 using the filtered lists
function updateScreen2() {
var index = randomNumber(0, filterSongList.length-1);
setText("artistOutput", filterArtistList[index]);
setText("songOutput", filterSongList[index]);
}
// when the start button is clicked the screen changes
onEvent("startButton", "click", function( ) {
setScreen("screen2");
});
onEvent("yesButton", "click", function( ) {
setScreen("screen3");
});
onEvent("noButton", "click", function( ) {
setScreen("screen1");
});
onEvent("homeButton", "click", function( ) {
setScreen("screen1");
});
// when the button is clicked, it will call the functions
onEvent("chooseButton", "click", function( ) {
randomSongFunction();
updateScreen2();
});
//
onEvent("checkButton", "click", function( ) {
var guessRankNum = getProperty("dropdown", "value");
for (var i = 0; i < rankList.length; i++) {
if (guessRankNum == rankList[i]) {
setText("answerOutput", "correct!");
} else {
setText("answerOutput", "wrong");
}
}
});
In your program,
randomSongFunction(); is not being called, so there isn't a rank for rankFunction(); to compare the dropdown's answer to.
When I put your code in code.org, it wasn't resulting in anything, even though I imported the same list, etc. When I called randomSongFunction, it displays "wrong." I'm just not sure if that was working correctly because I did not have the original dropdown options since they weren't specified.
See if calling randomSongFunction(); before rankFunction(); works for you.
I hope this helps!

Extjs 3.4 Button fires n times

I have a button that fires some action such as
someBtn.on('click'm function(..) { ... }
and I did some arithmetic operation inside. I saw calculated numbers and it was wrong, so I used console.log() to track it and the action was being fired multiple times.
More specifically, I have a window, let's say A, that has multiple rows and when I click one of the rows another window, B, pops up and I can type numbers there. When I type numbers and click saves it does some works and hide B windows and I can click other rows on A to alter other rows.
When I click first time, B runs only once, and second time, it runs twice, third, three times ....
I have been looking at my code but I have no idea how this can be happening.
This is my code:
function openCustDeposit(idCustomer) {
require(['view/Deposit'], function (dep) {
var windep= Ext.getCmp('windep');
if (!windep) {
windep= new Ext.Window({
...
items : [dep.initObj],
plain : true,
closable: true,
closeAction :'hide',
...
listeners:{
show:function() {
this.loadMask = new Ext.LoadMask(this.body, {
msg:'Loading. Please wait...'
});
},
destroy:function(){
if(this.mask)delete this.mask;
}
}
});
} else {
....
}
...
windep.show();
...
dep.store.load();
dep.grid.custDepositPostBtn.on('click', function(obj,evt)
{
try {
var str_idCrdtMemo='', str_CRApply='', sumCRApply=0;
var objGrid = grid;
var selRec = objGrid.selModel.getSelected();
....
selRec.set('CustDeposit', sumCRApply);
selRec.set('idPostCheck', str_idCrdtMemo.substr(0,str_idCrdtMemo.length-1));
selRec.set('CustDeposit2', str_CRApply.substr(0,str_CRApply.length-1));
....
closeWin(arCustDeposit.grid); // window close
}
catch (e) { Ext.MessageBox.alert('Error', e); }
finally {
....
}
});
});
}`
Any advice would be very helpful. Thanks

Can't empty array between submits

I'v been struggling with this problem for quite long now. I have an array where I'll be pushing numbers on button click to array like [2,6,8]. I tried emptying the array between submits with another button click but I'm unsuccessful. Can someone point out my mistake? The array keeps printing the first result even if I try to format and change it many times after that. The data-index also changed correctly in the DOM. I tried to empty the array also at the start of #accept click, but with no effect.
var mediaArray = [];
$( "#clearAll" ).click(function() {
mediaArray = [];
console.log("i can see this");
});
$( "#accept" ).click(function() {
var firstRound = true;
var mediaLength = 0;
var eachData = 0;
$( ".slots" ).each(function(index) {
if (!firstRound) {
mediaLength++;
if ($(this).data('index') != eachData) {
mediaArray.push(mediaLength);
mediaLength = 0;
}
}
eachData = $(this).data('index');
firstRound = false;
console.log($(this).data('index'));
});
mediaArray.push(mediaLength+1);
console.log(mediaArray);
});
that's pretty simple. It is due to your firstRound being true every time the click handler is invoked.
To fix it, you might want to have firstRound as a global variable, but that usually is not desired, in which case you can use an IIFE to make it local:
(function() {
var firstRound = true;
$( "#accept" ).click(function() {
// ...
});
}());
You should declare firstRound to be global. This will ensure it is set to true only in the first round. Right now it is being true at every call to onClick handler at id #accept.

Have a JS function *constantly* listen for clicks?

This seems like something that should be really simple. I have a few images animating on a page, but I want the user to be able to click on any one of them at any time and then go to a related page.
Problem is, evidently clicks stopped being listened for at some point if I use a loop to search through an array of clickable items. I thought having a function separate from the one that handles the animation would allow it to constantly listen no matter what the animated images were doing, but it seems once the "complete" function is called (for the "animate" function), the function that is listening for clicks (wholly separate from the animation, and using setInterval to listen for clicks) stops listening.
Oddly enough, I believe I did not have this problem when just listening for "img" instead of an array of different images.
Ideas as to what I'm doing wrong? More info needed? I tried to remove any irrelevant code below.
var links = ["#portfolio", "#animations", "#games"];
$(function() {
setInterval(function(){
for (var i=0; i<links.length; i++) {
$(links[i]).click(function(){
window.location.replace("http://www.gog.com");
});
}
}, 500);
});
$(document).ready(function() {
links.forEach(function(current){
//various vars
var link = $(current);
var footer3 = $(".footer3");
var over = true;
var randomTime = 3000*(Math.random()+1);
//dust vars
...
//image vars
var imageUrlShadow = 'images/home/non-char/shadow-pngs/shadow';
var imageUrlCharacter = 'images/home/char-pngs/';
var portfolioSrc;
var animationsSrc;
var gamesSrc;
//animate the characters
link.animate({
top: '0'
}, {
duration: randomTime,
easing: 'easeOutBounce',
step: function(now, tween) {
/*handle shadows*/
...
/*handle characters*/
if (now < -25 && over == false) {
...
} else if (now >= -25) {
...
}
$("#"+ link.data("portfolio")).attr('src', portfolioSrc);
$("#"+ link.data("animations")).attr('src', animationsSrc);
$("#"+ link.data("games")).attr('src', gamesSrc);
/*handle dust*/
var dustDoneMoving = '-50px';
var dustNotMoving = '0px';
//if link is NOT touching footer3
...
//set to "sitting" images when animation is done
complete: function() {
...
setTimeout(function() {
...
}, 1000);
}
})
})
});
var links = ["#portfolio", "#animations", "#games"];
$(function() {
$(links.join(',')).click(function(){
window.location.replace("http://www.gog.com");
});
});
One time only and listener will be attached to the image.
Consider listening via window
var links = ["#portfolio", "#animations", "#games"];
$(window).on('click', links.join(', '), function() {
// do what you wanna
});
I apologize, it turns out that, apparently, the problem was related to the z-index. There were some other divs with 0 opacity "covering up" the array divs.
Setting the z-index to 2 for the array items has fixed the matter. Again, my apologies.
I have modified your code. See, if this works now.
I have added one more array which contains some URLs. So, the intention is that on click of a particular element, its respective URL should be opened.
So, the sequence in these array will matter with respect to each other.
Also, I have made use of 'on', so that 'click' event should be handled even during animation.
var links = ["#portfolio", "#animations", "#games"];
var sites = ["http://www.gog.com", "http://www.gog1.com", "http://www.gog2.com"]; //change these to the expected URLs
$(function() {
for (var i=0; i<links.length; i++) {
$(document ).on("click",links[i],function(){
window.location.replace(sites[i]);
});
}
});

Tried to register widget with id==valores0 but that id is already registered

i get this error, and i don't know how can be solved. I read this link before.
EDIT:1
index.php
<script type="text/javascript">
$(document).ready(function() {
$("#customForm").submit(function() {
var formdata = $("#customForm").serializeArray();
$.ajax({
url: "sent.php",
type: "post",
dataType: "json",
data: formdata,
success: function(data) {
switch (data.livre) {
case 'tags':
$("#msgbox2").fadeTo(200, 0.1, function() {
$(this).html('Empty tags').fadeTo(900, 1);
});
break;
default:
$("#msgbox2").fadeTo(200, 0.1, function() {
$(this).html('Update').fadeTo(900, 1, function() {
$('#conteudo').load('dojo/test_Slider.php');
});
});
break;
}
}
});
return false;
});
});
</script>
test_slider.php
<script type="text/javascript">
var slider = [];
for (i = 0; i < 5; i++) {
slider[i] = (
function(i) {
return function() {
var node = dojo.byId("input"+[i]);
var n = dojo.byId("valores"+[i]);
var rulesNode = document.createElement('div'+[i]);
node.appendChild(rulesNode);
var sliderRules = new dijit.form.HorizontalRule({
count:11,
style:{height:"4px"}
},rulesNode);
var labels = new dijit.form.HorizontalRuleLabels({
style:{height:"1em",fontSize:"75%"},
},n);
var theSlider = new dijit.form.HorizontalSlider({
value:5,
onChange: function(){
console.log(arguments);
},
name:"input"+[i],
onChange:function(val){ dojo.byId('value'+[i]).value = dojo.number.format(1/val,{places:4})},
style:{height:"165px"},
minimum:1,
maximum:9,
}
},node);
theSlider.startup();
sliderRules.startup();
}
})(i);
dojo.addOnLoad(slider[i]);
}
</script>
Problem: First click in submit btn all works well, 5 sliders are imported. Second click, an update is supposed, but i get this message:
Tried to register widget with id==valores0 but that id is already registered
[Demo video]2
Just to add on to #missingo's answer and #Kevin's comment. You could walk through the existing dijits by looking in the registry:
var i = i || 0; // Cache this at the end of your loop
dijit.registry.map(function (widget) {
if (+widget.id.replace(/^[^\d]+/, '') < i) {
widget.destroyRecursive();
}
});
/*
Your loop fixed as described in missingno's answer.
*/
You fell in the age-old trap of making function closures inside a for loop. By the time addOnLoad fires and the sliders are created, i will be equal to 2 and both sliders will try to use the same DOM nodes (something that is not allowed).
You need to make sure that you give a fresh copy of i for everyone. The following is a quick fix:
for(i=0; i<2; i++){
(function(i){
slider[i] = ...
//everything inside here remains the same
//except that they now use their own i from the wrapper function
//instead of sharing the i from outside.
}(i));
}
Dijit stores all active widgets in the dijit.registry, and uses id's as unique qualifiers. You can't create dijits with same id.
Need to clean dojo.registry before create a new slider dijits. Add this code before declare dijit on test_slider.php
dijit.registry["input"+ [i]].destroyRecursive();
can you assign any number ID like ID generated by 10 digit random number or something with datetime combination so id will never be same.

Categories