Function parameter returning "undefined" - javascript

I'm hoping someone can tell me what I'm doing wrong here. When trying to log the value of artistBox in the hideProductCard function, it's returning 'undefined'. However, when logging the value of artistBox in the addArtistSelection function it returns with the correct value. Why is this happening? Both functions, as seen in the 'if/else if conditionals' are taking the same parameter and it is being passed along to both functions, but only one is working.
// Adding Artist Selection
let artistCheckBoxes = document.querySelectorAll('.artist-filter-input');
let artistProductCards = document.querySelectorAll('.store-card');
artistCheckBoxes.forEach((artistBox) => {
artistBox.addEventListener('click', () => {
if (artistBox.checked === true) {
addArtistSelection(artistBox);
hideProductCard(artistBox);
} else if (artistBox.checked === false) {
document.getElementById(`${artistBox.value}-selection`).remove();
}
});
});
let addArtistSelection = (artistBox) => {
let artistSelectionContainer = document.querySelector('.artist-selection-container');
let artistSelection = document.createElement('p');
artistSelection.classList = 'filter-selection artist-selection';
artistSelection.id = `${artistBox.value}-selection`;
artistSelection.innerHTML = `
${artistBox.value}
`;
artistSelectionContainer.appendChild(artistSelection);
};
let hideProductCard = (artistBox) => {
artistProductCards.forEach((productCard) => {
console.log(productCard.querySelector('.card-title').innerText);
console.log(artistBox.value);
});
};

Related

Simplify forEach in forEach React

I have a function where I have to return for each "subcontractor" its response for each selection criteria.
Subcontractor object contains a selectionCriteria object. selectionCriteria object contains an array of data for each selectionCriteria a user has responded to.
Each array item is an object, that contains files, id, request (object that contains info about selection criteria user is responding to), response (contains value of the response).
Here is an example of how a subcontractor looks:
This is the function I come up with, but it's quite complex:
const { subcontractors } = useLoaderData<typeof loader>();
const { t } = useTranslation();
const submittedSubcontractors = subcontractors.filter(
(s) => s.status === 'submitted'
);
const subcontractorsResponsesToSelectionCriteria: Array<ISubcontractor> = [];
let providedAnswersResponded: boolean | null = null;
let providedAnswersFiles: Array<IFile> | [] = [];
let providedAnswersRequiresFiles: boolean | null = null;
submittedSubcontractors.forEach((u) => {
u.selectionCriteria.forEach((c) => {
if (c.request.id === criteriaId) {
if (c.response && 'answer' in c.response) {
if (typeof c.response.answer === 'boolean') {
providedAnswersResponded = c.response.answer;
} else {
providedAnswersResponded = null;
}
} else {
providedAnswersResponded = null;
}
providedAnswersFiles = c.files;
providedAnswersRequiresFiles = c.request.are_files_required;
subcontractorsResponsesToSelectionCriteria.push(u as ISubcontractor);
}
});
});
How could I simplify this code by using .reduce() method, or maybe even better ideas?
You should start working on reducing the level of nesting in your if/else like so:
function getProvidedAnswersResponded(response: any) {
if (response && ('answer' in response) && (typeof response.answer === 'boolean')) {
return response.answer;
}
return null;
}
submittedSubcontractors.forEach(u => {
u.selectionCriteria.forEach(c => {
if (c.request.id !== criteriaId) {
return;
}
providedAnswersResponded = getProvidedAnswersResponded(c.response);
providedAnswersFiles = c.files;
providedAnswersRequiresFiles = c.request.are_files_required;
subcontractorsResponsesToSelectionCriteria.push(u);
});
});
The strategy followed was basically to invert the special cases (such as c.requet.id === criteriaId) and exit the function immediately.
Also, extracting the "provided answer responded" function seems atomic enough to move it to a separate block, giving it more verbosity about what that specific code block is doing.

command in rust does not get called via invoke, no error message

