JS Outer scoped variable - javascript

I have been working on and off on a game app based on the game show Countdown. So far I have been able to get the user to choose vowels and consonants and input a word which checks to see if the word that was entered contains the same letters that were generated. I have created an anonymous function which uses jQuery to check a dictionary text file to see if it is listed. However I'm running into trouble, I keep getting a warning message "functions declared within loops referencing an outer scoped variable may lead to confusing semantics."
I'm not sure what I'm doing wrong, please see code below:
$(".submission").hide();
//assigning letter container class to variable
var letterContainer = document.querySelector(".letter-container");
function pickFrom(letters) {
// if the length of the letter container is less than 8
if (letterContainer.innerHTML.length < 8) {
//add letters to the letter container
letterContainer.innerHTML += rando(letters);
}
//once letter container length reaches 8
if (letterContainer.innerHTML.length === 8) {
//show submission input and button
$(".submission").show();
//remove letter buttons after 8 letters have been chosen by user
$(".letter-btn").hide();
//assign given letters from letter container to a variable
var givenLetters = letterContainer.innerHTML.split("");
var inputWord = document.querySelector(".enter-word").value;
document.querySelector(".submit-word").addEventListener("click", function() {
var inputWord = document.querySelector(".enter-word").value.split("");
if (inputWord.length <= 8) {
//
var isValid;
for (var i = 0; i < inputWord.length; i++) {
// console.log(inputWord[i]);
if (givenLetters.includes(inputWord[i])) {
var indexPosition = givenLetters.indexOf(inputWord[i]);
givenLetters.splice(indexPosition, 1);
var newWord = inputWord.join("").toLowerCase();
$.get("https://raw.githubusercontent.com/cpog19901/Countdown/master/text/english3.txt", function(contents) {
//contents variable now contains the contents of the textfile as string
//check if file contains the word entered by user
var hasString = contents.includes(newWord);
//outputs true if contained, else false
console.log(hasString);
});
isValid = true;
} else {
console.log(inputWord[i]);
console.log("no");
isValid = false;
}
}
if (isValid == true) {
console.log("This is a valid word");
}
else if (isValid == false) {
console.log("This is NOT a valid word");
}
}
});
}
}
I need all statements to be true including the anonymous function so it will let the user know it's a valid word.

