Select and deselect multiple items from array - javascript

I have a snippet of code here where i have an array that may or may not have keys in it. When the user presses on a 'friend' they add them to a list (array) where they might start a chat with them (add 3 friends to the array, then start a chatroom). The users selected might be toggled on or off.
Current Behavior:
i can add/remove one person, but i cant add multiple people to the array at the same time. When i add one person, select another - the first person is 'active', when i remove the first person, the second person automatically becomes active
Expected Behavior:
I would like to be able to add multiple people to the array and then remove any of the selected items from the array
onFriendChatPress = (key) => {
console.log(key) // this is my key 'JFOFK7483JFNRW'
let friendsChat = this.state.friendsChat // this is an empty array initially []
if (friendsChat.length === 0) {
friendsChat.push(key)
} else {
// there are friends/keys in the array loop through all possible items in the array to determine if the key matches any of the keys
for (let i = 0; i < this.state.selGame.friends.length; i++) {
// if the key matches, 'toggle' them out of the array
if (friendsChat[i] === key) {
friendsChat = friendsChat.filter(function (a) { return a !== key })
}
else {
return friendsChat.indexOf(key) === -1 ? friendsChat.push(key) :
}
}
}
}
Help please!

From your code, I was quite confused regarding the difference between this.state.selGame.friends and this.state.friendsChat. Maybe I missed something in your explication. However, I felt that your code seemed a bit too overcomplicated for something relatively simple. Here's my take on that task:
class Game {
state = {
friendsChat: [] as string[],
};
onFriendToggle(key: string) {
const gameRoomMembers = this.state.friendsChat;
if (gameRoomMembers.includes(key)) {
this.state.friendsChat = gameRoomMembers.filter(
(member) => member !== key
);
} else {
this.state.friendsChat = [...gameRoomMembers, key];
}
}
}
I used typescript because it makes things easier to see, but your JS code should probably give you a nice type inference as well. I went for readability over performance, but you can easily optimize the script above once you understand the process.
You should be able to go from what I sent you and tweak it to be according to what you need

Related

Filter an Array of Objects from an Array in TypeScript

I built a custom component that filters an array of objects. The filter uses buttons, sets from active to non-active and allows more than one option on/off at the same time.
StackBlitz of my attempt - https://stackblitz.com/edit/timeline-angular-7-ut6fxu
In my demo you will see 3 buttons/options of north, south and east. By clicking on one you make it active and the result should include or exclude a matching "location" either north, south and east.
I have created my methods and structure to do the filtering, I'm struggling with the final piece of logic.
So far I have created a method to create an array of filtered locations depending on what the user clicks from the 3 buttons.
Next this passes to my "filter array" that gets the logic that should compare this filtered array against the original to bring back the array of results that are still remaining.
Its not quite working and not sure why - I originally got this piece of functionality working by using a pipe, but fore reasons do not want to go in that direction.
//the action
toggle(location) {
let indexLocation = this.filteredLocations.indexOf(location);
if (indexLocation >= 0) {
this.filteredLocations = this.filteredLocations.filter(
i => i !== location
);
} else {
this.filteredLocations.push({ location });
}
this.filterTimeLine();
}
// the filter
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
//the logic
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
https://stackblitz.com/edit/timeline-angular-7-ut6fxu
Sorry for my expression but u have a disaster in your code. jajaja!. maybe u lost that what u need but the logic in your functions in so wrong. comparing string with objects. filter a array that filter the same array inside... soo u need make a few changes.
One:
this.filteredLocations.push({location});
Your are pushing object. u need push only the string.
this.filteredLocations.push(location);
Two:
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
in this function you filter the timeLine array. and inside of contactMethodFilter you call filter method to timeLine again....
See a functional solution:
https://stackblitz.com/edit/timeline-angular-7-rg7k3j
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
This function is not returning any value and is passed to the .filter
Consider returning a boolean based on your logic. Currently the filter gets undefined(falsy) and everything would be filtered out

Javascript's method forEach() creates array with undefined keys

I am building a simple todo app, and I'm trying to get the assigned users for each task. But let's say that in my database, for some reason, the tasks id starts at 80, instead of starting at 1, and I have 5 tasks in total.
I wrote the following code to get the relationship between user and task, so I would expect that at the end it should return an array containing 5 keys, each key containing an array with the assigned users id to the specific task.
Problem is that I get an array with 85 keys in total, and the first 80 keys are undefined.
I've tried using .map() instead of .forEach() but I get the same result.
let assignedUsers = new Array();
this.taskLists.forEach(taskList => {
taskList.tasks.forEach(task => {
let taskId = task.id;
assignedUsers[taskId] = [];
task.users.forEach(user => {
if(taskId == user.pivot.task_id) {
assignedUsers[taskId].push(user.pivot.user_id);
}
});
});
});
return assignedUsers;
I assume the issue is at this line, but I don't understand why...
assignedUsers[taskId] = [];
I managed to filter and remove the empty keys from the array using the line below:
assignedUsers = assignedUsers.filter(e => e);
Still, I want to understand why this is happening and if there's any way I could avoid it from happening.
Looking forward to your comments!
If your taskId is not a Number or autoconvertable to a Number, you have to use a Object. assignedUsers = {};
This should work as you want it to. It also uses more of JS features for the sake of readability.
return this.taskLists.reduce((acc, taskList) => {
taskList.tasks.forEach(task => {
const taskId = task.id;
acc[taskId] = task.users.filter(user => taskId == user.pivot.task_id);
});
return acc;
}, []);
But you would probably want to use an object as the array would have "holes" between 0 and all unused indexes.
Your keys are task.id, so if there are undefined keys they must be from an undefined task id. Just skip if task id is falsey. If you expect the task id to possibly be 0, you can make a more specific check for typeof taskId === undefined
this.taskLists.forEach(taskList => {
taskList.tasks.forEach(task => {
let taskId = task.id;
// Skip this task if it doesn't have a defined id
if(!taskId) return;
assignedUsers[taskId] = [];
task.users.forEach(user => {
if(taskId == user.pivot.task_id) {
assignedUsers[taskId].push(user.pivot.user_id);
}
});
});
});

