为啥在下拉列表中加载组件时不会触发 ngmodelChange 事件?

Posted

技术标签:

【中文标题】为啥在下拉列表中加载组件时不会触发 ngmodelChange 事件?【英文标题】:Why does ngmodelChange event not fire when component loads on a dropdown?为什么在下拉列表中加载组件时不会触发 ngmodelChange 事件? 【发布时间】:2021-02-23 00:39:51 【问题描述】:

在我的 Angular 8 组件中,我向下拉控件添加了双向绑定。

观点

<select  (ngModelChange)='termSelectChanged($event)' [ngModel]="selected">
  <option [ngValue]="t" *ngFor='let t of termsColl'>t?.code</option>
</select>

组件代码

export class AppComponent implements OnInit


     public termsColl : Array<DDModel>;
     public selected : DDModel;
     
      constructor( private s : DDService )
      
    termSelectChanged( event  )    
            alert('HIT');
    
    
    
      ngOnInit()
        
        //service call #1
        this.s.getDataForComplexBind().subscribe(  data => 
          this.termsColl = data;
         
        , error => error );    


        //service call #2
        this.s.getOtherData(  ).subscribe( data => 
          
          //model changes here
          this.selected = this.termsColl[1];
          
        , error =>   console.error(error);  );

                    
    

 

当组件加载时,它会执行 ngOnInit() 并将模型绑定属性 Selected 设置为数组的第一个元素 termsColltermsColl 有数据,但 this.selected = this.termsColl[1]; 行不会将所选选项更改为下拉列表中的第一个元素。事实上,当组件加载时,我期待它触发事件ngModelChange,但它也没有触发事件。我在代码中添加了一个alert(),但它没有显示组件加载的时间。只有当我从下拉列表中选择一个选项时它才会显示。如何更改代码以便在组件加载时执行ngModelChange 事件?

这是我的堆栈闪电战 https://stackblitz.com/edit/angular-version-yeg27j?file=src%2Fapp%2Fapp.component.ts

【问题讨论】:

它可以帮助你参考:***.com/questions/33700266/… @ArunkumarRamasamy 我用 stakcblitz 更新了我的帖子 我不明白为什么在初始设置值时需要(ngModelChange) 触发。你能解释一下为什么吗? 【参考方案1】:

我将ngModeChange 输入更改为DDModel,并从订阅内部调用了您的termSelectChanged()。我也把[ngModel]改成了[(ngModel)]

<select  (ngModelChange)='termSelectChanged($event)' [(ngModel)]="selected">
  <option [ngValue]="t" *ngFor='let t of termsColl'>t?.code</option>
</select>
  termSelectChanged(selection: DDModel) 
    console.log("HIT", selection);
  

  ngOnInit() 
    this.s.getOtherData().subscribe(
      data => 
        this.termsColl = data;
        this.selected = this.termsColl[0];
        this.termSelectChanged(this.selected);
      ,
      error => 
        console.error(error);
      
    );
  

我无法告诉你为什么从代码更改this.selected 不会触发ngModelChange。可能是因为在模板中调用了ngModelChange

【讨论】:

您的代码可以工作,但是有一个问题,当我从下拉列表中选择一个选项时,termSelectChanged() 中的“选择”对象将显示之前选择的值? 我认为由于这个声明(ngModelChange)='termSelectChanged(selected)' 只需将selected 更改为$event 或其他东西。它应该在我的猜测中起作用【参考方案2】:

您可以使用viewToModelUpdate()ngModel 来更新值,如果您想触发ngModelChange。你可以在here找到更多相关信息。

但您需要进行以下更改。

html模板中:

<select  (ngModelChange)='termSelectChanged($event)' [ngModel]="selected" #ngModel="ngModel">
  <option [value]="t" *ngFor='let t of termsColl'>t?.code</option>
</select>

您可以看到我在模板中添加了对 ngModel 的引用,我将在组件类中使用它。

