Scoping Issue with React when calling a function inside a function - javascript

I am having some difficulty in getting scope maintained when calling a function within a function when using React, I have created an onChange function, that calls another function called buildBookingQuery
handlePerPageChange = (data) => {
const elementsIndex = this.state.filters.findIndex(element => element.id == 1)
let newArray = [...this.state.filters]
newArray[elementsIndex] = {...newArray[elementsIndex], perPage: parseInt(data.target.value)}
this.setState({
filters: newArray
})
console.log(this.state.filters[0])
console.log(newArray)
let query = this.buildBookingQuery() => This is the problem function
console.log(query)
}
my buildBookingQuery Function
buildBookingQuery (){
let page = 1
let orderby = this.state.filters[0].orderby.split(" ")
let from = this.state.filters[0].fromDate
let to = this.state.filters[0].toDate
let reservedFrom = this.state.filters[0].reservedFromDate
let reservedTo = this.state.filters[0].reservedToDate
console.log("Build Booking Query:", from) => getting undefined
// rest of code removed for sake of brevity
return someValue
}
from researching I have added the bind event to the constructor
this.buildBookingQuery = this.buildBookingQuery.bind(this);
but to no avail.
your help is appreciated

change your buildBookingQuery function to arrow function and also remove binding also.

my issue was myself this line of code:
this.state.filters[0].fromDate
should have been:
this.state.filters[0].startDate
thank for all your help, long day and tired eyes!

Related

Javascript New Function - Best way to pass large number of functions as parameter

In angular project and learning to build a feature to run a custom script using the new function method. With the great help from this forum I have been able to come up with core script solution.
The question I have if I have a large number of custom functions I need to pass into New Function to access what would be the best method?
So far I have 2 options:
Option 1.
Passing each function as parameter. My concern if there is 50 plus function this could look messy.
eg
const userFunction = new Function('testFunc1','testFunc2','testFunc3'...'testFunc50', script);
Option 2.
Nest the functions in parent function. The draw back is to access the function we need to call the parent function which again can look messy in the code writing. Eg
parentFunc().nestFunc().
Question is there a better way to do this?
Code and stackblitz below.
https://stackblitz.com/edit/angular-bx5kia?file=src/main.ts
option1() {
var nestFunc1 = () => {
alert('Nest1');
};
var nestFunc2 = () => {
alert('Nest2');
};
const script = `
var value = 1 +4;\n
console.log('value',value);\n
nestFunc1();\n
console.log("End Script");\n
`;
const userFunction = new Function('nestFunc1', 'nestFunc2', script);
userFunction(nestFunc1, nestFunc2);
}
option2() {
const script = `
var value = 1 +4;\n
console.log('value',value);\n
parentFunc().nestFunc2();\n
console.log("End Script");\n
`;
var parentFunc = (msg?: string) => {
console.log('Test Function', msg);
var nestFunc1 = () => {
alert('Nest 1');
};
var nestFunc2 = () => {
alert('Nest 2');
};
return { nestFunc1, nestFunc2 };
};
const userFunction = new Function('parentFunc', script);
userFunction(parentFunc);
}
Well, I'm not an expert with Angular but as we are working with JS maybe I can give you some light in plain JS and then you can convert it to Angular syntax.
In JS you can write functions inside an array:
const functions = [
() => console.log( 'Nest 1' ),
() => console.log( 'Nest 2' )
]
And then, in your userFunction you can make a loop inside this array calling all functions:
const userFunction = ( functionsArray ) => {
functionsArray.forEach( nestedFunction => nestedFunction() )
}
Hope I can give you any idea :)

Access data from inside a function in the global scope

I'm still learning JS and I'm currently struggling with this problem. I want to be able to access the data from ordArray in the global scope. How do I do this ? I've tried with returns but struggling to solve it.
const startOrd = function() {
const ordArray = [];
val = document.getElementById("val_ord").value;
ordArray.push(val)
console.log(ordArray)
}
Simply create ordArray outside of the function :)
const ordArray = [];
const startOrd = function () {
val = document.getElementById("val_ord").value;
ordArray.push(val)
console.log(ordArray)
}
Declare/initialize the array outside of the function.
const ordArray = [];
const startOrd = function() {
val = document.getElementById("val_ord").value;
ordArray.push(val)
console.log(ordArray)
}
Your code looks correct, Only thing you want is I've tried with returns but struggling to solve it
Demo :
const startOrd = function() {
const ordArray = [];
const val = document.getElementById("val_ord").value;
ordArray.push(val)
return ordArray;
};
console.log(startOrd());
<input type="text" id="val_ord" value="abcd"/>
Constants are block-scoped, when you create variable in function you dont access to variable out side the function.
please follow the link
I think, This writing code method is more better:
var ordArray = [];
let startOrd = (elem) => elem?.value;
let targetElem = document.getElementById("val_ord");
ordArray.push(startOrd(targetElem));

How to get current name of route(such as 'this' value)in Vuejs?