The error message indicates to look out for for-loops. I found this one:
for (var i = 0; i < inputWord.length; i++) {
/* … */
$.get("https://raw.githubusercontent.com/cpog19901/Countdown/master/text/english3.txt", function(contents) {
/* … */
}
/* … */
}
This AJAX call is made every single iteration of the loop (assuming the surrounding if is true).
Instead, you could do it earlier and store the results in a variable.

Related

GridView Validation is not working properly in JavaScript

I want to validate on button click that at least one of the rows must be edited and updated in JavaScript.
So I wrote the below code for validation
function checkGridValidate() {
var StrPriError = "";
var grdCount = GrdProspective1.Rows.length;
for (var i = 0; i < grdCount; i++) {
if (GrdProspective1.Rows[0].Cells[5].Value == "" || GrdProspective1.Rows[0].Cells[7].Value == "") {
StrPriError += "Kindly edit atleast one row \n";
}
if (StrPriError != "") {
alert(StrPriError);
return false;
}
else {
return true;
}
}
}
What happening here is, when I update the first row and submit it is not giving any alert that's perfect, but when I update the second row it still asks me Kindly edit at least one row.
I don't know what's going wrong here.
Have a look the js fiddle for the same
Currently, the validation is limited to only check the top row for two reasons:
.Rows[0] will always inspect the top row, despite the for loop.
This should make use of i as it increments through the collection:
if (GrdProspective1.Rows[i].Cells[5].Value == "" ||
The last if..else, by returning in either case, will interrupt the loop. The return statements here have a similar effect to break statements, with regards to the loop.
So, unless you want the loop to be interrupted, they should be moved out the loop:
for (var i = 0; i < grdCount; i++) {
if (...) {
// ...
}
}
if (StrPriError != "") {
alert(StrPriError);
return false;
}
else {
return true;
}
Though, fixing those should reveal a different issue – the function is checking that every row has been edited rather than one-or-more.
If, for example, there are 5 rows and you fill in both fields in 2 of the rows, the remaining 3 rows will match the condition and append the error message.
Inverting the condition, so you're searching for a row that's filled in and remembering whether you have, should resolve this.
function checkGridValidate() {
// assume invalid until found otherwise
var anyEdited = false;
var grdCount = GrdProspective1.Rows.length;
for (var i = 0; i < grdCount; i++) {
var cells = GrdProspective1.Rows[i].Cells;
// verify that both fields were given a value
if (cells[5].Value !== "" && cells[7].Value !== "") {
anyEdited = true; // remember that you've found an edited row
break; // and, no need to keep looking for more
}
}
// alert only if no rows were filled out
if (!anyEdited) {
alert("Kindly edit at least one row.");
}
return anyEdited;
}

Need Explaination in this word guessing javascript

So, I want to check wether the input that I give is being correctly executed, but why does the if statement always return false even i give the correct input?
I don't want the solution only the need explanation. Please is there anyone who could explain? I've included my html input elements Just in case something wrong with it.
<script>
var text1 = ["O","K","E"];
var text2 = ["_","_","_"];
function guess(j){
for(i=0; i < text1.length; i++){
if(j == text1[i]){
text2[i] = j;
console.log(text2[i])
}
else {
console.log("try again")
}
}
}
</script>
The comment of #Unglückspilz in code:
// extra "K" to show how to handle multiple finds
var text1 = ["O","K","E","K"];
var text2 = ["_","_","_","_"];
function guess(j){
// a flag to set if one or more letters were found
found = false;
// check every letter in the haystack against given needle
for(i=0; i < text1.length; i++){
if(j == text1[i]){
// exchange underbar against found letter(s)
text2[i] = j;
console.log(text2[i]);
// set flag to true
found = true;
}
}
// no letter was correct
if(!found){
console.log("try again");
}
// return boolean if anything was found (but not how many)
return found;
}

How to get the position of a typed letter in a textarea with Javascript?

I am creating a dropdown while typing in a textarea. How can I get the position of the typed letter given a keyup event?
Greg's answer seems to work. But if you want a more simpler way to get it, you can access the selectionStart property of the textarea.
For example
var myTextArea = $("#mytextarea");
myTextArea.keyup(function () {
console.log("The last typed character is at: ", myTextArea.get(0).selectionStart - 1);
});
http://jsfiddle.net/wasjdhtu/
var oldValue = '';
var keyup = function() {
var value = document.getElementById('myTextArea').value;
for(var i=0; i<value.length; i++) {
if(i >= oldValue.length) {
// letter typed at end
oldValue = value;
return; // not really necessary since we should be at the end of the loop anyway
} else if(value.charAt(i) !== oldValue.charAt(i)) {
// letter typed at i
oldValue = value;
return; // no need to keep searching
}
}
// no new letters typed
}

Unwanted return from JavaScript functions with DOM

I am designing a JavaScript function checkForm(), which is meant to check if at least half of the answers of a form have been completed. It returns ”true” if the condition is met and an alert message and ”false” if not. The answers are given in input text fields, whose content mustn't be the empty string in order to be regarded as answered.
In order to make the check, the function checkForm() calls two other functions: totalNumberOfQuestions() and totalCompletedAnswers(), as follows:
function totalNumberOfQuestions() /* Returns the total number of questions in the form */
{ total
numberOfQuestions = 0;
i = 1;
do
{
nameOfAnswer = 'answer_' + i;
if(document.getElementsByName(nameOfAnswer)[0] != null)
{
totalnumberOfQuestions ++;
}
i++;
}
while (document.getElementsByName(nameOfAnswer)[0] != null);
return totalnumberOfQuestions;
}
function totalCompletedAnswers() /* Returns the total number of completed answers in the form */
{
numberOfCompletedAnswers = 0;
i = 1;
for(i = 1; i<= totalNumberOfQuestions(); i++)
{
nameOfAnswer = 'answer_' + i;
if ( form[nameOfAnswer].value != '')
{
numberOfCompletedAnswers ++;
}
}
return numberOfCompletedAnswers;
}
function checkForm()
{
if ( totalCompletedAnswers() < 7 )
{
alert("Please answer at least half of the questions.");
return false;
}
return true;
}
But, surprisingly, the function checkForm() does not work correctly in this form, but returns true even when the number of completed answers is less than a half of the total number of answers. However, the function works properly if the function totalCompletedAnswers() is checked against a constant value, e.g.:
function checkForm()
{
if ( totalCompletedAnswers() < 7 )
{
alert("Please answer at least half of the questions.");
return false;
}
return true;
}
This means that using the function totalNumberOfQuestions() in the body of the checkForm() function is ”importing” some unwanted returned value. This happens even if I call the former separately (x= totalNumberOfQuestions() and then rewriting the condition: if ( totalCompletedAnswers() < x )
). Does anyone know how one can avoid such unwanted returned values when calling a function?
In totalComletedAnswers you have the snippet:
if(numberOfCompletedAnswers < totalNumberOfQuestions() )
{
alert("Please answer at least half of the questions.");
return false;
}
So totalCompletedAnswers will return false if all the answers are not completed not the number of questions answered.
In checkForm the the following will evaluate to true: false < 7
See: http://jsfiddle.net/5mURZ/
Have a look at these two articles for more information on truthiness/falsiness in javascript:
http://11heavens.com/falsy-and-truthy-in-javascript
http://www.sitepoint.com/javascript-truthy-falsy/
UPDATE
Upon closer inspection you have a scoping issue. All your variables have a global scope. This will cause the most issues with the variable i. Declaring the variable with the var key word will restrict the scope of the variable to the function. It is best practice in javascript to delvare all variable with the var keyword to explicitly declare the scope of the variable.
Working Fiddle: http://jsfiddle.net/Dr5Hx/1/
Article on scoping: http://coding.smashingmagazine.com/2009/08/01/what-you-need-to-know-about-javascript-scope/
Update 2
For a completely different approach, try the magic of jQuery. This approach relies on wrapping the answers in some kind of container. In this case a div. This is required as elements such as check boxes and radio buttons would be multiple elements, but each set should only be counted once.
//The selector below finds DOM elements with a name beginning with "answer"
var answers = $("[name^='answer']"); //'Cache' answers
var answerDivs = $("div").has("[name^='answer']"); //'Cache' answer divs
var totalAnswers = answerDivs.length; //'Cache' number of answers
$("#checkIt").click(function(){ //Add a click listener to the button
var numAnswered = $(answerDivs).filter(function(){ //Filter our answer divs to answered question
var answer = $(this).find("[name^='answer']"); //Get the answer element(s) in the div
var textCheck = $(answer).is("input:text") && $(answer).val() != ''; //Check For Text Value
var selCheck = $(answer).is("select") && $(answer).val() != ''; //Check for selected
var radioCheck = $(answer).is(":checked"); // Check for Checked, WOrks for radio & checkbox
//console.log($(answer).attr("name") + " " + textCheck + " " + selCheck + " " + radioCheck)
return (textCheck || selCheck || radioCheck); //End of the filter
}).length;
if(numAnswered < (totalAnswers/2))
{
alert("Please answer atleast half the questions");
return false;
}
alert("We're good to go");
return true;
});
Just make sure to wrap the above in $(document).ready();
http://jsfiddle.net/Dr5Hx/3/

Array.push causes program to have errors

I followed the advice from a previous question to get my promps to add values to an array, but it has caused my program to throw up True values when they are not.
HIGHEST_GRADE = 7;
LOWEST_GRADE = 0;
var course = new Array();
var grade = new Array();
while(confirm("Would you like to add a course?")){
course.push( prompt("Enter the course code. Example - ABC1234") );
};
var upperTest = course.slice(0,3);
var integerTest = course.slice(4,7);
if (course.length !== 7) {
alert ('Invalid Course Code');
}
if (upperTest !== upperTest.toUpperCase()) {
alert ('Invalid Course Code');
}
if (isNaN(integerTest)) {
alert('Invalid Course Code');
}
if (isNaN(grade)) {
alert('Invalid Grade');
}
if (LOWEST_GRADE > grade || HIGHEST_GRADE < grade) {
alert('Invalid Grade');
}
I have it set to make sure the entered text matches the conditions, but since the .push was added the whole thing stuffs up.
I get an Invalid Course Code error, something is playing up with that.
The Array is used to store multiple courses, which is fine. But, since it's an array, you need to access each position of it to validate each individual course, using a loop:
var courses = new Array(); // use the name courses instead, to indicate that it's a collection
for (var i = 0; i < courses.length; i++) {
var course = courses[i];
var upperTest = course.slice(0,3);
var integerTest = course.slice(4,7);
if (course.length !== 7) {
alert ('Invalid Course Code');
}
if (upperTest !== upperTest.toUpperCase()) {
alert ('Invalid Course Code');
}
if (isNaN(integerTest)) {
alert('Invalid Course Code');
}
}
This will validate every course that is in the Array. Otherwise, when you test courses.length, you'll be validating the number of elements in the array, not the number of characters of each course.
The same needs to be done for the grades array.
Do you want to validate entered course code? In such case you need to do it with the item not with the whole array:
while (confirm("...")) {
var courseCode = prompt("...");
var upperTest = course.slice(0,3);
var integerTest = course.slice(4,7);
if (courseCode.length !== 7) {
alert ('Invalid Course Code');
continue;
}
// place your other if's here
courses.push(courseCode);
}

Categories