I'm having some trouble with booleans and scope. I have set a global boolean to false, upon a function the boolean turns true. if the boolean is true I want another function to run. However the boolean is only changed in the scope of the function that makes it true and is still false globally. Thus the following function which needs the boolean to be true is not running.
The first part of my code looks something like this:
let threePick= false;
let twoPick = false;
let onePick = false;
let found = false;
var startGame = false;
function selector() {
$("#threebut").click(function () {
if (found === false) {
found = true;
onePick = true;
twoPick = true;
var input = this;
input.disabled = true;
}
})
$("#onebut").click(function () {
if (found === false) {
found = true;
threePick = true;
twoPick = true;
var input = this;
input.disabled = true;
}
})
$("#twobut").click(function () {
if (found === false) {
found = true;
threePick = true;
onePick=true;
var input = this;
input.disabled = true;
};
});
};
selector();
function enemy() {
$("#twobut").click(function () {
if (twoPick === true){
var input = this;
input.disabled = true;
startGame = true;
}
});
$("#threebut").click(function() {
if (threePick === true){
input.disabled = true;
startGame = true;
}
});
$("#twobut").click(function() {
if (twoPick === true){
var input = this;
input.disabled = true;
startGame = true;
}
});
}
enemy();
Notice that the enemy(); changes the startGame boolean to true
Now in the next part of my code:
function gameStart(){
if (startGame === true){
var button = $('<button/>', {
text: 'Attack'
})
$('#atkButton').append(button);
}
}
gameStart();
I want the function to run when the boolean is true but the boolean only changes locally. I know that accessing local variables is not possible but is there any way around this or an alternative I could use?
P.S I apologise for my inefficient code I've only been doing javascript for a few days.
Any help is appreciated!
gameStart() is called immediately after it is defined and only once. At this time the value of startGame is false.
enemy() sets up eventlisteners for clicks on buttons #threebut and #twobut. Only when one of these buttons is clicked is the value of startGame set to true. If gameStart() is called thereafter it will see that startGame is true.
Your two functions selector and enemy define event handlers for the click action on elements in your HTML. Unless you click on those elements these event handlers, and attached functions, are not called.
Your id=twobut element has three different event handlers attached which will all fire when that element is clicked.
Normally in jQuery you use $(document).ready(function() { ... }); in which you can call selector(); and enemy(); so this run when the DOM is properly loaded and the event handlers can be attached successfully.
Maybe add the HTML from your page to create a working example?
Related
What would be the right approach to use a single DOMContentLoaded call on multiple functions as shown below:
Here is what I have:
function rtd3Transaction() {
if (rtd3tchanged.checked || rtd3dchanged.checked) {
formWrapperCertainSelection.style.display = '';
formWrapperConfirm.required = true;
} else {
formWrapperCertainSelection.style.display = 'none'
formWrapperConfirm.required = false;
}
}
rtd3tchanged.addEventListener('change', rtd3Transaction);
document.addEventListener('DOMContentLoaded', rtd3Transaction);
rtd3Transaction();
function rtd3Device() {
if (rtd3tchanged.checked || rtd3dchanged.checked) {
formWrapperCertainSelection.style.display = '';
formWrapperConfirm.required = true;
} else {
formWrapperCertainSelection.style.display = 'none'
formWrapperConfirm.required = false;
}
}
rtd3dchanged.addEventListener('change', rtd3Device);
document.addEventListener('DOMContentLoaded', rtd3Device);
rtd3Device();
It's fine to do it the way you have it now. You can attach multiple handlers to the event, they'll all get called.
If you want to change it, though, you can do it the same way you do any other time you want to do multiple things at once from a single place: you put the operations in a function, and arrange for that function to be called:
document.addEventListener('DOMContentLoaded', function() {
rtd3Transaction();
rtd3Device();
});
I prefer to create an array that I can push new initialization routines onto wherever they're defined, then initialize each once the content-load event fires.
const initRoutines = []
function example1() {}
initRoutines.push(example1)
function example2() {}
initRoutines.push(example2)
document.addEventListener("DOMContentLoaded", () => {
initRoutines.forEach(routine => routine())
})
I need to use the value of a boolean variable to trigger an action, and I will use this in several occasions, then is very important I do in the best way.
I already search and found a way to use object.watch, like this:
let test1 = {on: false};
teste1.watch('on', function (prop, oldval, newval) {
if (teste1.on === true) {
$('#bot').toggleClass('switch-bck');
} else {
$('#bot').toggleClass('switch');
}
return newval;
});
interact('#bot2')
.on('down', function (event) {
event.currentTarget.classList.toggle('switch');
event.preventDefault();
if (teste1.on) {
teste1.on = false;
} else {
teste1.on = true;
}
document.getElementById('demo').innerHTML = teste1.on;
})
.on('up', function (event) {
event.currentTarget.classList.toggle('switch');
event.preventDefault();
document.getElementById('demo').innerHTML = teste1.on;
});
document.getElementById('demo').innerHTML = teste1.on;
This almost works.
When I change the state of teste1.on the first 2 times works well. But after this take the double of changes of teste1.on for the
$('#bot').toggleClass('switch-bck');
be activated. But I see that teste1.on change correctly because I see its value with
document.getElementById('demo').innerHTML = teste1.on;
If I change return newval to return oldval or even remove it, the change that I want happens perfectly, but the value that I se with
document.getElementById('demo').innerHTML = teste1.on;
remain freeze or show "undefined".
Any help? Or even a way to do this without using .watch?
I cant seem to get this function to return true even after ticking the two check boxes I have on the page. I've been working on this for hours now and running out of ideas. Any help would be much appreciated.
if(myfunction() == true){
alert('YAY!');
}
function myfunction(){
if($("input[type=checkbox]").length > 0){
$('.checkbox').each(function(){
if($(this).prop('checked')){
return true;
}
else{
$(this).find(".CheckboxCheck").show();
return false;
}
});
}
else{
return true;
}
}
You are returning true from within the function that you passed to each, not from myfunction. Except in the case that there are no check boxes on your page, and thus the else block executes in myfunction, myfunction is returning undefined.
You can do something like this however:
if(myfunction() == true){
alert('YAY!');
}
function myfunction(){
var returnValue = true;
if($("input[type=checkbox]").length > 0) {
$('.checkbox').each(function(){
if($(this).prop('checked')){
returnValue = true;
return false; // Stops the each loop.
}
else {
$(this).find(".CheckboxCheck").show();
returnValue = false;
return false; // Stops the each loop.
}
});
}
return returnValue;
}
Now, I'm not exactly sure of what you're trying to do, and you will almost certainly need to tweak the code above. I'm just providing it as a way to illustrate how to get a value out of the function passed to each. If you're trying to determine if all of the checkboxes are checked, for example, then you'll want your each function to look something like this:
var returnValue = true;
...
$('.checkbox').each(function() {
if (!$(this).prop('checked')) {
returnValue = false;
return false;
}
});
EDIT: After looking at the second code snippet again, I realized that the each loop is unnecessary. If you want to determine if all check boxes are checked, all you need is this:
if ($('.checkbox:not(:checked)').length == 0) {
// All .checkbox elements are checked.
}
Now, keep in mind that the :not() and :checked selectors can't utilize the native JS functions, so they are slower, but probably not enough to matter. I prefer the conciseness.
Returning from inside the each callback function will not return from the outer function. The function will return undefined as you haven't specified any return value for it, and that is not equal to true.
You can use a variable for the result, that you set from within the loop:
function myfunction(){
var result = true;
$('.checkbox').each(function(){
if(!$(this).prop('checked')){
result = false;
$(this).find(".CheckboxCheck").show();
return false; // exit the loop
}
});
return result;
}
Updated jsFiddle: http://jsfiddle.net/leongaban/NmH97/
Inside my main function is a button state modifier function and several click functions.
Having a bit of trouble updating the boolean values in the parent function. I could solve this by using global variables, but I know I shouldn't need to do that here.
In the function below, when #toggle_company is clicked I pass the bool company (which is set to true by default) into the setupToggleButtons function. The current state is then switched, but the original company bool value is unchanged, how would you write this to target and update the variable company in the parent function wireSearchIcons?
var wireSearchIcons = function() {
// Boolean Flags
var company = true;
var phone = true;
var orange_on = '#F37B21'; var orange_off = '#f3cdb1';
var green_on = '#3DB54A'; var green_off = '#d8e0c3';
// Other code...
$("#toggle_company").unbind('click').bind('click', function () {
setupToggleButtons(company, '#toggle_company path', orange_on, orange_off);
});
function setupToggleButtons(bool, path, on, off) {
var path = $(path);
if (bool) {
path.css('fill', off);
bool = false;
return bool;
} else {
path.css('fill', on);
bool = true;
return bool;
}
console.log(bool);
}
}
When you use the variable in the function call, you will be sending the value that the variable contains, not the variable itself. Changing the parameter has no effect on the variable where the value came from.
Javascript doesn't support sending parameter by reference, so just return the value from the function, and assign it back to the variable:
$("#toggle_company").unbind('click').bind('click', function () {
company = setupToggleButtons(company, '#toggle_company path', orange_on, orange_off);
});
function setupToggleButtons(bool, path, on, off) {
var path = $(path);
if (bool) {
path.css('fill', off);
bool = false;
} else {
path.css('fill', on);
bool = true;
}
return bool;
}
It doesn't make sense to write a setupToggleButtons function that does so little. You should inline the code into the click handlers, or create the click handlers within the setup function.
var wireSearchIcons = function() {
// Flags
var company = true;
var phone = true;
var orange_on = '#F37B21'; var orange_off = '#f3cdb1';
var green_on = '#3DB54A'; var green_off = '#d8e0c3';
// Toggle Button States
$("#toggle_company").unbind('click').bind('click', function () {
company = !company;
$('#div_company').css('background', company ? orange_on : orange_off);
});
$("#toggle_phone").unbind('click').bind('click', function () {
phone = !phone;
$('#div_phone').css('background', phone ? green_on : green_off);
});
}
wireSearchIcons();
I want to make custom confirm function.
so, I make a code like :
function confirm(msg){
var obj = document.createElement("div");
var body = document.createElement("div");
body.innerHTML = msg;
var foot = document.createElement("div");
var ok = document.createElement("div");
ok.innerHTML = "OK";
var cancel = document.createElement("div");
cancel.innerHTML = "Cancel";
foot.appendChild(ok);
foot.appendChild(cancel);
obj.appendChild(body);
obj.appendChild(foot);
document.getElementsByTagName("body")[0].appendChild(obj);
ok.onclick = function(){
return true;
}
cancel.onclick = function(){
return false;
}
}
or
returnValue = -1;
ok.onclick = function(){
returnValue = true;
}
canacel.onclick = function(){
returnValue = false;
}
while(true){
if(returnValue !== -1) break;
}
return returnValue;
If this custom confirm function must get 1 parameter like original confirm function.
How can make the custom confirm function?
Personally, I would use a third-party dialog already written for this, write a jQuery plugin, or at least take a more object-oriented approach. As it stands, you are putting a confirm function in the global namespace (where a confirm function already exists).
Also note that you can't halt execution of the page and wait for a response like window.confirm can. See: How can I reproduce the "wait" functionality provided by JavaScript's confirm() function? (where the accepted answer is "you can't").
The available way of performing such a task is to use a callback:
function customConfirm(message, resultCallback){
ok.onclick = function(){
// note that you can pass whatever you want to the callback
// you are not limited to one parameter.
resultCallback(true);
}
cancel.onclick = function(){
resultCallback(false);
}
}
In the above example, resultCallback is a function defined to perform an action(s) in response to events in your confirmation box.
You could pass an object with both the message and the callback to achieve the single parameter goal, but I suspect the real goal is to replace window.confirm which (as stated) behaves differently.
{ message: "foo", callback: function bar(status){ alert(status); } }
You can't have your confirm function halt until a value is found, otherwise the whole page would freeze. What you need in this case is to provide a callback to execute once either of the buttons is clicked (if you can not pass it as argument for any reason, you'd have to use a global var, or maybe a queue):
var queue = [];
function confirm(msg){
...
var callback = queue.shift();
ok.onclick = function(){
callback(true);
}
cancel.onclick = function(){
callback(false);
}
}
You use it this way:
queue.push(function(returnValue) {
if ( returnValue ) {
// Code for "yes"
}
else {
// Code for "no"
}
});
confirm("Are you sure?");
like my case i used promise to solve the delete confirmation problem, here is the code
function deleteBook(id, elm) {
const container_alert = document.querySelector('.container-alert')
alertMsg('Anda yakin ingin menghapus?').then(() => {
// console.log('i love you');
let index = books.findIndex(book => book.id == id);
books.splice(index, 1)
updateDataToStorage();
elm.parentNode.parentNode.remove()
container_alert.classList.add('hidden')
}).catch(() => {
container_alert.classList.add('hidden')
})
}
and my alert function code is as follows
function alertMsg(msg) {
const container_alert = document.querySelector('.container-alert')
const btn_yes = document.querySelector('.action-alert .yes')
const btn_cancel = document.querySelector('.action-alert .cancel')
container_alert.classList.remove('hidden')
return new Promise((resolve, reject) => {
btn_yes.addEventListener('click', function(){
resolve()
})
btn_cancel.addEventListener('click', function(){
reject()
})
})
}