checking an object property when adding to Array - ES6

I have a simple algorithm problem but couldn't find a proper solution. There is an array and I just want to add an item in the array if the property of recipe_id is not the same in any objects recipe_id property value in the Array.
I want to prevent any item to add if it has the same property value. If the value of the property is different then it is ok. Thus all the objects in the Recipes array should have different recipe_id values. I write these code but it seems it's not working correctly
here is JSBin link : link
const Recipes =[
{recipe_id:4},
{recipe_id:5}
]
onClickedHandler = (recipe_id) => {
const favData = {
recipe_id: recipe_id,
}
if (Recipes.length > 0) {
for (let item in Recipes) {
if (Recipes[item].recipe_id !== recipe_id) {
console.log("added in the loop!")
Recipes.push(item)
} else {
console.log("it is already in the Recipe list!")
}
}
} else {
console.log("Recipes is empty")
Recipes.push({recipe_id:recipe_id})
}
}
onClickedHandler(9)
console.log(Recipes.length)
Use the Array.some method to check if the ID exists in the array.
You probably need something like:
const Recipes =[
{recipe_id:4},
{recipe_id:5}
];
function addRecipe(recipeId) {
if(!Recipes.some(item => item.recipe_id === recipeId)) {
Recipes.push({recipe_id:recipeId});
console.log("Not duplicate, inserted");
} else {
console.log("duplicate");
}
}
addRecipe(4);
addRecipe(6);
console.log(Recipes)
The problem is that you're going through elements, and first item when you're adding an element with id of 4 there is one item with that ID.
It doesn't pass, next iteration, it checks agains the element with different ID. It passes and goes to ID.
You need a loop within a loop, for example try .filter function, if it returns undefined, you can add it, otherwise don't add.
Well you are pushing an object with new recipe whenever you find another object with a different id instead of checking all of them before adding.
if you were to try adding another object with id 7 (onClickedHandler(7)) after all of your code you would end up with 3 different objects with id 7
This happens because you are not returning in your for loop. Of course, it will iterate over all items and, for each item that has different recipe_id, it will append a new item. You should jump out your function once you find the recipe is already there:
for (let item in Recipes) { // Iterate over each item (no need to test length)
if (Recipes[item].recipe_id !== recipe_id) { // Break if recipe already there.
console.log("it is already in the Recipe list!");
return;
}
}
// Otherwise, it is safe to append the recipe_id:
Recipes.push({recipe_id:recipe_id});
console.log("added in the loop!");
Now, when you find the same recipe_id, you exit from your function.

How to remove value from array using index (Ant Design specific)?

I am creating a questionnaire type form using ReactJs and Ant Design. It is a follow up question of How to create a questionnaire type form using Ant Design?
Now I am succeeded in adding new questions and their respective answers but not in removing them. Let's suppose I have added three questions and when I am trying to remove any one of them, its always removing the last one. The related code for removing is as follows:
remove = k => {
console.log(k);
const { form } = this.props;
// can use data-binding to get
const keys = form.getFieldValue("keys");
// We need at least one passenger
if (keys.length === 1) {
return;
}
keys.splice(k, 1);
// can use data-binding to set
form.setFieldsValue({
keys: keys
});
console.log(keys);
};
The complete code can be found as a demo on codesandbox.io.
I have done something similar in the past. Got rid of the boilerplate of antd's remove and replaced with this. Every time I add a row I push that row (object) to formRows array then removing like this:
remove = key => {
const newRows = this.state.formRows.filter(r => r.key !== key)
this.setState(
prev => ({
formRows: newRows
})
)
}

Filter an array of nested objects

I have an array of nested objects and I have a user, which searches for a room
Here is an array of objects.
I would like to filter an array as soon as user types something
I tried a lot of functions, but nothing worked for me, here is the last example, which failed
search(val: any) {
// if input is clear - show everything, what we have
if (val === '') {
this.roomList = this.roomList;
} else {
//choose the object (objects) where rName = val
this.roomList = this.roomList.staticData.rName.filter(function(o) {
return Object.keys(o).some(function(k) {
return o[k].toString().toLowerCase().indexOf(val) != -1;
})
});
}
}
Could you please help or give me a hint?
You need to apply Array.filter() on roomList instead of staticData propety
this.roomList = this.roomList.filter(function (r) {
return r.staticData.rName.toLowerCase().indexOf(val.toLowerCase()) != -1
});
this.roomList = this.roomList.staticData.rName
This is a wrong starting point, just look at it. Then, rName is not an array, so you can't invoke .filter on it.
Here's how to do it :
this.roomListFiltered = this.roomList.filter(o => new RegExp(val,"i").test(o.staticData.rName) )
new RegExp(val,"i") performs a case-insensitive match.
Also, store the result of the filter in a different variable, otherwise you will lose your original list as it gets filtered out.

Categories