Angular: How to update an array object key value dynamically? - angularjs

I am trying to change the points of selected object that in the exp below.
$scope.players = [{
name: 'Kobe',
points: 10,
asists: 0,
rebounds: 0
}, {
name: 'Jordan',
points: 20,
asists: 0,
rebounds: 0
}, {
name: 'Grant',
points: 30,
asists: 0,
rebounds: 0
},
];
and I assign an object selected with its name.
if($scope.playerName == $scope.players[i].name){
$scope.selectedPlayerPoints = $scope.players[i].points;
$scope.selectedPlayerAsists = $scope.players[i].asists;
$scope.selectedPlayerRebounds = $scope.players[i].rebounds;
}
but I can't update them:
$scope.selectedPlayerPoints.push(playerPoints);
To make it more clear please check: http://plnkr.co/edit/B8Nydni586Se79fDpjnq?p=preview
How it works:
1-click on a player
2-click on points = each time 2 points will be added.
3-as you add more point, it will change the object dynamically..(but that is the problem..)
Thnx in advance!

I'm not exactly sure what you want to achieve, but my guess is you have trouble with saving player points.
I've updated your plunkr. Basically instead of passing primitive values:
$scope.selectPlayer = function(name, points, asists, rebounds) { ... }
you should pass object reference:
$scope.selectPlayer = function(player) { ... }

Related

Devide list from database into multiple section (React)

I am currently struggling with this problem. Hopefully, you can help me :)
Data is selected from a Database and it returns Objects structured like this:
object = {
id: 4,
name: "Banana",
idParent: 1
}
idParent would be the section of the product.
There are a lot of products and a lot of sections so a simple
const sectionOne = [];
ObjectList.map(e => {
if(e.idParent === 1) {
sectionOne.push(e);
}
})
would probably be wrong, because it should be possible to add other idParents in the future and code should not need some rework in that case.
Let's say there are 30 Objects, 10 have idParent = 1, 15 have idParent = 2 and the last 5 have idParent = 3.
How can the whole list be divided into these sections without making a variable for each section?
Thanks for the help :)
What I believe you need here is a map which groups the values of the list by idParent.
Example:
const objectList = [{
id: 4,
name: "Banana",
idParent: 1
},
{
id: 3,
name: "apple",
idParent: 2
},
{
id: 5,
name: "orange",
idParent: 2
}];
const groupBy = (array, key) => {
return array.reduce((accumlator, value) => {
(accumlator[value[key]] = accumlator[value[key]] || []).push(value);
return accumlator;
}, new Map());
};
const resultMap = groupBy(objectList, "idParent");
console.log(resultMap);
enter code here
The sub-arrays from the map can be access also like this:
const groupWihtIdParen1 = resultMap[1];
// or like this
const groupWithIdParent2 = resultMap.get(2);
``

In an array of obects watched with Vue-watch, how to get index of object that was changed?

