PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Wednesday, August 17, 2022

[FIXED] How to pass an array from one component to its sub component

 August 17, 2022     angular, arrays, components, input, output     No comments   

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)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing