Change detection is not working even with ngZone or Array Copy or with setTimeout - angularjs

I have a function like below, which is invoked from within ngAfterViewInit(). I have a ngFor in the view using the countryUsageTypesArr variable. Now I have tried to put that part of the code inside ngZone.run(), setTimeout(), tried to use spread operator (to create a new array), but nothing makes angular to catch the change. The only option is using ChangeDetectionRef (which works well, I have tested). But I am not feeling well to use ChangeDetector every where. Is there any other way I should try?
getCategoryById(categoryId: number) {
this.categoryService.getCategoryById(categoryId).subscribe((response: any) => {
if (response.result == 1) {
window.setTimeout(() => {
this.countryUsageTypesArr = [...response.data.country_usage_types, []];
}, 0);
}
}, (error: any) => {
// console.log(error.error.msg);
});
}

Related

ReactJS map: Expected an assignment or function call and instead saw an expression - no-unused-expressions

I'm in the midst of cleaning up errors for a repo and I've come across this error where someone's trying to to assign a tag value object to a const variable inside of a map function. Here's its current form:
const BatchEditState = {
CURRENT: 'CURRENT',
DELETE: 'DELETE',
PUT: 'PUT',
}
handleShow = () => {
this.batchEditSet = {};
this.state.currentTags.map((tag) => {
this.batchEditSet[tag.tag_name] = BatchEditState.CURRENT;
});
};
As far as I've researched, one is definitely not supposed to go about it this way even if it does still function. I've seen plenty examples returning a jsx element, but I'm pretty sure that's not the point for this. I do know a map function is supposed to at least return a value however.
I attempted to use a spread operator and an implicit return, but that didn't work out. I also tried making a basic return & even though I'm not encountering any immediate errors in our application, I'm still not sure if this is the right way to go. Still fairly new at this, but appreciate any info, help, and education I can get
handleShow = () => {
this.batchEditSet = {};
this.state.currentTags.map((tag) => {
this.batchEditSet[tag.tag_name] = BatchEditState.CURRENT;
return(
BatchEditState.CURRENT
)
});
};
.map is only for creating new arrays by iterating over an existing array. While you want to iterate over an existing array, you don't want to create a new array - rather, you want to construct a plain object - so .map should not be used here. (The array you're constructing in your current code is going unused.)
To procedurally assign to properties of the object, do:
handleShow = () => {
this.batchEditSet = {};
this.state.currentTags.forEach((tag) => {
this.batchEditSet[tag.tag_name] = BatchEditState.CURRENT;
});
};
Or create an array of entries, then turn that array into an object.
handleShow = () => {
this.batchEditSet = Object.fromEntries(
this.state.currentTags.map(tag => [tag.tag_name, BatchEditState.CURRENT])
);
};
But also, doing this.batchEditSet = in the first place looks like a mistake in React. If this is a component, you should almost certainly be calling this.setState instead of mutating the instance.

React Native - Is using Immer.js and SetState together a problem?

Yesterday I had a behaviour that I don't understand by using Immer.js and setState together. I was using a setState (in a bad way, by the way) when fetching my data and this fetch was called at each endReached of my SectionList.
This setState looked like this:
this.setState((prev) => {
let sections = prev.sections
/* Extract alive topics from "topics"(array retrieved from fetch)*/
let topicsSection1 = topics.filter((card) => !card.states.is_killed)
/* Extract killed topics from "topics"(array retrieved from fetch)*/
let topicsSection2 = topics.filter((card) => card.states.is_killed)
if (sections[0] && sections[0].data)
sections[0].data = positionExtracted > 1 ? sections[0].data.concat(...topicsSection1) : topicsSection1
if (sections[1] && sections[0].data)
sections[1].data = positionExtracted > 1 ? sections[1].data.concat(...topicsSection2) : topicsSection2
return {
sections: sections,
position: response.position,
lastPage: response.laftPage
}
})
and everything worked just fine.
However, I have a function that is called when you press on the topic, and it changes the "opened" value of the topic in the data array to indicate to the list that "this topic" is open.
This function calls the "produce" function of Immer.js
And this function looks like this:
_onPressTopic = (id_card) => {
this.setState(produce((draft) => {
if (draft.sections[0] && draft.sections[0].data)
draft.sections[0].data = draft.sections[0].data.map((item) => {
if (item.id === id_card)
item.opened = !item.opened
return item
})
if (draft.sections[1] && draft.sections[1].data)
draft.sections[1].data = draft.sections[1].data.map((item) => {
if (item.id === id_card)
item.opened = !item.opened
return item
})
}))
}
MY PROBLEM IS:
If I open a topic and then my list data goes through this function, then when an endReached is called again, either I get an error "This object is not expensive", or my list data is not modified at all. And if instead of my first setState, I use a produce from Immer, everything works again.
What I don't understand is: Why does everything work perfectly if I only use Immer.js or just SetState, but as soon as I try to use both together, they don't seem to get along?
Thank you for your answers,
I hope I made it clear !
Viktor

How to extract "=>" to function model

