Checking an array for existing array items passed as a parameter - reactjs

I have 2 react functions below
const hasPermission = (permission: string) => {
if (user?.permissionsEnabled === false) {
return true
}
return permissions.includes(permission) || false
}
The function below accepts an array of a particular type
I want a situation where if any item in the array passed here(parameter) exist in the enum
UserPermissions I want to return a true.
return true does not seem to be working in the method below.
const hasAnyPermission = (permissionsPassed: UserPermissions[]) => {
permissionsPassed.map(permission => {
if (hasPermission(permission)) {
return true
}
})
return false
}
I am calling hasAnyPermission like this..
hasAnyPermission([Edit,View])

Array.prototype.map only returns an array, you need to use Array.prototype.some instead:
const hasAnyPermission = (permissionsPassed: UserPermissions[]) => {
return permissionsPassed.some(permission => {
if (hasPermission(permission)) {
return true
}
})
}
Which is equivolent to:
const hasAnyPermission = (permissionsPassed: UserPermissions[]) => {
return permissionsPassed.some(permission => hasPermission(permission));
}
Or use the regular for-of loops:
const hasAnyPermission = (permissionsPassed: UserPermissions[]) => {
for(let permission of permissionsPassed) {
if (hasPermission(permission)) {
return true
}
}
return false
}

Abbreviated fully-working example:
enum UserPermissions { Edit, View, Delete }
const user = { permissions: [UserPermissions.View] }
console.log("has permission?", hasAnyPermission(user, [UserPermissions.Delete]))
function hasAnyPermission(user, permissions: UserPermissions[]) {
if (user?.permissionsEnabled === false) return true
const userHasPermission = (p) => user.permissions.includes(p)
return permissions.some(userHasPermission)
}

Related

change state variable (array of objects) in react

I am very new to react and have a very straightforward usecase.
on a certain function call, I need to update one of the state variables - which is an array of objects.
I need to iterate through this array find an element and add a key the object in that element.
I tried this way but its not working.
const [finalStudents, setFinalStudents] = useState([]);
function setAttentionForStudent(deviceName, value) {
// console.log("Device ID:", deviceName)
// console.log("Attention value:", value)
finalStudents.map((student, index) => {
console.log("student", student)
if (student['device']['deviceName'] == deviceName) {
console.log("student inside", student)
setFinalStudents((prevFinalStudents) => {
console.log("prev final student",prevFinalStudents)
prevFinalStudents[index]['device']['attentionValue'] = value
})
// student['device']['attentionValue'] = value
} else {
setFinalStudents((prevFinalStudents) => {
prevFinalStudents[index]['device']['attentionValue'] = 0
})
}
})
// console.log(finalStudents)
}
Try this:
const [finalStudents, setFinalStudents] = [];
const setAttentionForStudent = (deviceName, value) => {
if (finalStudents.length !== 0) {
for (var x = 0; x < finalStudents.length; x++) {
if (finalStudents[x].device.deviceName === deviceName) {
finalStudents[x].device.deviceName = value;
setFinalStudents(new Array(...finalStudents));
} else {
finalStudents[x].device.deviceName = value;
setFinalStudents(new Array(...finalStudents));
}
}
}
};
callback in setFinalStudents should return an array to update state. You can use map in setFinalStudents like this:
setFinalStudents((prevFinalStudents) => {
return prevFinalStudents.map((student) => {
if (student["device"]["deviceName"] == deviceName) {
student["device"]["attentionValue"] = value;
} else {
student["device"]["attentionValue"] = value;
}
return student;
});
});
Was finally able to solve the problem by the following way:
setFinalStudents((prevFinalStudents) => {
const clonedFinalStudents = [...prevFinalStudents];
return clonedFinalStudents.map((student) => {
let updatedStudent = { ...student };
let attentionValue = 0;
if (student['device']['deviceName'] == deviceName) {
attentionValue = value;
}
updatedStudent = {
...updatedStudent,
device: {
...updatedStudent.device,
attentionValue,
},
};
return updatedStudent;
});
});

