Why isn't this function stopping its parent? - javascript

I'm created a function that stops its parent if a condition is given:
handleUserSubmit () {
this.userForm.options.hasFormSubmitted = true
if (!this.userForm.options.isFormValid) return
},
handleUpdateUser () {
const fields = this.userForm.schema
this.userInput.buildId = this.user.objectId
this.handleUserSubmit()
// rest of code
}
However the rest of the code runs no matter what the condition is. What am I doing wrong?

Move the conditional return to the function from which you need to return from:
handleUserSubmit () {
this.userForm.options.hasFormSubmitted = true
return !this.userForm.options.isFormValid;
},
handleUpdateUser () {
const fields = this.userForm.schema
this.userInput.buildId = this.user.objectId
if(this.handleUserSubmit()) return;
// rest of code
}

Related

Button is self-pushing (JS)

Logout button class, Im creating instance to connect it with API. After the moment instance created it is immediately activated like the button was pushed
Can you help to understand what is wrong?
I'm just beginner
class LogoutButton {
constructor() {
[this.logoutBtn] = document.getElementsByClassName('logout');
this.action = (f) => f;
this.logoutBtn.addEventListener('click', this.logoutClick.bind(this));
}
logoutClick(event) {
event.preventDefault();
this.action();
}
}
instance
"use strict"
let newLogoutButton = new LogoutButton();
const logoutSuccess = (data) => {
if (data.success === true) {
location.reload();
} else {
alert("");
}
};
newLogoutButton.action = ApiConnector.logout(logoutSuccess);
the issue is with the last line
newLogoutButton.action = ApiConnector.logout(logoutSuccess);
change it to
newLogoutButton.action = () => ApiConnector.logout(logoutSuccess);
The last line needs to be a function, right now you're just immediately calling .logout()
newLogoutButton.action = () => ApiConnector.logout(logoutSuccess);

Why won't a boolean object property update?

I have an array of objects. Each object has a method that should update a boolean property in the same object called 'found'.
When I call the function, the property does not update. I am not sure why.
I thought that the 'found' property would be accessible but it isn't??
I have created a minimal version of the problem here:
https://codepen.io/sspboyd/pen/XWYKMrv?editors=0011
const gen_s = function () { // generate and return the object
let found = false;
const change_found = function () {
found = true;
};
const update = function () {
change_found();
};
return {
change_found,
found,
update
};
};
const s_arr = []; // initialize an array
s_arr.push(gen_s()); // add a new s object to the array
console.log(s_arr[0].found); // returns 'false'
s_arr.forEach((s) => {
s.update();
});
console.log(s_arr[0].found);
When your change_found function changes the value of found, it's changing the value pointed to by your let found variable, but the object returned by your gen_s function still points to the old value.
You can fix your code using the 'holder' pattern, like this:
const gen_s = function () { // generate and return the object
let foundHolder = {value: false};
const change_found = function () {
foundHolder.value = true;
};
const update = function () {
change_found();
};
return {
change_found,
foundHolder,
update
};
};
const s_arr = []; // initialize an array
s_arr.push(gen_s()); // add a new s object to the array
console.log(s_arr[0].foundHolder.value); // returns 'false'
s_arr.forEach((s) => {
s.update();
});
console.log(s_arr[0].foundHolder.value);
Or even better, use a class:
class S {
constructor() { this.found = false; }
change_found() { this.found = true; }
update() { this.change_found(); }
}
const s_arr = [];
s_arr.push(new S());
console.log(s_arr[0].found);
s_arr.forEach(s => s.update());
console.log(s_arr[0].found);

When I give the function a name and trigger it from the console it works perfectly, but when I add the window.onload = to it it never starts

This is my code:
window.onload = function ()
{
var user = firebase.auth().currentUser
var login = document.getElementById("NavLogin");
if (user) {
login.innerHTML = "Account";
login.href = "AccountPage/AccountPage.html";
}
else {
login.innerHTML = "Login";
login.href = "AccountPage/LoginPage.html"
}
}
I have tried changing it to the onload of the body, but that didn't help either. I do not understand why it only works if called manually.
From your code I can see that you need to wait until #NavLogin element is loaded. If this element needs to be present in your page to run the rest of the code, then I would suggest you to use a pulling function like bellow:
function waitForElement(selector, cb) {
var tick = setInterval(function () {
var target = document.querySelector(selector);
if (null !== target) {
clearInterval(tick);
cb(target);
}
}, 200);
};
Then you can call the pulling function and pass your target element as the first parameter:
waitForElement("#NavLogin", function(login){
if (user) {
login.innerHTML = "Account";
login.href = "AccountPage/AccountPage.html";
}
else {
login.innerHTML = "Login";
login.href = "AccountPage/LoginPage.html"
}
})
If the target element is found, the callback function will be called and the target element will be passed as parameter to the callback function

Why is this element null?

