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

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!

Related

Show/Hide elements by dependency

I was inspired by this topic Show/Hide form fields based on value of other fields and made some changes to working it not only on select.
Here is example:
var ObserverPlugin = (function(){
// here will be stored every DOM object which has
// data-observe attr and data-name attr (data-name will be served
// as a key , which will store another object with a reference to the DOM object
// how many object does it observe)
var observers = {},
publishers = [];
var _setStylesheet = (function() {
// Create the <style> tag
var style = document.createElement("style");
// Add a media (and/or media query) here if you'd like!
// style.setAttribute("media", "screen")
// style.setAttribute("media", "only screen and (max-width : 1024px)")
// WebKit hack :(
style.appendChild(document.createTextNode(""));
// Add the <style> element to the page
document.head.appendChild(style);
return style.sheet;
})();
// observer pattern & revealing module pattern
var observer = (function(){
var topics = {};
var publish = function(topic, reference) {
// if there is no topic on the publish call, well get out !
if (!topics[topic]) {
return false;
}
// self invoked funciton, which calls the function passed when
// the topic was subscribed (if more then one function was published on the same topic
// then call each one of them)
(function(){
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, reference);
}
})();
};
var subscribe = function(topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}
topics[topic].push({
func: func
});
};
return {
subscribe: subscribe,
publish: publish,
topics: topics
}
})();
// creates random string, used to make data-name random for observers
var _makeRandomString = function() {
var text = "";
var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 5; i++ ) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
// verifies if eleme existis in array, if not, returns false
var _isInside = function( elem, array ) {
return array.indexOf(elem) > -1;
};
// topic is the topic
// reference is a reference to the DOM object clicked
var _observerFunction = function(topic, reference) {
var number = reference.attr('data-publish-value');
var topics = topic.toString().split(' ');
var length = topics.length;
//var display;
for( var key in observers ) {
for( var i = 0; i < length; i +=1 ) {
if( _isInside( topics[i], observers[key].topicsObserved ) ) {
// it exists
observers[key].sum += Number(number);
// 'number' is a string, so we have to convert it back to number
}
}
if( observers[key].sum === 1 ) {
// it is 0, so show that goddam DOM obj ! :))
// again, put here 'var' for clarity
// does not affect the code
//display = 'block';
_changeProperty(key,observers[key].property,1);
}
else {
// it is not 0, so hide it
//display = 'none';
_changeProperty(key,observers[key].property,0);
}
//observers[key].reference.css('display', display);
}
// change value to -1 or 1
if( number === '-1' ) {
reference.attr('data-publish-value', '1');
}
else {
reference.attr('data-publish-value', '-1');
}
};
/*
* lets say we have 3 DOM objects with data-publish="1"
and 2 DOM objects with data-publish="2"
and one with data-observe="1 2";
so data-observe has to be called 5 times in order for him to be shown on the page;
each DOM object with data-publish will be added at runtime a data-value attribute
which will be -1 or 1. each time it is clicked or changed, it changes to the opposite.
this serves as data-observes will have a property named sum, which will be in the previous case 5
5 gets calculated with -1, or 1 when clicked data-publish DOM object.
So if i click first at data-publish="1" , 5 becomes 4. if i click again the same data-publish, becomes 5.
when sum property becomes 0, the data-observe is shown.
this function calculates how many data-publish="1" exists and so on
(it also does the other stuff needed for publishers)
*/
var _managePublishers = function() {
$('[data-publish]').each(function(){
var el = $(this);
// adds that value data, remember it? :D
el.attr('data-publish-value', '-1');
// trim in case data-publish = "1 2 3" and store in an array
var publisher = el.data('publish').toString();
// we subscripe 'publisher' topic, but we check each string in topic
// here is tricky. if one publishers has more than one topic inside data-publish
// then we subscribe topic, but we check for topic's substring in publishers
var topics = publisher.split(' ');
if( !observer.topics[publisher] ) {
// we subscribe data-publish topic, becouse when we click it we want to fire something, no?
observer.subscribe( publisher, _observerFunction );
}
// but here in publishers we add only the substrings
for( var key in topics ) {
if( publishers[topics[key]] ) {
// the publisher exists
publishers[topics[key]] += 1;
}
else {
// the publisher doesn't exist
publishers[topics[key]] = 1;
}
}
});
};
// gets the observers, calculates sum, caches their reference
var _manageObservers = function() {
$('[data-observe]').each(function(){
var el = $(this);
// create random data-name
el.attr('data-observe-name', _makeRandomString());
var datas = el.data('observe').toString().split(' '); // make an array again if we have multiple attachments
observers[el.data('observe-name')] = (function(){
var sum = (function(){
var sum2 = 0;
// if datas[key] is found in publishers array, add it to sum
for( var key in datas ) {
var temp = publishers[datas[key]];
if( temp ) {
sum2 += temp;
}
}
return sum2;
})();
var reference = el, topicsObserved = datas; // caching, so it is faster !
// we need this when a user clicks data-publish, we need to see which DOM obj. are observing this.
// i really like revealing module pattern...i got used to it
return {
sum: sum,
reference: reference,
topicsObserved: topicsObserved,
property: $(reference).data('observe-property') //style-display[none/block],attr-disable/-,class-active/inactive
}
})();
})
};
var _changeProperty = function(observer, property, status) {
if(property === "style") {
if(status === 1) {
observers[observer].reference.css('display', 'block');
}
else {
observers[observer].reference.css('display', 'none');
}
}
else if(property === "attr") {
if(status === 1) {
$(observers[observer].reference).removeAttr('disabled');
}
else {
$(observers[observer].reference).attr('disabled','disabled');
}
}
else if(property === "class") {
if(status === 1) {
$(observers[observer].reference).removeClass('inactive');
}
else {
$(observers[observer].reference).addClass('inactive');
}
}
};
var init = function() {
_managePublishers();
_manageObservers();
$('[data-publish]:not(select)').on( 'click', function(){
observer.publish( $(this).data('publish'), $(this) );
});
$('select[data-publish]').on('change', function(){
var cache = $(this);
// if in this select there is an option which has value 1(there is chance that it triggered a succesfull publish) we publish that too
//observer.publish( cache.find('[data-value="1"]').data('publish'), cache.find('[data-value="1"]') );
var el = cache.find(':selected');
observer.publish( el.data('publish'), el );
});
$('[data-publish]').each( function() {
if(this.type !== 'radio' || this.type !== 'checkbox' || this.nodeName !== 'SELECT') {
observer.publish( $(this).data('publish'), $(this) );
}
});
// when observers[xx].sum is 0 it must be activated always, otherwise it is always invisible
$.each( observers, function( key, value ) {
if(value.topicsObserved) {
$.each( value.topicsObserved, function( key2, value2 ) {
if(!publishers.hasOwnProperty(value2)) {
$(value.reference).css('display', 'block');
return;
}
if(value.property === "style") {
_setStylesheet.insertRule('[data-observe-name="'+key+'"] {display: none;}', _setStylesheet.rules.length);
}
else if(value.property === "attr") {
$(value.reference).attr('disabled','disabled');
_setStylesheet.insertRule('[disabled] {cursor: not-allowed;}', _setStylesheet.rules.length);
}
else if(value.property === "class") {
$(value.reference).addClass('inactive');
}
});
}
});
};
return {
init: init,
publish: observer.publish,
subscribe: observer.subscribe
}
})();
ObserverPlugin.init();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="post" name="form">
<input type="text" name="text" value="">
<div class="wraper">
<label><input type="radio" name="typ" value="subscribe" checked data-publish="newslist" >Subscribe</label>
<label><input type="radio" name="typ" value="unsubscribe" data-publish="unsubscribe" >Unsubscribe</label>
</div>
<div class="wraper">
<button type="submit" name="subscription" value="1" data-observe="newslist" data-observe-property="attr" >
<span>Send</span>
</button>
</div>
<div data-observe="unsubscribe" data-observe-property="style">
<label>
<input type="checkbox" name="confirm" value="1" data-publish="newslist">
<span>Confirm</span>
</label>
</div>
</form>
jsfiddler also here https://jsfiddle.net/ogxusLja/
Problem is that radio inputs fired click event always, not only on
change to second radio input.
Another problem is that Confirm
checkbox is hidden on load.
Expected behavior:
Selected Unsubscribe radio will enable the Send button and hide the Confirm checkbox.
Selected Subscribe radio and Confirm checkbox will together enable the Send button.
Selected Subscribe radio or 'Confirm checkbox' (if only one is selected) Send button will be disabled.

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.