在组件类中:

export class AppComponent 
  name = "Angular 6";
  version = VERSION.full;

  public termsColl: Array<DDModel>;
  public selected: string;

  @ViewChild("ngModel") ngModel: NgModel;

  constructor(private s: DDService) 

  termSelectChanged(event) 
    this.selected = event;
  

  ngOnInit() 
    this.s.getOtherData().subscribe(
      data => 
        this.termsColl = data;
        this.ngModel.viewToModelUpdate(this.termsColl[1]);
      ,
      error => 
        console.error(error);
      
    );
  

您可以看到我使用ngModel 引用来调用带有值的viewToModelUpdate,这反过来会触发ngModelChange

由于您没有直接使用双向绑定,因此您必须将值设置为触发函数termSelectChanged内的selected变量。

希望这能帮助您实现您的要求。

【讨论】:

你不应该直接调用内部 NgModel 方法。 @Rishanthakumar 在您提到的帖子中,我没有使用“直接模型绑定”。我很好奇,如果我想使用“直接模型绑定”,那么如何在组件加载时触发 (ngModelChange) 事件?您能否将直接模型绑定连同现有的属性绑定一起发布? @eutychostfar 我提到的是关于“双向绑定”的内容,我们可以在其中输入[(ngModel)]="selected"。这样您就不需要在ngModelChange 触发时更新this.selected 变量,因为它是双向绑定的。您最初触发ngModelChange 的任何理由,因为您可以通过简单的方式从更新变量的同一位置触发该方法。 @eutychostfar 我认为由于他的解决方案(ngModelChange)='termSelectChanged(selected)' 中的这一陈述,只需将selected 更改为$event 或其他东西。它应该在我的猜测中起作用。 @eutychostfar 我认为您应该将“未分配的头脑”答案标记为正确,因为它很简单。可能是我的答案可以留在这里只是为了知识。再次使其直接双向绑定,您需要放置此[(ngModel)]="selected",除此之外,除了此this.ngModel.viewToModelUpdate(this.termsColl[1]); 之外,您还需要为订阅中的变量分配值。然后你可以删除ngModelChange触发器中的变量赋值。【参考方案3】:

您可以在选项元素中使用value 而不是ngValue。并将t.code 而不是t 分配给value 属性。

<select  (ngModelChange)='termSelectChanged($event)' [ngModel]="selected">
  <option [value]="t.code" *ngFor='let t of termsColl'>t?.code</option>
</select>

参考:https://angular-version-xkjuff.stackblitz.io

【讨论】:

【参考方案4】:

termsColl 有数据,但代码行 this.selected = this.termsColl[1];不会将所选选项更改为下拉列表中的第一个元素。

因为您使用的是属性绑定 [ngModel]="selected",而不是双向数据绑定。

[(ngModel)]="selected" 用于双向绑定,语法是compound from:

[ngModel]="selected" 和 (ngModelChange)="selected = $event"

此外,selected 的值应该是下拉菜单中可用的值,即

ngOnInit()
 
 this.selected = this.termsColl[1].code


下面的代码对你有用:

<select  [(ngModel)]="selected" (change)="onSelection()">
  <option  *ngFor='let t of termsColl' [value]="t.code" [selected]="selected === t.code">t?.code</option>
</select>

您可能还想参考这个https://***.com/a/63192748/13596406

【讨论】:

以上是关于为啥在下拉列表中加载组件时不会触发 ngmodelChange 事件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在下拉菜单中加载组合框项目

AG Grid:通过 ComponentFactoryResolver 在组件中加载网格时未触发 gridReady 事件

为啥核心数据不会在 swiftui 类中加载,但会在结构视图中加载

在 mvc 中加载 2 个下拉列表的更好方法

无法在angularjs中加载下拉列表的ng-model

如何在 AdminLte 多选下拉列表中加载项目以进行更新 - Laravel 8