Issue
After googling lots of related answers and tries, I seemly have to seek help here. I have an angular application, one of its components named stock-subscribe, which is used to display the feeTypes that a customer subscribed. Within this component, I created another component, stock-addsubs, used to display the feeTypes that are not yet subscribed by this customer. enter image description here
Obviously, the two feeType lists can compose one whole list. From stock-subscribe, I can get an array, subscribedFeeIds, which holds all the ids of those subscribed feeTypes.
My requirement is to pass this array, subscribedFeeIds, to the stock-addsubs component so that I can filter out those yet unsubscribed feeTypes based on those ids of the array.
To my best understanding, the data passing from one component to its sub component should be a simple process and neither of two component html templates should be involved for my case. Of the many googled solutions, using @Output and @Input seems the simpler than event emitting. However, none can successfully pass the elements of the array in the sub component.
I can get the expected id list (subscribedFeeIds[]) from the stock-subscribe component, and all the rest code work fine so long as the array passed to the sub component is not EMPTY.
1) stock-subscribe.component.ts
@Component({
selector: 'app-stock-subscribe',
templateUrl: './stock-subscribe.component.html',
styleUrls: ['./stock-subscribe.component.scss']
})
export class StockSubscribeComponent implements OnInit {
userSubscribe: ISubscribe;
@Output() subscribedFeeIds: any = [];
listData: MatTableDataSource<any>;
constructor(private accountService: AccountService,
private stockService: StockService) { }
ngOnInit(): void {
this.createSubsList();
}
createSubsList() {
this.accountService.getUserAccount()
.subscribe(account => {
let userId = account.id.toString();
this.stockService.getUserSubscribes(userId).subscribe((data: ISubscribe[]) => {
// get the id of subscribed fee type and thenpublish to other component
for (var i = 0; i < data.length; i++)
{
if (data[i].status)
this.subscribedFeeIds.push(data[i].fees[0].id);
}
console.log(this.subscribedFeeIds);
// prepare the list source for display
this.listData = new MatTableDataSource(data);
this.listData.sort = this.sort;
}, error => {
console.log(error);
});
}, error => {
console.log(error);
});
}
}
2) stock-addsubs.component.ts
@Component({
selector: 'app-stock-addsubs',
templateUrl: './stock-addsubs.component.html',
styleUrls: ['./stock-addsubs.component.scss']
})
export class StockAddsubsComponent implements OnInit {
listData: MatTableDataSource<any>;
@Input() subscribedFeeIds: any [];
constructor(private feesService: FeesService) { }
ngOnInit(): void {
this.createFeeList();
}
createFeeList() {
this.feesService.getFeeList().subscribe((data: IFee[]) => {
// filter those already subscribed
for (var i = 0; i < this.subscribedFeeIds.length; i++)
{
for (var j = 0; j < data.length; j++)
{
data = data.filter(f => f.id != this.subscribedFeeIds[i]);
}
}
// prepare data to display
this.listData = new MatTableDataSource(data);
}, error => {
console.log(error);
});
}
}
Solution
You can implement either one of these methods:
1.) Enhance your @Input
and @Output
based on your code above:
stock-subscribe.component.ts
@Component({...})
export class StockSubscribeComponent implements OnInit {
@Output() subscribedFeeIds: EventEmitter<any> = new EventEmitter<any>();
list: any[] = []; // To store your ids, do not use the @Output variable above to push things inside a loop, you may not want to continuously emit data for an nth number of the sequence.
...
createSubsList() {
...
for (var i = 0; i < data.length; i++) {
...
if (data[i].status)
this.list.push(data[i].fees[0].id); // Push IDs on this.list not on this.subscribedFeeIds
}
this.subscribedFeeIds.emit(this.list); // After the loop finishes, emit the final list value
// Do not use .push() on @Output variable, this is an emission variable so use .emit()
}
}
or you could also do any of these methods when handling your array list:
// METHOD #1
this.filteredIds = [];
for(const { status, fees } of FEES_DATA) {
if (status) filteredIds.push(fees[0].id);
}
OR
// METHOD #2
this.filteredIds = FEES_DATA
.filter(({ status }) => status)
.map(({ fees }) => fees[0].id);
// Then emit the filtered ids
this.list.emit(this.filteredIds);
stock-addsubs.component.ts
@Component({...})
export class StockAddsubsComponent implements OnInit {
// Since you are waiting for emission from StockSubscribeComponent which the
// emission also waits till the loop is finished based on the code above, better to
// implement the @Input like this so as to avoid processing a an empty list
@Input() set subscribedFeeIds(list: any[]) {
if (list && list.length) { // If the list now has items, call createFeeList() function
this.createFeeList();
}
}
...
}
____
or
@Component({...})
export class StockAddsubsComponent implements OnInit, OnChanges { // Add OnChanges
@Input() subscribedFeeIds: any [];
ngOnChanges({ subscribedFeeIds }: SimpleChanges) { // SimpleChanges from @angular/core
if (subscribedFeeIds && subscribedFeeIds.currentValue && subscribedFeeIds.currentValue.length) {
this.createFeeList();
}
// You can also console the subscribedFeeIds and check it's value or changes
console.log(subscribedFeeIds);
}
}
Have created a Stackblitz Demo for your reference
2.) Use RxJS Subject
or BehaviorSubject
to emit data
Use this Stackblitz Demo for your reference.
Answered By - KShewengger Answer Checked By - David Marino (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.