Unable to return from a function in reactjs

I am passing an object from one function to another. If I try to print the object values directly in the view, then it gets displayed at once. Instead if I loop through the object values and try to display each of them from the function return then it is not getting displayed. Can any one please help.
const [projects, setprojects] = useState([]);
function scanData() {
var params = {
TableName: "Voicemail_Project_Configuration_Details",
};
docClient.scan(params, onScan);
function onScan(err, data) {
if (err) {
console.log("err", JSON.stringify(err, undefined, 2))
//document.getElementById('textarea').innerHTML = "Unable to update item: " + "\n" + JSON.stringify(err, undefined, 2);
} else {
//console.log(data.Items)
return (
data.Items.map((item, index) => {
//console.log(item)
Object.entries(item).map((key,val) => {
if(val == 0){
Object.entries(key).map((k,v) => {
if (v == 1)
newArr.push(k[1]);
setprojects(Object.values(newArr))
projectList(newArr)
})
}
})
})
)
}
}
}
function projectList(projects) {
console.log(projects)
return(
projects.map( (k,v) => {
return(<tr><td key={v}>{k}</td></tr>)
})
)
}
<tbody>{projectList}</tbody> is not returning anything. But <tbody>{projects}</tbody> is displaying all the values as a string in a row.
This is console.log of data.items

Why is my object type not getting updated?

I'm creating a permission service using react typescript and I ran into the following problem. I have the class:
import {IPermission} from "../interfaces/IPermission";
class PermissionService {
private permissions: IPermission[] = [];
constructor(permissions: IPermission[]) {
this.permissions = permissions;
}
public getValue(key: string): IPermission['value'] {
const perm = this.permissions.find(permission => permission.key === key);
if (!perm) {
throw new Error('Could not find the permission');
}
return perm.value;
}
public modifyPermission(key: string, defaultValue: any, value: any): void {
const perms = [...this.permissions];
for (let i = 0; i < perms.length; i++) {
perms[i].defaultValue = defaultValue;
perms[i].value = value
}
this.permissions = perms;
console.log(perms);
}
public parseActivePermissions(permissions: IPermission[]): IPermission[] {
this.permissions.forEach(permission => {
permissions.forEach(activePermission => {
if (permission.key === activePermission.key) {
permission.defaultValue = activePermission.defaultValue;
permission.value = activePermission.value;
}
})
})
return this.permissions;
}
public getAll(): IPermission[] {
return this.permissions;
}
}
export default PermissionService;
and an AdminPermissions data file
import PermissionService from "../services/permission.service";
import {IPermission} from "../interfaces/IPermission";
import Permissions from "./Permissions";
const service: PermissionService = new PermissionService(Permissions);
service.modifyPermission('canAccessAcp', true, true);
const AdminPermissions: IPermission[] = service.getAll();
export default AdminPermissions;
The problem is, the service.modifyPermission() does not update the defaultValue and value of the permission. It's still false when console logging. Why is that?
UPDATE #1
Changed the file a bit. Still doesn't work. Now I'm directly changing the values, but they still log as false.
class AdminPermissions {
public getAll(): IPermission[] {
const service: PermissionService = new PermissionService(Permissions);
service.permissions.forEach(permission => {
if (permission.key === 'canAccessAcp') {
permission.defaultValue = true;
permission.value = true;
}
})
return service.permissions;
}
}
The problem is that with forEach you are not changing the actual value of each items, so you should do something like this:
class AdminPermissions {
public getAll(): IPermission[] {
const service: PermissionService = new PermissionService(Permissions);
return service.permissions.map(permission => {
if (permission.key === 'canAccessAcp') {
return (
{
...permission,
defaultValue: true,
value: true
}
)
}
return permission
});
}
}
I found a solution.
In the permission.service.ts
public modifyPermission(key: string, defaultValue: any, value: any): void {
const perms: IPermission[] = this.permissions.map(permission => {
if (permission.key === key) {
console.log('found permission');
return {
...permission,
defaultValue,
value
}
}
return permission
})
this.permissions = perms;
}