I am a newbie of vueJS
and I would like to use the following template to start my project and I would like to convert it work with IE11
Link : codepen erickarbe/pen/pLbRqQ
The original code is:
computed: {
filteredMembers() {
return this.members.filter(member => {
let first = member.First.toLowerCase()
let last = member.Last.toLowerCase()
let fresult = first.includes(this.searchQuery.toLowerCase())
let lresult = last.includes(this.searchQuery.toLowerCase())
if(fresult)
return fresult
if(lresult)
return lresult
})
},
In order to work with IE11 and I try to use polyfill and convert the code to
computed: {
filteredMembers: function(){
return this.members.filter(function(member){
let first = member.First.toLowerCase()
let last = member.Last.toLowerCase()
//Error for 'this'
let fresult = first.includes(this.searchQuery.toLowerCase()) //'this' Error
let lresult = last.includes(this.searchQuery.toLowerCase()) //'this' Error
//Error for 'this'
if(fresult)
return fresult
if(lresult)
return lresult
})
},}
I have Error When I using 'this' on this.searchQuery.toLowerCase())
but I can solve it using 'var ths = this' like
computed: {
filteredMembers: function(){
var ths = this;
........
let fresult = first.includes(ths.searchQuery.toLowerCase())
let lresult = last.includes(ths.searchQuery.toLowerCase())
Is it very hardecode or stupid way to get 'this' value???
Is there any best way to get current 'this' value,Thank you very much
Please read about how the this keyword works in JavaScript.
You just need to bind the original this to the new function:
return this.members.filter((function (member) {
// ...
}).bind(this))
The extra () around the function may not be necessary, but I wasn't sure if IE11 would work without it.

I can't nake Reset Button

I need to make reset button which makes Resetting Scores. Can anyone help me?
I tried all my best but I don't know how to make it.
https://github.com/SandroGamrekelashvili/New-folder
const game = () => {
let pScore = 0;
let cScore = 0;
});
const startGame = () => {
const playBtn = document.querySelector(".intro button");
const introScreen = document.querySelector(".intro");
const match = document.querySelector(".match");
There were a few things you needed to get done to make the reset work.
1.) Assign reset button element to a const.
2.) Move your score elements to parent scope.
const game = () => {
let pScore = 0;
let cScore = 0;
const resetBtn = gameContainer.querySelector("button.startOver");
const playerScore = document.querySelector(".player-score p");
const computerScore = document.querySelector(".computer-score p");
// The rest of your code...
2.) Attach event listener to reset button.
const startGame = () => {
playBtn.addEventListener("click", () => {
introScreen.classList.add("fadeOut");
match.classList.add("fadeIn");
});
resetBtn.addEventListener("click", () => {
playerScore.innerText = '0';
computerScore.innerText = '0';
pScore = cScore = 0;
});
};
Here is a JSFiddle with a working example.
I think what you need to solve your problem is very well explained in this other questions here.
The idea is that instead of declaring your variable inside your main function, you would create a variable that refer to your functions related to your score outside of it that can then be called when you need it. To avoid global conflict, you would have that function return an object with functions inside for getters and setters. In your case, I would do something like this:
const scoreModule = () => {
let pScore = 0;
let cScore = 0;
return {
getPScore: () => pScore,
getCScore: () => cScore,
setPScore: value => pScore = value,
setCScore: value => cScore = value,
}
}
Because you defined the scoreModule as a global object, you can then use it wherever you want. And, because you returned only getters and setters (not the actual value, but rather a mean to get or change them) your object is protected and you avoid the bad practice of globally available variables. Then in any of your other functions, when you want to use them either to get or set them, you simply:
const game = () => {
// To get a score
const currentPScore = scoreModule().getPScore()
// To set a score
scoreModule().setPScore(newScore)
});

How to give a function a return value when the return is inside an if statement

I had a function that was initially like this, and worked:
productGroupPages(): PDF.Page[] {
const descriptions = {};
this.areas.forEach(area => descriptions[area.id] = area.description);
return this.json.engagementAreas.map(area => {
return this.productGroupPage(area, descriptions[area.id]);
});
}
Basically everything isnt wrapped in the for each.
I had to alter to the function as i wanted to go through a for each, to then use an if statement so i would only return values that actually contained a certain value, the result is that my return statement is too early, I cant move it to the end because of the for loop and im struggling to find out how I can get past this,
this new function:
productGroupPages(): PDF.Page[] {
const descriptions = {};
let pages = {};
console.log('this .json' + JSON.stringify(this.json))
this.json.engagementAreas.forEach(area => {
descriptions[area.id] = area.description
if (area.engagementTypes.length !== 0) {
return this.json.engagementAreas.map(area => {
return this.productGroupPage(area, descriptions[area.id]);
});
}
})
}
I tried creating a variable, an array or object and equaling that to the return value and then returning that near the end of the scope but this wouldnt let me it said the return type was wrong.
Any help would be greatly appreciated.
I think your initial code, with the forEach and map separated was very clean!
The problem with your new code, is that using return inside .forEach() does not make sense in javascript ;) Whenever you return from .forEach(), javascript just ignores the result:
let result = [1,2,3].forEach(x => {
return x * 2;
});
result // undefined
I think you wanted to only return some area-s, which you can do with array.filter() like this:
productGroupPages(): PDF.Page[] {
const descriptions = {};
this.areas.forEach(area => descriptions[area.id] = area.description);
return this.json.engagementAreas
.filter(area => area.engagementTypes.length !== 0)
.map(area => {
return this.productGroupPage(area, descriptions[area.id]);
});
}
I hope that is actually what you meant to do, and if so, I hope this works :)

Categories