I have an array of objects, like this:
myArray: [{
name: "First",
price: 10,
rebate: 5,
listPrice: 15,
outcome: 0
},{
name: "Second",
price: 11,
rebate: 5,
listPrice: 16,
outcome: 0
}
I want to recalculate the outcome-value whenever any of the other values in the same object change.
I already have a setup like this, but it looks for changes in any object and then recalculates the whole array. I've managed to set this up by using a combination of computed and watch functions. However they watch the whole array for changes and then recalculate the outcome-value for all objects in the array.
How can I watch for changes and then recalculate only the changed object?
Below is my current functions for recalculating the whole array (watching another property), but what I'm looking for could be completely different.
computed:
myArrayWasChanged() {
return [this.myArray.reduce((a, {vendors}) => a + vendors, 0), this.myArray.filter(item => item.discounted == false).length]
watch:
myArrayWasChanged: {
handler: function (val, oldVal) {
this.recalculateIsVendor();
Given the outcome is completely dependent on the other properties, it isn't really part of the component's state. Thus, in the component's data you could store the array without the outcome, and then calculate a new version of the array with the outcome as a computed property.
data: function () {
return {
myArrayWithoutOutcome: [
{
name: "First",
price: 10,
rebate: 5,
listPrice: 15
},
{
name: "Second",
price: 11,
rebate: 5,
listPrice: 16
}]
}
},
computed: {
myArrayWithOutcome: function () {
return this.myArrayWithoutOutcome.map(x => {
return {...x, outcome: this.calculateOutcome(x)}
})
}
},
methods: {
calculateOutcome(item) {
// Logic to calculate outcome from item goes here
return 0
}
}

Right way to partially update all items in an array with items from another array in redux reducer?

In Redux, what's the best practice to update all items in an array with items from another array only with the fields that are common to the 2 arrays.
So for example :
billArrayInStore = [{id, amount, dueDate, summary}, ...]
newBillArray = [{id, amount, dueDate}, ...]
Update each bill (amount, dueDate) but keep the 'summary' field untouched.
Thank you :)
You can use Array.prototype.map
newBillArray = billArrayInStore.map(bill => ({
...bill,
amount: 0, // new amount
dueDate: '', // new dueDate
}))
For each bill object in billArrayInStore, you want to see if there is a corresponding bill object in newBillArray by comparing IDs. If you find a matching bill object, you then merge the two bills together into a new object. These new bill objects are stored in a new array to avoid mutating the original.
Since this solution involves transforming existing bill objects and storing them in a new array, it's a perfect use case for Array.prototype.map.
const updatedBills = billArrayInStore.map(bill => {
// For each existing bill, check to see if there is a corresponding
// new bill by comparing bill IDs.
const newBill = newBillArray.find(newBill => newBill.id === bill.id);
// If there is a new bill, merge the bills together using spread syntax.
if (newBill) {
// Order matters here, you want to spread the new bill last so it
// can override any properties in the current bill. If the current
// bill has properties that don't exist in the new bill, they won't
// be changed.
return { ...bill, ...newBill };
}
// If there isn't a corresponding new bill, the current bill should be
// returned unmodified.
return bill;
});
Here's a snippet with a working example.
const billArrayInStore = [
{ id: 1, amount: 1000, summary: 'Rent' },
{ id: 2, amount: 50, summary: 'Internet' },
{ id: 3, amount: 110, summary: 'Electric' }
];
const newBillArray = [
{ id: 2, amount: 40 },
{ id: 3, amount: 125 }
];
const updatedBills = billArrayInStore.map(bill => {
const newBill = newBillArray.find(newBill => newBill.id === bill.id);
if (newBill) {
return { ...bill, ...newBill };
}
return bill;
});
console.log(updatedBills);

How to setState the object of the object of state

Goal: I have two square and I want to change selected square's location. While I'm doing it, I need to change selected square's x-coordinate, y-coordinate, width, and height.
Here is my state which holds the data for square information.
state = {
gestureState: {},
thumbSize: 100,
left: width(100) / 2,
top: height(100) / 2,
taggedClothes: {
0: {id:0, left:100, top:100, thumbSize:100}, <- I want to setState this
1: {id:1, left:200, top:200, thumbSize:200},
},
selectedClothId : 0,
}
Problem: taggedClothes have two square information and I want to change only selected problem but I'm getting compile error
Here I'm performing setState its taggedClothes[0]
// this.state.selectedColorId = 0
var deep = _.cloneDeep(this.state.taggedClothes[this.state.selectedColorId]);
deep.left = left
deep.top = top
deep.thumbSize = thumbSize
this.setState({
gestureState: {
...gestureState
},
taggedClothes[0]: deep <- Getting Compile Error
})
If your have any other suggestion, Please suggest other option!
The key taggedClothes[0] is not valid. You need to spread the taggedClothes and only replace the one that changed:
var deep = _.cloneDeep(this.state.taggedClothes[this.state.selectedColorId]);
deep.left = left
deep.top = top
deep.thumbSize = thumbSize
this.setState({
gestureState: {
...gestureState
},
taggedClothes: {
...taggedClothes,
[this.state.selectedColorId]: deep
}
})
You are trying to access your taggedClothes object like an array.
change this:
taggedClothes: {
0: {id:0, left:100, top:100, thumbSize:100}, <- I want to setState this
1: {id:1, left:200, top:200, thumbSize:200},
},
to that:
taggedClothes: [
{id:0, left:100, top:100, thumbSize:100},
{id:1, left:200, top:200, thumbSize:200},
],
now you should be able to access taggedClothes.

Angular 2 - Update *ngFor table after data has changed

Normally I would expect this to update in realtime, but it doesn't seem to be doing so. In my angular app, I have an array that stores a string and another array like so:
var myArray= [{id:"name1",array:{"id1", "id2"}]
And then in my html I have a table that lists every item in myArray in a row
<table *ngFor="item in myArray">
<td>{{item.id}}</td>
<td>{{item.array}}</td>
</table>
The items in the array are added in a function that is bound to a button click. So the users will chose from a list of items, click a button, and those choices get pushed to the array. They are also able to go back and delete some of those items, so I am adding in code to handle the check every item in myArray, and if its array contains that item that was deleted, it will remove it.
for(let i=0; i<myArray.length;i++) {
let row:any = myArray[i];
for(let k=0; k<row.array.length;k++) {
if(row.array[k] == deletedItem) {
row.array.splice(index, 1);
}
}
}
The code works, using console logs I am able to see that the deletedItem is removed from any item in myArray's array (sorry for the confusing variable names!). However, the table doesn't reflect the updated values, even when myArray shows it when submitting or printing to console. Do I have to refresh the table? I thought it should update automatically since the data is bound.
From this code, I think you are not deleting any element from myArray, but from the local variable row. That's why in your template, you don't see any change.
Try with this :
for(let i=0; i<myArray.length;i++) {
let row:any = myArray[i];
for(let k=0; k<row.array.length;k++) {
if(row.array[k] == deletedItem) {
myArray[i].array.splice(k, 1);
}
}
}
I ran into the same problem today and nearly tore my hair out trying to figure it out. Just like you, my console.log looked right but my data wasn't updating even though it was bound. The reason it won't update is that the data source is immutable and the only way to have it update is by assigning the spliced ArrayList to a new array and then assigning it to the data source.
The data I'm going to use is from https://material.angular.io/components/table/overview this is their property, not mine.
EX:
const ELEMENT_DATA: PeriodicElement[] = [
{position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
{position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
{position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
{position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
{position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
{position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'},
{position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N'},
{position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'},
{position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'},
{position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'},
];
this.dataSource = ELEMENT_DATA;
remove(){
//this is where I splice
this.dataSource.splice(1,1);
//this is where I assign it to the new array.
const ELEMENT_DATAS: PeriodicElements[]=[...this.dataSource];
//this sets the new array to the data source updating it and updating the
table on the UI
this.dataSource = ELEMENT_DATAS;
}

Resources