Clarification:
I'm not interested in using jQuery methods.
Summary
I use a method to only run my modules after the html has finished loading. It looks like this. page_complete is the id of the last element on the page.
$A.finish('page_complete', function () {
// page has finished loading
});
Finish is implemented like this. It is just a timer that checks of the existence of the last element. Once it finds it, it initializes all the modules.
I don't understand why the element is NULL as FF is telling me.
/*finish
** Once an element has been loaded an HTML focus event is fired
** on that ID. It can not be cancelled and bubbles up
**
*/
$A.finish = function (id, callback) {
var htm_finished = document.getElementById(id);
if (htm_finished) {
$A.initAll(); // intilAll will fire the init function of all modules.
$A.makeEvent('focus', htm_finished);
callback();
} else {
setTimeout(function () {
$A.finish(id, callback);
}, 10);
}
};
Error in Firefox
...TypeError: this.E.ready is null # ...
Note I put a comment where the error is.
Module with error
/*MUserAny
**
**
**
*/
$A.module({
Name: 'MUserAny',
S: {
DynSma: SDynSma,
DynTwe: SDynTwe,
DynArc: SDynArc,
AniFlipMediaPane: SAniFlipMediaPane,
AniFlipPage: SAniFlipPage,
ClientStorage: SClientStorage
},
E: {
ready: $A('#page_complete')[0]
},
init: function () {
var pipe = {},
this_hold = this;
this.E.ready.addEventListener("focus", function (event) { // error is here.
pipe = $A.definePipe(this_hold.Name);
$A.machine(pipe);
}, false);
},
pre: function (pipe) {
var h_token = this.S.ClientStorage.get('h_token');
if ((h_token === '0') || (h_token === 'undefined') || (h_token === null)
|| (h_token === undefined)) {
this.S.AniFlipPage.run('sp');
pipe.state = false;
} else {
pipe.server.smalls.h_token = h_token;
pipe.state = true;
}
this.S.AniFlipMediaPane.run('mi_cover');
return pipe;
},
post: function (pipe) {
this.S.DynSma.run(pipe.server.smalls);
this.S.DynArc.run(pipe.server.arcmarks);
this.S.DynTwe.run(pipe.server.tweets);
this.S.AniFlipPage.run(this.S.ClientStorage.get('page'));
return pipe;
},
finish: function (pipe) {
}
});
It looks like
E: {
ready: $A('#page_complete')[0]
}
is being evaluated as part of the object literal, and if this is occuring before the page is complete you get your error.
One quick and dirty solution may be to change E.ready to a function, which will only be called during init, which you know happens after page complete, something like
E: {
ready: function() { return $A('#page_complete')[0]; }
},
init: function () {
var pipe = {},
this_hold = this;
this.E.ready().addEventListener("focus", function (event) { ...

Create anonymous function dynamically?

I'm working on simple evolutionary AI. I need to generate an anonymous function dynamically. For it I have a list of conditions and actions:
var conditions = [
function () { return enemyNear(), },
function () { return mySpeed() > 5; },
function () { return 1 === 1; }];
var actions = [
function () { return alert('walk'); },
function () { return alert('jump'); }
function () { return alert('attack'); } ]
The code chooses one of each to generate a new function:
condition = conditions [Math.floor(Math.random()*conditions .length)];
actions = conditions [Math.floor(Math.random()*actions .length)];
Provided it the chosen condition is enemyNear() and the chosen action is walk(), how can I generate the simple anonymous function?
behavior = function() {
if(enemyNear()) {
walk();
}
}
I can change the way the arrays are saved if needed. How can this be done?
All characters behaviors are called inside a loop like this:
for(i=0,i<chars.length,i++) {
chars[i].behavior.call();
}
The simplest way would be to only put functions inside the arrays:
var conditions = [
enemyNear,
function () { return mySpeed() > 5; },
function () { return 1 === 1;
}];
var actions = [walk, attack, jump];
Then you could define behave as something like:
var behave = function(condition, action) {
if(condition()) {
action();
}
}
And use it like for example:
behave(conditions[2], actions[1]);
Here, 2 and 1 could be a randomly generated number like this:
var getRandomInt = function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var actRandomly = function (conditions, actions) {
behave(
conditions[getRandomInt(0, conditions.length -1)],
actions[getRandomInt(0, actions.length -1)]
);
};
Call it like:
actRandomly(conditions, actions);
Of course this only presents the idea, and is not neatly organized.
For the fun of it, I created a Basic jsFiddle Demo Version.
Note: Always use var when you are defining a variable. Don't pollute the global scope.
First, inside of the arrays you will need to have a reference to the condition and action function. Right now, you are calling them, so they basically are the same as a useless array like:
conditions = [true, false, true];
actions = [undefined, undefined, undefined];
I would correct it to something like this:
var conditions = [enemyNear,
function() { return mySpeed() > 5 },
function(){ return true; }];
var actions = [walk, attack, jump];
And then you can create a function that generates a behavior:
function generateBehavior(){
var condition = conditions[Math.floor(Math.random() * conditions.length)];
var action = actions[Math.floor(Math.random() * actions.length)];
return function() {
if(condition()) {
action();
}
}
}
You can see it in action on this JSFiddle demo.
Change your arrays from this:
conditions = [enemyNear(), mySpeed()>5, 1=1];
To this:
conditions = [
function() { return enemyNear() }, // or just enemyNear
function() { return mySpeed() > 5 },
function() { return 1 == 1 } // 1 = 1?
];
With your current code, your functions are being called and conditions becomes an array of the outputs of those functions.
condition = [
enemyNear,
function() { return mySpeed() > 5; },
function() { return 1 == 1; }
];
You need to store your functions in the array, not call them, otherwise you are storing the result of the functions in the array.
function enemyNear() {}
function walk() {}
conditions = [enemyNear]
actions = [walk]
behaviour = function() {
if(conditions[randomNumber]()) {
actions[randomNumber]();
}
}
Simple. Use eval()
var behavior;
eval("behavior = function() { if (enemyNear()) walk(); }");
behavior();

Categories