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
Related
I have something like the following:
$('#country1').change(function() {
var hrc = "Yes";
if (className == "HR") {
var hrc = "Yes";
return true;
} else {
var hrc = "No";
return false;
}
Then I am pulling this with JSON into a SP List like:
$('.submitdataAccounts').on('click', function() {
var data = {
__metadata: {
'type': 'SP.Data.ChangeOfAddressListListItem'
},
"high_risk_country": hrc,
};
This part works correctly as everything else in the form posts successfully into the list
If I leave it as a static variable at the top of the page it passes correctly but does not work if it's based on the fuction.
Thanks,
Declare the variable outside the functions, so it is a global variable, and then you can acces it everywhere in your code. If you give a global variable an another value, it is redefined and gets that value until an another value change.
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.
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'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?
The code looks fine to me which is why I'm confused with the G_SResult variable losing scope. It's declared globally above the ready function but that isn't visible in the screenshot. In the screenshot you will see 4 highlighted alert expressions. The one with the red dot is where it returns undefined. The other alerts return the right value.
Screenshot of the code.----> http://i.imgur.com/nNIBk.png
function Savedat(){
var Surveyz=new Survey();
Surveyz.Name=j$('#survey_name').val();
var SResult;
var QuestionOrder=1;
var id;
//alert(G_SResult+'----first');
//alert(typeof G_SResult === 'undefined');
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.SV_CreateSurvey.insertSurvey}'
,Surveyz
,function(Survey_result, event){
console.log(Survey_result);
SResult=Survey_result;
j$('[name="p_Q"]').each(function(){
elId=this.id;
var elNum=elId.substring(1);
QType=j$('input[name=ctrlSel'+elNum+']:checked').val();
Quest=new Question();
Quest.Question__c=j$(this).val();
Quest.Question_Input_Type__c=QType;
SResult=Survey_result;
G_SResult=SResult;
alert(G_SResult+'---1');
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.SV_CreateSurvey.insertQuestion}'
,Quest
,function(Question_result, event){
console.log(Question_result);
var SQLink=new SurveyQL();
SQLink.SG_Survey__c=SResult;
SQLink.Survey_Question__c=Question_result;
SQLink.QOrder__c=(QuestionOrder);
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.SV_CreateSurvey.insertSurveyLink}'
,SQLink
,function(SurveyLink_result, event){
console.log(SurveyLink_result);
});
j$('[name="A'+elNum+'"]').each(function(){
SA=new SurveyAnswer();
SA.Answer__c=j$(this).val();
SA.Survey_Question__c=Question_result;
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.SV_CreateSurvey.insertAnswer}'
,SA
,function(Answer_result, event){
console.log(Answer_result);
});
});
QuestionOrder++;
});
alert(G_SResult+'----2');
});
alert(G_SResult+'----3');
});
setTimeout(function(){Work();}, 1000);
}
In case anyone ever comes across this for whatever reason, the solution was this...
(Both code blocks have been edited as a working example)
function Work()
{
//Semaphore like
if (typeof G_SResult === 'undefined')//(G_SResult == undefined)
{
//run stuff here
setTimeout(function(){Work();}, 1000);
}
else
{
alert(G_SResult+'----5');
//G_SResult = null;
}
}
Looks like Visualforce.remoting.Manager method is Asynchronous.
The variable exists in another scope. It is declared in the anonymous function
function Savedat(){
// [ Code .. ]
j$('[name="p+Q]').each(
function(){
// [ Code.. ]
G_SResult = 999;
// G_SResult didnt exist and is therefore declared locally.
// It implies "var G_SResult = 999"
}
);
// G_SResult undefined here.. because it is outside the scope where it was defined.
}
And doesnt exist in the Savedat(){} function