【问题标题】:How to pass an array from one component to its sub component如何将数组从一个组件传递到其子组件
【发布时间】:2021-01-25 13:24:47
【问题描述】:

在谷歌搜索了很多相关的答案和尝试之后,我似乎不得不在这里寻求帮助。 我有一个 Angular 应用程序,它的组件之一名为 stock-subscribe,用于显示客户订阅的费用类型。在这个组件中,我创建了另一个组件 stock-addsubs,用于显示该客户尚未订阅的费用类型。 enter image description here

显然,两个 feeType 列表可以组成一个完整的列表。从 stock-subscribe 中,我可以得到一个数组 subscribedFeeIds,它保存了那些订阅的 feeTypes 的所有 id。

我的要求是将这个数组 subscribedFeeIds 传递给 stock-addsubs 组件,以便我可以根据数组的这些 id 过滤掉那些尚未订阅的费用类型。

据我所知,从一个组件传递到其子组件的数据应该是一个简单的过程,两个组件的 html 模板都不应该涉及我的案例。在许多谷歌搜索的解决方案中,使用 @Output 和 @Input 似乎比事件发射更简单。但是,没有一个可以成功传递子组件中的数组元素。

我可以从 stock-subscribe 组件获取预期的 id 列表 (subscribedFeeIds[]),只要传递给子组件的数组不是 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);
        });
      } 
}

【问题讨论】:

  • 您能否也显示相应的 HTML 代码,将subscribedFeeIds 传递给您的子组件?当你说neither of two component html templates should be involved for my case时,我不太明白。您必须在 HTML 中进行一些属性绑定才能将数组从父组件传递到子组件。
  • 这些要传递的数组的id不会在HTML中使用,而只是作为过滤器来获取那些尚未订阅的feeTypes。所以这些数组的元素只在 ts 中消耗。这就是为什么我说“我的案例不应该涉及两个组件 html 模板”。很抱歉让您感到困惑,请忽略它。这就是我没有在这里发布 HTML 的原因。感谢您的时间和在这里的任何输入,谢谢先生。
  • 但正如@Tarun 所说,您需要在两个组件之间建立连接。所以要么导入它,要么在 HTML 中使用它并隐式导入它。
  • 感谢塔伦和美因茨。这是我的 HTML。
  • 感谢塔伦和美因茨。这是我的 HTML。您可能会注意到之前发布的 ts 中没有 columnToDisplay 的属性,为了干净的目的而被删除。

标签: arrays angular input components output


【解决方案1】:

您可以实现以下任一方法:

1.) 根据您上面的代码增强您的@Input@Output

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()

   

   }

}

或者您也可以在处理数组列表时执行以下任何一种方法:

// 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);

  }

}

已创建 Stackblitz Demo 供您参考


2.) 使用 RxJS SubjectBehaviorSubject 发出数据

使用此 Stackblitz Demo 供您参考。

【讨论】:

  • 感谢您花时间回答我的问题。当我在子组件中得到空列表时,可以再看看解决方案 1 吗?在您的第一个解决方案的基础上,我只是简单地更改了原来的 @Output() subscribedFeeIds: any = [];到@Output() subscribedFeeIds = new EventEmitter();为了发出列表。
  • 对不起,已将@Output() 编辑为“@Output() subscribedFeeIds: EventEmitter = new EventEmitter();”,是的,它与方法相同# 1 这将是您的问题的可能解决方案。我可以知道它是否在你身边或者我错过了什么吗?
  • 使用新的@Output 发射变量,错误仍然是:EventEmitter {_isScalar: false,observers: Array(0), closed: false, isStopped: false, hasError: false, ...} closed: false hasError: false isStopped: false 观察者: Array(0) 长度: 0
  • 您是否使用了“this.subscribedFeeIds.emit()”,而您使用的是“.emit”函数而不是使用“=”分配它,您的是“this.subscribedFeeIds.push(data[ i].fees[0].id);"。请参阅上面的示例,但如果它仍然让您感到困惑,我可以提供一个示例演示?
  • 我想我最终会按照建议让它工作。谢谢大家...
猜你喜欢
  • 1970-01-01
  • 2019-03-11
  • 1970-01-01
  • 1970-01-01
  • 2020-05-02
  • 2020-07-30
  • 2018-01-24
  • 2019-11-06
相关资源
最近更新 更多