Reputation: 83
I am wondering what the best way is to prevent duplicate data from getting into a new array. I have a service call that returns the same array 3 times. I'm trying to take a number from inside the objects in the array and add them up to create a "total" number (fullRentAmt), but since the array gets returned 3 times I'm getting the total*3. I am thinking maybe .some() or .filter() could be of use here but I've never used those/am not sure how that would be implemented here. Thanks for any help!
What I tried, but it's not working/the new array isn't getting populated:
Component
properties = [];
fullRentAmt: number = 0;
const propertyDataSub = this.mainService.requestPropertyData()
.subscribe((pData: PropertyData[]) => {
if (pData) {
const propertyData = pData;
for (let i = 0; i < propertyData.length; i++) {
if (this.properties[i].propertyId !== propertyData[i].propertyId) {
this.properties.push(propertyData[i]);
}
}
for (let i = 0; i < this.properties.length; i++) {
this.fullRentAmt += this.properties[i].tenancyInformation[0].rentAmount;
}
});
Data returned from backend (array of 2 objects):
[
{
"tenantsData":[
{
"email":null,
"tenantNames":null,
"propertyId":2481,
}
],
"tenancyInformation":[
{
"id":2487,
"rentAmount":1000,
}
],
},
{
"tenantsData":[
{
"email":null,
"tenantNames":null,
"propertyId":3271,
}
],
"tenancyInformation":[
{
"id":3277,
"rentAmount":1200,
}
],
},
Upvotes: 0
Views: 854
Reputation: 13079
First thing you need to do is to fix your server and return the list once.
If server is out of your reach, you can leverage distinctUntilChanged
pipe in combination with isEqual
method in the frontend. You can either implement it yourself, or use a library such as lodash.
Also you do not have to subscribe, use async
pipe in the template.
this.properties$ = this.mainService.requestPropertyData()
.pipe(
distinctUntilChanged(isEqual) // provide isEqual function somehow
);
this.totalRentAmount$ = properties$.pipe(
map(getTotalRentAmount)
);
// maybe in some other utility file:
export const getTotalRentAmount = (properties: Property[]): number => {
return properties
.map(property => property.tenancyInformation.rentAmount)
.reduce((total, amount) => total + amount, 0);
}
Then in the template:
<div>Total Rent Amount: {{ totalRentAmount | async }}</div>
Also if you really need to subscribe in the component and are only interested in the first emitted value of an observable, you can use first()
or take(1)
pipe to automatically unsubscribe after first value.
this.mainService.requestPropertyData()
.pipe(
first() // or take(1)
)
.subscribe(properties => this.properties = properties);
See the difference between first() and take(1)
Upvotes: 0
Reputation: 269
@YaYa is correct. I added this to show the correct code in Angular
properties = [];
fullRentAmt: number = 0;
const propertyDataSub = this.mainService.requestPropertyData()
.subscribe((pData: PropertyData[]) => {
if (pData && pData.length) {
let arrSet = new Set()
const propertyData = pData;
for (let i = 0; i < propertyData.length; i++) {
if (this.properties[i].propertyId !== propertyData[i].propertyId) {
arrSet.add(propertyData[i])
}
}
this.properties = Array.from(arrSet);
for (let i = 0; i < this.properties.length; i++) {
this.fullRentAmt += this.properties[i].tenancyInformation[0].rentAmount;
}
});
Upvotes: 0
Reputation: 35
I'm not an angular developer, but I hope my answer will help you.
let the for loop duplicate the data as much as it wants. you just have to change the idea of storing the stuff from an array to a JavaScript Set
basically, it's very similar to arrays they're lists and iteratables that are very similar to arrays, the only difference is that they don't allow duplication,
usage:
const properties = new Set()
properties.add("yellow")
properties.add("blue")
properties.add("orange")
console.log(properties) // yellow, blue, orange
properties.add("blue")
properties.add("blue")
properties.add("blue")
console.log(properties) // yellow, blue, orange
after your for loop finishes, you may want to convert this set into a normal array, all you have to do is to use destructuring:
const propertiesArray = [...properties]
Upvotes: 1