I've defined some functions, and I want to get user input to invoke those functions. I have the following code, but can't figure out how to invoke the actual function when I'm using a variable. I assumed below code would work..
thanks!
var someFunctions = {
play: function() {
if (player.stopped()) {
player.play();
} else {
return false;
}
}
var getCommand = function(){
var command = prompt("Please enter a command");
if (!(command in someFunctions)) {
alert('command not recognized');
getCommand();
} else {
command();
}
}
getCommand();
var someFunctions = {
play: function() {
if (player.stopped()) {
player.play();
}
else {
return false;
}
}
};
var getCommand = function(){
var commandInput = prompt("Please enter a command");
var command = someFunctions[commandInput];
if (!command) {
alert('command not recognized');
getCommand();
}
else {
command();
}
};
getCommand();
The reason your code isn't working is because you're missing the closing } of someFunctions.
var someFunctions = {
play: function() {
if (player.stopped()) {
player.play();
} else {
return false;
}
}
} // here
Your call is fine, you call a "variable" function the same way you do a regular one. The only difference between a "variable" function and an ordinary one is you can call the ordinary one before it's declared (if you're in the same scope at least)
Related
I want to validate some fields passing a different pattern to a validation function.
send.addEventListener("click", function (event) {
let pattern = /^[A-Za-zÁ-Úá-ú\s]{3,15}$/;
let nameIsVal = regexValidator(pattern);
if (nameIsVal) {
return true;
} else {
event.preventDefault();
return false;
}
});
function regexValidator(pattern) {
if (!pattern.test(this.value)) {
return false;
} else {
return true;
}
}
I am assuming that you are in a class. Make sure that the this keyword points to the correct instance in your event handler, either with the .bind() keyword or with an arrow function.
I would register the handler like this:
send.addEventListener('click', (event) => this.checkRegex(event));
Or if your environment doesn't support arrow functions, this should work as well:
send.addEventListener('click', this.checkRegex.bind(this, event));
Then I would add the methods to the class like this:
checkRegex(event) {
let pattern = /^[A-Za-zÁ-Úá-ú\s]{3,15}$/;
let nameIsVal = this.regexValidator(pattern);
if (nameIsVal) {
return true;
} else {
event.preventDefault();
return false;
}
}
regexValidator(pattern) {
if (!pattern.test(this.value)) {
return false;
} else {
return true;
}
}
I have a problem in regards to using .execute in Nightwatch.
When I run this code in the DOM, it works perfectly. However when I wrap it in an execute command in Nightwatch, it does not even make it to the first click. So probably the execute command is never being executed.
What am I doing wrong?
Thanks in advance
LoopThroughQuestions: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium);
this.api.execute(function() {
var checkQuestion = function() {
var nextButton = document.querySelector('.next-button');
var answers = document.querySelectorAll('.flex-row.key');
answers[0].click();
nextButton.click();
setTimeout(function () {
if (document.querySelector('.next-button')) {
checkQuestion();
} else {
console.log("Exit");
}
}, 2000, "Running")
}
}, []) ;
return this;
},
You have defined the variable checkQuestion as a function, but you never call that function.
Try something like this:
LoopThroughQuestions: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium);
this.api.execute(function() {
var checkQuestion = function() {
var nextButton = document.querySelector('.next-button');
var answers = document.querySelectorAll('.flex-row.key');
answers[0].click();
nextButton.click();
setTimeout(function () {
if (document.querySelector('.next-button')) {
checkQuestion();
} else {
console.log("Exit");
}
}, 2000, "Running")
checkQuestion();
}
}, []) ;
return this;
},
Recall that you can use a self invoking, anonymous function, too.
(function () {
// body of the function
}());
For people who experience the same problem; I fixed it with executeAsync, the script was being executed but the waiting on an element was insufficient
TestLoop: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium);
this.api.executeAsync(function() {
let checkQuestion = function() {
let nextButton = document.querySelectorAll('.next-button');
let answers = document.getElementsByClassName('flex-row');
let blueButton = document.querySelectorAll('.blue-inverse-button').length;
answers[0].click();
nextButton[0].click();
setTimeout(() => {
if (document.querySelectorAll('.next-button')) {
console.log('Answering another question!');
checkQuestion();
}
if (blueButton === 1){
blueButton[0].click()
checkQuestion()
}
else {
console.log("Exiting?");
}
}, 2000);
};
// Initiating the check question function
return checkQuestion();
},[], function(){
console.log('Done?')
});
},
So basically i need to check if the est_wont_show was made/fulfilled/executed.
function est_wont_show() {
var HideThis, estpgt_id;
estpgt_id = $(this).attr("estpgt_id");
//Saving in DOM
HideThis = $("#estpgt_" + estpgt_id).detach();
HideThis = $("#estpt_tr_for_" + estpgt_id).detach();
if (document.body.getElementsByTagName(HideThis)) {
//Check if element is detached
alert("Element is in DOM");
}
}
Something in this way(this function is tied up to button)
function TEST_ALERT() {
if () {
//check if function was made
alert('hello');
} else {
alert('NO-2');
}
}
He should check because in the end there will be 2 things. Like if the elements ARE in DOM, then he will delete them, if they are not, then he will bring them back.
You can use a global scoped variable to know if it has been executed.
// We can use a flag to see if the function got executed
let est_wont_show_execution_flag = false;
function est_wont_show() {
// Do something ...
est_wont_show_execution_flag = true;
}
function TEST_ALERT() {
// Did est_wont_show has been executed ?
if (est_wont_show_execution_flag) {
console.log('TEST_ALERT : est_wont_show has been executed');
return;
}
console.log('TEST_ALERT : est_wont_show hasn\'t been executed');
}
TEST_ALERT();
est_wont_show();
TEST_ALERT();
You can use typeof operator to see if any function is available by the given name
function TEST_ALERT() {
if (typeof est_wont_show === "function") {
//check if function was made
alert('hello');
} else {
alert('NO-2');
}
}
If the function is not created typeof est_wont_show will be "undefined"
Working on my framework again. Wanted to create a method to blink an element. I would need to set interval inside the method. So I thought this might work:
var optionalSelector = "$";
(function() {
(this[arguments[0]] = function constructor(input) {
if (!(this instanceof constructor)) { return new constructor(input); }
this.elm = document.getElementById(input);
}).prototype = {
blink: function() {
function changeDisplay() {
if (this.elm.style.display != "none") {
this.elm.style.display = "none";
} else {
this.elm.style.display = "block";
}
}
setInterval(changeDisplay, 1000);
},
};
})(optionalSelector);
And calling the method $("anElmId").blink();
But it doesn't. Another function inside the method and there's also an interval. I guess this two messes things up. Like it doesn't recognize this.elm. Since I'm a newbie I couldn't figure out a way to fix this. Any ideas?
Fiddle
You should try some console.log statements in your code. When in Chrome or in Firefox (preferably with firebug plugin installed) you can press F12 to open the console and check out the output of your logs.
console.log(this)
In changeDisplay would reveal that this most likely is Window. To understand why you have to understand what this stands for in JavaScript. I like to call it the function invoking
object as that most accurately describes it (in my opinion). See here for more details.
var optionalSelector = "$";
window[optionalSelector] = function constructor(input) {
if (!(this instanceof constructor)) {
return new constructor(input);
}
this.elm = document.getElementById(input);
this.intervalid = 0;
this.timeoutid = 0;
};
window[optionalSelector].prototype.blink =
function(interval, timeout) {
this.intervalid = setInterval(this._callbacks.
changeDisplay(this.elm), interval);
this.timeoutid=setTimeout(this._callbacks.
cancelInterval(this.intervalid),timeout);
return this;
};
window[optionalSelector].prototype.cancel = function() {
clearTimeout(this.timeoutid);
clearInterval(this.intervalid);
return this;
};
// I like to have callback functions (closures) in it's own
// scope so you can better control what variables
// are passed to it
window[optionalSelector].prototype._callbacks = {
changeDisplay: function(elm) {
return function() {
if (elm.style.display !== "none") {
elm.style.display = "none";
} else {
elm.style.display = "block";
}
};
},
cancelInterval:function(intervalid){
return function(){
clearInterval(intervalid);
};
}
};
var myBlinker = window[optionalSelector]
("hplogo").blink(200, 2000);
//cancel it
myBlinker.cancel();
//blink something else for 2 seconds
window[optionalSelector]("gbqfba").blink(200, 2000);
Went to google.com pressed F12 and ran the above code. It should work. More on the difference between prototype properties and instance properties here.
I have such code:
function allValid() {
$('input').each(function(index) {
if(something) {
return false;
}
});
return true;
}
which always returns true as return false; affects anonymous inner function. Is there an easy way to call outer function's return?
PS. I am not looking for a workaround, just want to know the answer to original question. If the answer is "not possible" it is fine.
Yeah, store it in a local variable.
function allValid() {
var allGood = true;
$('input').each(function (index) {
if (something) {
allGood = false;
}
});
return allGood;
}
You could also use Array.prototype.some which iterates until finding an element that matches the criteria.
function allValid() {
var inputs = $('input');
if(inputs.toArray().some(function(input){
if(something)
return true;
})) {
return false;
} else {
return true;
}
}
You can also do this with filter:
var anyInvalid = $('input').filter(function(index) {
if (inValidCheck)
return true;
}).length;
This works because 0 is treated as false, but it actually gives you the number of invalid, which you could use this to display "You have 3 invalid entries" or something if you wanted.
If you want to do this efficiently, I think this is the best way:
function allValid() {
elements = $('input')
for (i = 0; i < elements.length; i++) { invalidityCheck(elements[i]) && return false; }
return true;
}
Edit: Although a more JavaScript-y version would probably use exceptions:
function allValid() {
try
$('input').each(function(index)) {
if (something) { throw 'something happened!'; }
});
catch (e) {
if (e == 'something happened!') {
return false;
} else {
throw e;
}
}
return true;
}