Why is some jQuery/javascript code being skipped?

I am currently coding an instant chatbox using jquery which will show the latest chat on top (refreshes when user send data via post request)
and push the oldest chat downward and remove it.
The problem is that if more than one latest chat is retrieved(for example, 2), two new div will be prepended but only one oldest div is removed instead of two...I tried timeout but it didnt work either..
Below are the code snippets I believe which got problem in it.
function showData(currentchatstyle, data, final){
var newchatstyle;
if (currentchatstyle == "chatone") {
newchatstyle = "chattwo";
}
else {
newchatstyle = "chatone";
}
$('div[class^="chat"]:first').before('<div class="' + newchatstyle + '" style="display:none;">' + data + ' </div>');
$('div[class^="chat"]:first').slideDown(500,"swing", function(){
$('div[class^="chat"]').last().fadeOut(500, function() {
$(this).remove();
});
});
return newchatstyle;
}
$('input[name="content"]').keyup(function(key) {
if (key.which==13) {
var author = $('input[name="author"]').val();
var content = $('input[name="content"]').val();
var lastnum = $('postn:first').text();
var chatstyle = $('div[class^="chat"]:first').attr("class");
$.post(
"chatajax.php",
{ "author": author, "content": content, "lastnum": lastnum },
function(data) {
var msg = data.split("|~|");
for (var i = 0; i < msg.length; i++) {
chatstyle = showData(chatstyle, msg[i], true);
}
}
);
}
});
Help will be very much appreciated.
The problem is that you do select also currently-fading-out divs with $('div[class^="chat"]').last(), as you don't remove them immediately but in the animation callback. You for example might immediately remove the chat class so it won't be selected in the next call to showData.
Also, you should only use one class "chat" for a similar divs and for a zebra-style give them independent classes.
var chatstyle = "one";
function showData(data, final){
chatstyle = chatstyle=="one" ? "two" : "one";
var newDiv = $('<div class="chat '+chatstyle+'" style="display:none;">'+data+'</div>');
$('div.chat:first').before(newDiv);
newDiv.slideDown(500, "swing", function(){
$('div.chat:last').removeClass('chat').fadeOut(500, function() {
// ^^^^^^^^^^^^^^^^^^^^
$(this).remove();
});
});
}
function post(data) {
return $.post(
"chatajax.php",
data,
function(data) {
var msg = data.split("|~|");
for (var i = 0; i < msg.length; i++)
showData(msg[i], true); // what's "final"?
}
);
}
$('input[name="content"]').keyup(function(key) {
if (key.which==13)
post({
"author": $('input[name="author"]').val(),
"content": $('input[name="content"]').val(),
"lastnum": $('postn:first').text() // I'm sure this should not be extracted from the DOM
});
});

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.

function iterates through loop and works once but never again

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');
}
}

Categories