I'm making a hangman game and I'm writing a function to search for a letter in the word. So when the user clicks on a letter, I am grabbing the text in there and searching for it in the chosen word.
The code I have written is:
function searchLetter()
{
var aLetter = letter.toLowerCase();
var aChosenWord = chosenWord.toLowerCase();
//chosenWord is a global variable initialised in another function
if(aChosenWord.indexOf(aLetter) != -1)
alert("Letter is there")
else
{
alert("Letter not found")
}
}
The variable 'letter' is a global variable and was given a value based on what has been clicked:
$(function(){
$('a').click(function () {
letter = $(this).text();
$(this).slideUp();
searchLetter()
});
});
I'm not sure what I've done wrong here. I put in a bunch of alert boxes and my code seems to be grabbing the letters correctly.
When I run this however, every time I'm getting the value of -1 for indexOf; i.e. the letter is not found in the word.
I cannot figure out what it is I've done wrong here!!
Any input is greatly appreciated,
Thanks
While I am not an advocate for unnecessary global vars, the code below should do what you need.
HTML
<span id="chosenWord">Some awesome word</span>
<br />
a
b
d
e
JS
var letter,
chosenWord = document.getElementById('chosenWord');
$('a').on('click', function () {
if (chosenWord.innerHTML.toLowerCase().indexOf($(this).text().toLowerCase()) !== -1) {
console.log('Found ' + $(this).text())
} else {
console.log($(this).text() + ' not found.');
}
});
JSFiddle demo
It would be better to create a context for your global variables, e.g.:
jQuery(function($) {
var chosenWord;
$('a').click(function() {
var $this = $(this);
$this.slideUp();
searchLetter($this.text(), chosenWord);
});
// link that generates new game?
$('.generate-new-word').function() {
chosenWord = generateNewWord();
});
});
The searchLetter() function receives the letter and word as its arguments and is thus decoupled from this code.
I've also written an example of how the word generation function can be integrated. As with searchLetter() this function has no knowledge of any global state.
This would be the implementation of your searchLetter():
function searchLetter(letter, chosenWord)
{
var aLetter = letter.toLowerCase();
var aChosenWord = chosenWord.toLowerCase();
if(aChosenWord.indexOf(aLetter) != -1) {
alert("Letter is there")
} else {
alert("Letter not found")
}
}
Organizing your code this way reduces the chance of introducing bugs in the code, because the context is managed exclusively inside only a small part of your code.
Did you declare the global variable with? (check the scope):
var letter = ''
Why not prefer passing the variables within the argument list of the searching function?
Related
I can't figure out how to update a global variable for a javascript calculator I am working on. I know using eval would make this a lot easier but from what I read online, eval from user input is not advised.
My idea is store the first number until an operation comes is clicked. Once that is clicked, store second number and then see what operation comes up by the user, where it is '=' or '+/*-' do the appropriate action. I have not completed the CE or AC or '.' buttons yet. There's no point in completely that if I can not update the global variable.
Within the function itself, I can change the variable firstNum and secondNum.
From what I have read online, I believe I am not changing the global variable but the local instance of the variable.
I am hoping to be pointed in the right direction to get this done. I attempted to store in the number in an object and later reference that object when I needed to do an operation but I do not believe I did that quite right since I receiving a Reference Error.
Thank you in advance.
var theParent = document.querySelector("#container");
var display = document.querySelector("#display");
theParent.addEventListener("click", doSomething, false);
var reg = new RegExp('^\\d+$');
var result=0;
var symbol='';
var firstNum=0;
var secondNum=0;
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.innerHTML;
if (reg.test(clickedItem)) {
if (display.innerHTML==="0"){
display.innerHTML=clickedItem;
}
else {
display.innerHTML+=clickedItem;
}
}
}
if (clickedItem==='='){
console.log('check firstNum:' +firstNum);
console.log('check symbol:'+ symbol);
console.log('operations return: '+ operations(symbol));
result= operations(symbol);
console.log('result: '+ result);
display.innerHTML=result;
firstNum=result;
secondNum=0;
symbol='';
}
if (!(reg.test(clickedItem))&&symbol===' '&&clickedItem!=='=')
{
symbol=clickedItem;
display.innerHTML='0';
console.log('first op '+ symbol);
}
if (!(reg.test(clickedItem))&&symbol!==clickedItem&&clickedItem!=='=') {
solve(symbol);
symbol=clickedItem;
console.log('second op '+symbol);
}
if (symbol===''){
//firstNum = parseInt(display.innerHTML);
setFirstNum();
console.log("this firstNum in If: " +firstNum)
}
else if (reg.test(clickedItem)){
setSecondNum();
console.log("this secondNum in If: " +secondNum)
}
else {display.innerHTML='0';}
e.stopPropagation();
}
function setFirstNum(){
window.firstNum=parseInt(display.innerHTML);
}
function setSecondNum(){
window.secondNum=parseInt(display.innerHTML);
}
function operations(symbol){
var operation=[{
'+': firstNum + secondNum ,
'-': firstNum - secondNum ,
'รท': firstNum/secondNum ,
'X': firstNum*secondNum
}];
return operation[symbol];
}
function solve(symbol){
result=operations(symbol);
display.innerHTML=result;
firstNum=result;
secondNum=0;
}
You are referencing the global variables fine, the problem is with the global variable theParent. Most of the times, the browser executes the javascript before it loads the document, and hence cannot find any element with id #container.
In order to fix this, you can declare the global variable, and define it on loading the document.
var theParent;
window.onload = function() {
theParent = document.querySelector("#container");
theParent.addEventListener(...);
}
Similarly for the display variable.
Hope this helps.
I'm working on a text game in javascript right now and have a function to pick up a sword.
var takeSword = function() {
if (currentRoom.hasSword) {
$("<p>You picked up a sword.</p>").properDisplay();
}
else {
$("<p>The sword is not here.</p>").properDisplay();
}
};
My problem is, as long as you're in the same room as the sword, you can pick it up over and over. How can you set the function so that once you pick up the sword you can't pick it up again?
My original thought was setting a variable like var sword = false; and then when the function runs to set sword = true; but that didn't work.
This isn't my entire code, there's an object further up that sets `hasSword = true;' so that the sword can be picked up in the first place and can NOT be picked up in different rooms of the game.
Something like this perhaps?
var GameState = {
worldHasSword: true,
playerHasSword: false,
takeSword: function() {
if( this.worldHasSword ) {
this.worldHasSword = false;
this.playerHasSword = true;
$("<p>You picked up a sword.</p>").properDisplay();
}
else {
$("<p>The sword is not here.</p>").properDisplay();
}
}
}
GameState.takeSword();
The best solution here is not to touch your original function at all, but simply wrap it in a general function that will prevent its being called more than once. This general function can be used anywhere else in your code that you need to "once-ify" something:
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
Now you simply do:
var takeSwordOnce = once(takeSword);
and use takeSwordOnce in your code. Or, you can do:
takeSword = once(takeSword);
Please see this article for further explanation of the once function.
#Kenney got me thinking in the right direction. Here's how I fixed it without totally rewriting the function:
var takeSword = function() {
if (currentRoom.hasSword) {
$("<p>You picked up a sword.</p>").properDisplay();
currentRoom.hasSword = false;
}
else {
$("<p>The sword is not here.</p>").properDisplay();
}
};
The first mistake I made was thinking "hasSword" was the variable by itself. I needed to add the currentRoom to it then it worked fine. I've tested it and also tried it in rooms where the sword does not exist and it seems to be working fine.
Is it possible to access an object inside another if statement? Because the situation is like this.
I have an edit button and it will set a <div> to contenteditable. so if I press the cancel button, the text inside the <div> should also reset. and now my javascript goes like this
$('.class').on('click','.etc',function(){
var orig = {};
$a = $(this).('.etc').text().trim(); // just getting the text of the button
if($a == "Edit") // just checking if edit button
{
orig.text = $(this).find('original-text').text(); // should store the original text
}
else if ($a == "Cancel")
{
// the div must be set to the original text
alert(orig.text); // undefined
}
});
I'm really at lost here
Declare the variable at a scope where it is accessible by both the if and the else condition or maybe at a global scope. But make sure it's initialized before you try to access its properties!
var orig = {text:""};
$('.class').on('click','.etc',function(){
if($a == "Edit") // just checking if edit button
{
orig.text = $(this).find('original-text').text();
}
else if ($a == "Cancel")
{
alert(orig.text);
}
});
The issue is in the scope of the variable orig. JS has function level lexical scope.
So to answer your title question, yes you can access a variable created in an in in if in the else so long as the else is sure to occur after the if has occurred at least once. But that's not really what's causing your problems.
Your issue is that you are trying to persist this variable beyond the onclick function. When that function ends so does the life of the variable. The simple fix is to declare it outside the function and utilize JS closures.
var orig = {};
$('.class').on('click', function () {
if ($(this).text() == "Store") {
orig.text = $("#display").text();
} else if ($(this).text() == "Cancel") {
alert(orig.text);
}
});
I had to adapt it a bit because I don't know your full HTML, but it works.
UPDATE
To avoid the bad practice of global variables you can create a closed scope for the whole thing like so:
(function () {
var orig = {};
$('.class').on('click', function () {
if ($(this).text() == "Store") {
orig.text = $("#display").text();
} else if ($(this).text() == "Cancel") {
alert(orig.text);
}
});
})();
And here's that in practice
So, I have this little code in my js file:
window.onload = function Equal() {
var a = 'b1'
var b = 'box1'
var bookstorname = localStorage.getItem(a)
if (bookstorname == 1) {
document.getElementById(b).setAttribute('checked','checked');
}
if (bookstorname == 0) {
document.getElementById(b).removeAttribute('checked','checked');
}
var a = 'b2'
var b = 'box2'
var bookstorname = localStorage.getItem(a)
if (bookstorname == 1) {
document.getElementById(b).setAttribute('checked','checked');
}
if (bookstorname == 0) {
document.getElementById(b).removeAttribute('checked','checked');
}
}
The function itself is not important (it equals checkboxvalues set in the localstorage), but I execute it 2 times. First time with var a & b set to 'b1' & 'box1'. Then I run the script again (same script), but with var a & b set to 'b2' & 'box2'. Now, this code works, but my question is if there is a shorter way to write this? I can imagine some sort of array with a loop, but I could not get it to work for some reason. The 2 variables are pairs, and I know this might be a dumb question, but I can't find the answer anywhere.
You can use a second function which will accept the local storage key and the checkbox id like
window.onload = function Equal() {
setCheckboxState('box1', 'b1');
setCheckboxState('box2', 'b2');
}
function setCheckboxState(id, key) {
document.getElementById(id).checked = 1 == localStorage.getItem(key);
}
You might separate common logic into another function
window.onload = function Equal() {
function extractFromStorage(a, b) {
var bookstorname = localStorage.getItem(a)
if (bookstorname == 1) {
document.getElementById(b).setAttribute('checked','checked');
}
if (bookstorname == 0) {
document.getElementById(b).removeAttribute('checked','checked');
}
}
extractFromStorage('b1', 'box1');
extractFromStorage('b2', 'box2');
}
function doTheStuff(a, b) {
var bookstorname = localStorage.getItem(a)
if (bookstorname == 1) {
document.getElementById(b).setAttribute('checked','checked');
}
if (bookstorname == 0) {
document.getElementById(b).removeAttribute('checked','checked');
}
}
window.onload = function Equal() {
doTheStuff('b1', 'box1');
doTheStuff('b2', 'box2');
}
?
This is how I would do it.
There are several problems with your code.
You do not check that the element you are stetting an attribute to
exists. You do not check if the localStorage item you get is
defined.
You pollute the global name space with the function name Equal.
That function should not be named with a capital as it is not a Object generator.
There is no need to use setAttribute and removeAttribute, in
fact removeAttribute makes no sense in this case as you can not
remove the checked attribute from the element. BTW why use setAttribute here and not for window.onload?
The checked attribute is either true or false, it does not use the
string "checked"
Binding the load event via the onload attribute is not safe as you may
block 3rd party code, or worse 3rd party code may block you.
There is no error checking. DOM pages are dynamic environments, pages
have adverts and content from many places that can interfer with your
code. Always code with this in mind. Check for possible errors and deal with them in a friendly way for the end user. In this case I used an alert, not friendly for a normal user but for you the coder.
My solution.
// add an event listener rather than replace the event listener
window.addEventListener(
"load", // for the load event
function(){
// the update function that is called for each item;
var update = function(item){
// the right hand side equates to true if the localstorage
// is equal to "1". LocalStorage allways returns a string or
// undefined if the key is not defined.
item.element.checked = localStorage[item.storageName] === "1";
}
// safe element getter
var getElement = function(eId){
var e = document.getElementById(eId); // try and get the element
if(e === null){ // does it exist?
throw "Missing element:"+eId; // no then we can not continue
// the program stops here unless
// you catch the error and deal with
// it gracefully.
}
return e; //ok return the element.
}
// Item creator. This creates a new item.
// sName is the local storage name
// eId id the element ID
var item = function(sName, eId){
return {
storageName: sName, // set the loaclStorage name
element:getElement(eId); // get the element and check its safe
};
}
// make it all safe
try{
// create an array of items.
var items = [
item("b1","box1"),
item("b2","box2")
];
// for each item update the element status
items.forEach(update);
}catch(e){
alert("Could not update page?");
}
}
);
I have a variable declared:
var recent;
And I wrote a function which needs the variable passed into it. However, I believe what is happening is the variable is being passed as a string. The var is represented by thisVar:
function detachVariable(thisDiv, thisVar, fileName) {
//Check if this section is visible:
if($(thisDiv + " li").length > 0) {
$(thisDiv).prepend(thisVar);
} else {
//If variable does not have content stored, store it:
if(thisVar === undefined) {
$("#site-nav li a").parents().removeClass("nav-active");
$(this).addClass("nav-active");
$(thisDiv + " ul.top-level").load('assets/includes/' + thisFile, function () {
$(this).show().siblings().hide();
ajaxAudioController();
});
//If variable has content, show it:
} else {
$("#site-nav li a").parents().removeClass("nav-active");
$(this).addClass("nav-active");
$(thisDiv).prepend(thisVar);
}
}
}
My click function:
$("#site-nav .nav1").on("click", function (event) {
detachVariable("#recent", "recent", "recent.php");
event.preventDefault();
});
Is there a way I can pass my variable into the function?
If I understood correctly.. all you have to do is remove the quotes around recent.. see below,
detachVariable("#recent", recent, "recent.php"); //removed quotes
Just omit the quotes around the second parameter. With them, you are indeed passing a string literal instead of the variable.
Variables in Javascript have a global scope. So you can literally just use recent == whatever instead of trying to pass it as a parameter.