I am fresher here, trying to start using => for functions and can't quite understand the inner part of a function in this code. It does work, wrote it myself, but just want to fully understand how and why.
Is there any other form you could write the exact same code in different "shape"?
I understand how first function extracts to:
function deleteNote(NoteID) {
...
}
But can't figure out how does the inner part work.
const deleteNote = noteID => {
setNote(existingNotes => { return existingNotes.filter((note) => note.id !== noteID);
})
}
Result is fine, just want to clarify what's going on... :)
In short, that could all be translated to:
const deleteNote = function(noteId) {
setNote(function(existingNotes) {
return existingNotes.filter(function(note) {
return note.id !== noteID;
});
});
};
If you wrap the part after => in curly brackets {}, then you need a return statement to return something, such as in:
setNote(existingNotes => {
return ...;
})
If you don't wrap it around curly brackets, then whatever you put after the arrow is what will be returned, such as in:
existingNotes.filter((note) => note.id !== noteID);
Take a look at this short article.
To add to Elder's answer, another easier way of getting used to arrow function is by dissecting the calls into separate named functions (which is what we are commonly used to).
So for example:
existingNotes.filter((note) => note.id !== noteID);
Could also be viewed as:
function noteDifferent(note) {
return (note.id !== noteID);
}
existingNotes.filter(noteDifferent);
Array.filter(fn) expects a callback function 'fn' as a parameter, and will send the element note in this case, to said function.

Promise not executing then outside but it is inside the function

I am using a promise to dispatch an asynchronous action in react. I just want to change the properties of an object. The function works. If I wrap the code in a promise and after doing Promise().then works but if I do myFunction(params).then() the then is not called here is my function. (It is recursive):
export function setValue(propertyPath, value, obj) {
console.log("setting the value")
return new Promise((resolve, reject) => {
// this is a super simple parsing, you will want to make this more complex to handle correctly any path
// it will split by the dots at first and then simply pass along the array (on next iterations)
let properties = Array.isArray(propertyPath) ? propertyPath : propertyPath.split(".")
// Not yet at the last property so keep digging
if (properties.length > 1) {
// The property doesn't exists OR is not an object (and so we overwrite it) so we create it
if (!obj.hasOwnProperty(properties[0]) || typeof obj[properties[0]] !== "object") obj[properties[0]] = {}
// We iterate.
return setValue(properties.slice(1), value, obj[properties[0]])
// This is the last property - the one where to set the value
} else {
// We set the value to the last property
obj[properties[0]] = value
console.log("modified object")
console.log(obj)
return resolve(obj)
}
}
)
}
export function performPocoChange(propertyPath, value, obj) {
console.log("we are indeed here")
return (dispatch) => {
setValue(propertyPath, value, obj).then((poco) => {
console.log("poco is here")
console.log(poco)
dispatch(changePoco(poco))
})
}
}
the console shows "we are indeed here" but not "Poco is here" and changePoco (that is the action) is not called. However if I do a then right after the brackets of the promises and log it shows the log.
I am not an expert in JS. I am trying really hard and this really got me. Any ideas?
Many thanks in advance
You are not resolveing the promise except in the else so the then doesn't get executed.

Superagent Not Returning Value From Then

superagent.get(URL).then((res) => {
for(let i in res.body) {
if (i==='has_rejected_advisories') {
console.log(i + "="+res.body[i]);
}
}
})
.catch((err) => err.message));
My result is:
has_rejected_advisories=false
But I am not able to use res.body[i] outside this function, i.e I want superagent function to return this value in a boolean variable to use it elsewhere.
ex.
a = superagent.get(URL).then((res) => {
for(let i in res.body) {
if(i==='has_rejected_advisories') {
console.log(i + "="+res.body[i]);
}
}
})
.catch((err) => err.message));
if(a===false){/*do this*/}
This is because the superagent.get(url) call is asynchronous. The value given to a is a Promise
Since this is async, the if (a === false) is actually executing before the function body passed to .then. You will either need to move this logic to the .then function, or use something like async/await if you like the synchronous looking syntax.
On top of jerelmiller's great advice you need to note the following:
Try this:
create a global var assuming it's a string
var mysares = ""
This example will only bring back 1 string back of everything!! Not single element. Also if you can't get the standard Fetch() to work don't try other methods like axios or superagents. Now use our global like so:
superagent.get(URL).then((res) => {
for(let i in res.body) {
if (i==='has_rejected_advisories') {
//Add comments as will help you
//to explain to yourself and others
//what you're trying to do
//That said if this iteration produces
//correct data then you're fine
//push my result as a string
mysares = res.body[i];
//infact what's in row 1?
mysares = res.body[0];
//Actually I code my own JSON!!
mysares = res.body[1];
console.log(i + "="+mysares);
}
}
})
.catch((err) => err.message));
Now you can do whatever:
if(mysares===false){/*do this*/
alert(playDuckHunt());}
Things to note:
res.body[i] is an iteration
You cannot use it outside of the function
Because:
It's local to that function
You don't know what position of 'i' is even if you could use it as you will be outside of your loop
One last thing:
Loops loop through loops or arrays etc.
So (in real world) you can't just request the value of the loop
unless you agree the position of data to be released,
type,and bucket (where it's going to be displayed or not).
Hope this helps!
PS> we need to know where 'has_rejected_advisories' is in the JSON so send us your json url as it must be a column/obj header name. Or it's any old 'a' then var a can be your "false"
In constructor:
this.state = {a:null};
In some function:
superagent.get(URL).then(
(res) => {for(let i in res.body)
{
if(i === 'has_rejected_advisories')
{
this.setState({a:res.body[i]})
}
}
}).catch((err)=>(err.message));
In render:
console.log(this.state.a);
Inside then() the value could be used using state variable but there are many scenarios we could not use them, like if we want to perform all the operations under constructor i.e Initializing state variable, calling superagent and changing the state variable and using the state variable.

Resources