I've got 3 commands i am calling from the front end, 2 of them work perfectly, the third does not.
The issue lies with the function tournament_search
main.rs:
fn main() {
tauri::Builder::default()
.manage(ApiKey {key: Default::default()})
.invoke_handler(tauri::generate_handler![set_api_key, check_connection, tournament_search])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
#[tauri::command]
fn set_api_key(key: String , state: State<ApiKey>){
let mut api_key = state.key.lock().unwrap();
*api_key = key;
}
#[tauri::command]
async fn check_connection(api_key: State<'_, ApiKey>) -> Result<bool, ()> {
let key = api_key.key.lock().unwrap().clone();
let res = Client::new().get(API_URL).bearer_auth(key).send().await.unwrap().text().await.unwrap();
let json: Value = serde_json::from_str(res.as_str()).unwrap();
match json["success"].as_bool() {
Some(_x) => Ok(false),
None => Ok(true)
}
}
#[tauri::command]
async fn tournament_search(search_string: String, api_key: State<'_, ApiKey>) -> Result<&str, ()> {
println!("test: {}", search_string);
let key = api_key.key.lock().unwrap().clone();
let mut query: String = String::new();
query.push_str("query($name:String){tournaments(query:{filter:{name:$name}}){nodes{name,slug,id}}},{$name:");
query.push_str(search_string.as_str());
query.push_str("}");
let res = Client::new().get(API_URL).bearer_auth(key).body(query).send().await.unwrap().text().await.unwrap();
println!("{}", res);
Ok("")
}
index.js:
const { invoke } = window.__TAURI__.tauri
window.addEventListener("load", (ev) => {
let test = document.getElementById("test");
let apiKey = document.getElementById("apiKey");
let tournamentSearch = document.getElementById("tournamentSearch");
let tourneyList = document.getElementById("tourneyList");
apiKey.addEventListener("input", (ev) => {
invoke("set_api_key", {key: apiKey.value});
invoke("check_connection").then((res) => {
if(res){
tournamentSearch.disabled = false;
}else{
tournamentSearch.disabled = true;
}
});
});
tournamentSearch.addEventListener("input", (ev) => {
test.innerText = "e";
invoke('tournament_search', {search_string: tournamentSearch.value}).then((res) => {
test.innerText = res;
});
});
});
Already looked for zero width characters, whether the event get's called in js etc. The issue is just that the function is not called.
You'd only see an error message by adding a .catch() to the invoke call.
Anyawy, the issue here is that Tauri converts command arguments to camelCase on the rust side (to match the JS default) so it would be { searchString: tournamentSearch.value } instead.
If you'd prefer snake_case instead, you can tell Tauri to use that for arguments by changing the command like this:
#[tauri::command(rename_all = "snake_case")]

Function declared in a loop contains unsafe references to variable(s)

My code checks if a user is available. See snippet below:
const users = ['user1', 'user2', 'user3', 'user4']
const usersToAdd = 2
const getRandomWorker = (userArray) => {
return userArray[Math.floor(userArray.length * Math.random())]
}
const availableUsers = []
for (let i = 0; i < usersToAdd; i += i) {
let randomWorker = getRandomWorker(users)
let didAddWorker = false
while (!didAddWorker) {
if (checkIfUserAvailable(randomWorker)) {
availableUsers.push(randomWorker)
users = users.filter((user) => user !== randomWorker)
didAddWorker = true
} else if (!users.length) {
didAddWorker = true
} else {
users = users.filter((user) => user !== randomWorker)
}
}
}
My only problem is that it contains unsafe references to variables(s) because I get the following error:
Function declared in a loop contains unsafe references to variable(s) randomWorker.
I've searched around and fiddled with my code but I can't get rid of the error. I don't know where to look anymore.
As T.J Crowder suggested I had to make a function outside of the loop:
const filterOut = (array, target) => array.filter(element => element !== target);
That fixed it. A bit strange but I can continue know. Thanks!

how to unsubscribe of function in method?

Working on dialog component with angular js and now I find out that my function is subscribed and in if condition do not quit method, but continuously executing another function afterClosed() , here is example of code :
openCreateNewContentDialog(): void {
const oldData = this.dataSource.data;
const dialogConfig = AppConstants.matDialogConfig();
const dialog = this.dialog.open(LicenseDialogComponent, dialogConfig);
dialog.beforeClosed().subscribe(licenceDate => {
for (const datesToCheck of oldData) {
const newDateFrom = new Date(licenceDate.expirationDateFrom);
const oldDateTo = new Date(datesToCheck.expirationDateTo.toString());
if (newDateFrom <= oldDateTo) {
// console.log('return?');
return;
}
}
});
dialog.afterClosed().subscribe(licence => {
if (licence) {
this._value.push(licence);
this.dataSource.data = this.value;
this.change();
}
});
}
What is the best and optimized way to unsubscribe beforeClosed() function?
So from your description, I understand that you dont want a second subscription to happen if the condition in the first subscriber is true, right? But you subscription will happen anyway because you instantiated it in the method, the code in the subscribe() it's just a callback. So if you dont want a lot of rewriting I will suggest storing
subscriptions in variables, so you will have an access to them and can unsubscribe at any time.
openCreateNewContentDialog(): void {
const oldData = this.dataSource.data;
const dialogConfig = AppConstants.matDialogConfig();
const dialog = this.dialog.open(LicenseDialogComponent, dialogConfig);
const beforeClosed = dialog.beforeClosed().subscribe(licenceDate => {
for (const datesToCheck of oldData) {
const newDateFrom = new Date(licenceDate.expirationDateFrom);
const oldDateTo = new Date(datesToCheck.expirationDateTo.toString());
if (newDateFrom <= oldDateTo) {
// console.log('return?');
afterClosed.unsubscribe();
return;
}
}
});
const afterClosed = dialog.afterClosed().subscribe(licence => {
if (licence) {
this._value.push(licence);
this.dataSource.data = this.value;
this.change();
}
});
}
I hope it helps! Also you can try https://www.digitalocean.com/community/tutorials/angular-takeuntil-rxjs-unsubscribe if you have to handle multiple subscriptions.

How to call async function to use return on global scope

I'm currently struggling with a function call, when I call the function from an if statement it does work but when I call it from outside it doesn't, my if statement only checks which button was pressed but I'm trying to remove the function from the button and just call it as soon as my app starts.
We will look at fetchJokes() inside jokeContainer.addEventListener('click', event => {
This is my current code:
const jokeContainer = document.querySelector('.joke-container');
const jokesArray = JSON.parse(localStorage.getItem("jokesData"));
// Fetch joke count from API endpoint
async function sizeJokesArray() {
let url = 'https://api.icndb.com/jokes/count';
let data = await (await fetch(url)).json();
data = data.value;
return data;
}
// use API endpoint to fetch the jokes and store it in an array
async function fetchJokes() {
let url = `https://api.icndb.com/jokes/random/${length}`;
let jokesData = [];
let data = await (await fetch(url)).json();
data = data.value;
for (jokePosition in data) {
jokesData.push(data[jokePosition].joke);
}
return localStorage.setItem("jokesData", JSON.stringify(jokesData));;
}
const jokeDispenser = (function() {
let counter = 0; //start counter at position 0 of jokes array
function _change(position) {
counter += position;
}
return {
nextJoke: function() {
_change(1);
counter %= jokesArray.length; // start from 0 if we get to the end of the array
return jokesArray[counter];
},
prevJoke: function() {
if (counter === 0) {
counter = jokesArray.length; // place our counter at the end of the array
}
_change(-1);
return jokesArray[counter];
}
};
})();
// pass selected joke to print on html element
function printJoke(joke) {
document.querySelector('.joke-text p').textContent = joke;
}
sizeJokesArray().then(size => (length = size)); // Size of array in response
jokeContainer.addEventListener('click', event => {
if (event.target.value === 'Fetch') {
fetchJokes(length);
} else if (event.target.value === 'Next') {
printJoke(jokeDispenser.prevJoke(jokesArray));
} else if (event.target.value === 'Prev') {
printJoke(jokeDispenser.nextJoke(jokesArray));
}
});
And I'm trying to do something like this:
// pass selected joke to print on HTML element
function printJoke(joke) {
document.querySelector('.joke-text p').textContent = joke;
}
sizeJokesArray().then(size => (length = size)); // Size of array in response
fetchJokes(length);
jokeContainer.addEventListener('click', event => {
if (event.target.value === 'Next') {
printJoke(jokeDispenser.prevJoke(jokesArray));
} else if (event.target.value === 'Prev') {
printJoke(jokeDispenser.nextJoke(jokesArray));
}
});
By the way, I'm aware that currently, you can't actually iterate through the array elements using prev and next button without refreshing the page but I guess that will be another question.
Couldn't think of a better title.(edits welcomed)
Async functions are, as the name implies, asynchronous. In
sizeJokesArray().then(size => (length = size)); // Size of array in response
fetchJokes(length);
you are calling fetchJokes before length = size is executed because, as you may have guessed, sizeJokesArray is asynchronous.
But since you are already using promises the fix is straightforward:
sizeJokesArray().then(fetchJokes);
If you have not fully understood yet how promises work, maybe https://developers.google.com/web/fundamentals/getting-started/primers/promises helps.

Categories