Why is not the state updated?

I have a function that updates a state with a change and adds a value, but the state in the 'addResponse' function does not always change:
handleSelected (e, item) {
this.setState({
current_component_id: item.id,
}, () => this.addResponse()
);
};
Call function above:
addResponse (e) {
const { enrollment_id, evaluation_id, user_id, question_id, current_component_id,
responses, current_question, current_question_id
} = this.state;
console.log(current_component_id)
if (current_component_id != 0) {
const newResponse = {
enrollment_id: enrollment_id,
evaluation_id: evaluation_id,
user_id: user_id,
question_id: current_question_id,
answer_component: current_component_id,
};
function hasAnswer(res) {
const list_question_id = res.map((item) => {
return item.question_id
});
if (list_question_id.includes(current_question_id)) {
return true
} else {
return false
}
}
if (responses === undefined) {
this.setState({
responses: [newResponse]
}
, () => console.log('---------> primeiro', this.state.responses)
)
} else {
const check = hasAnswer(responses);
if (check) {
this.setState(prevState => {
prevState.responses.map((item, j) => {
if (item.question_id === current_question_id) {
return item.answer_component = current_component_id
}
return item ;
})
}
, () => { console.log('----> questao alterada ', this.state.responses)}
)
} else {
this.setState({
responses: [...this.state.responses, newResponse]
}
, () => console.log('------> questao nova', this.state.responses)
);
}
}
}
// this.nextQuestion();
};
the first console.log is always correct, but the others do not always change, I know that setState is asyn, but I thought that as I call the addResponse function it would be async
There is a problem in your how you call setState when check is true.
It should be
this.setState(prevState => ({
responses: prevState.responses.map((item, j) => {
if (item.question_id === current_question_id) {
item.answer_component = current_component_id
}
return item ;
})
})
, () => { console.log('----> questao alterada ', this.state.responses)}
)

Filter out existing objects in an array of objects

I don't think this is difficult, I just can't figure out the best way to do it. This function is creating an array, from a group of checkboxes. I then want to break up the array and create an array of objects, because each object can have corresponding data. How do I filter out existing rolesInterestedIn.roleType.
handleTypeOfWorkSelection(event) {
const newSelection = event.target.value;
let newSelectionArray;
if(this.state.typeOfWork.indexOf(newSelection) > -1) {
newSelectionArray = this.state.typeOfWork.filter(s => s !== newSelection)
} else {
newSelectionArray = [...this.state.typeOfWork, newSelection];
}
this.setState({ typeOfWork: newSelectionArray }, function() {
this.state.typeOfWork.map((type) => {
this.setState({
rolesInterestedIn: this.state.rolesInterestedIn.concat([
{
roleType: type,
}
])
}, function() {
console.log(this.state.rolesInterestedIn);
});
})
});
}
UDPATE
rolesInterestedIn: [
{
roleType: '',
experienceYears: ''
}
],
Because each time you do setState you are concatenating the new value to the prev one in rolesInterestedIn array. Add new value only when you are adding new item, otherwise remove the object from both the state variable typeOfWork and rolesInterestedIn.
Try this:
handleTypeOfWorkSelection(event) {
const newSelection = event.target.value;
let newSelectionArray, rolesInterestedIn = this.state.rolesInterestedIn.slice(0);
if(this.state.typeOfWork.indexOf(newSelection) > -1) {
newSelectionArray = this.state.typeOfWork.filter(s => s !== newSelection);
rolesInterestedIn = rolesInterestedIn.filter(s => s.roleType !== newSelection)
} else {
newSelectionArray = [...this.state.typeOfWork, newSelection];
rolesInterestedIn = newSelectionArray.map((workType) => {
return {
roleType: workType,
experienceYears: '',
}
});
}
this.setState({
typeOfWork: newSelectionArray,
rolesInterestedIn: rolesInterestedIn
});
}
Suggestion: Don't use multiple setState within a function, do all the calculation then use setState once to update all the values in the last.

Resources