【问题标题】:Plain English for #something="ngModel"#something="ngModel" 的简单英语
【发布时间】:2021-02-11 00:36:43
【问题描述】:

基于https://stackblitz.com/edit/angular-m2tkrf?file=src%2Fapp%2Fhero-form%2Fhero-form.component.html,稍作修改:

.ts

export class page
{
  model = {mm: "Inside model"}; // my understanding is 'model' is not a required object for binding.
  X = "xxx";  // wired with display via [(ngModel)]="X"
  Y = "yyy";     
  mm="Outside of model";
}

.html

Binding: 
        <input type="text"
               required name="bogus123"
               [(ngModel)]="X"
               #Y="ngModel">
        <div [hidden]="Y.valid || Y.pristine">
          A value is required
        </div>
        <div>
          X value ="{{X}}"
        </div>

效果很好

这是我的理解:

required name="bogus123"input 标记的 HTML 属性,尽管下一个 &lt;div&gt; 中有什么内容,不在讨论范围内。

[(ngModel)]="X" 表示将此输入框与.ts 内名为X 的局部变量双向绑定

认为#X="ngModel" 是在.ts 中使用变量X 连接此输入框的另一种方法,但得到

“不能赋值给引用或变量!”

在 .html 中将 Y 替换为 mm 有效。已经研究过这两个SO What is the difference between the #name and [(ngModel)]="name" in Angular2 Form input?

Angular 2 bind HTML inputs to component variables like in Vue?

有人可以用简单的英语解释什么是#something="ngModel",没有“指令”和“组件”吗?

【问题讨论】:

    标签: angular


    【解决方案1】:

    首先,#X="ngModel" 不是另一种将 ngModel 绑定到 .ts 的局部变量 X 的方法。

    TLDR:它将Angular 指令ngModel 的实例绑定到一个新的模板变量 X,它与您的.ts 变量无关。模板变量仅在您的组件的 .html 中可用(除非您使用 @ViewChild 或类似的方式在您的 .ts 中获取引用)。

    所以当你尝试时:

    <input type="text"
        required name="bogus123"
        [(ngModel)]="X"
        #X="ngModel">
    

    您收到此错误:Error: Cannot assign value "$event" to template variable "X". Template variables are read-only.

    您创建一个新的模板变量X 来保存指令NgModel 的实例。然后 Angular 尝试对这个新的模板变量 X 进行双向绑定,并且不会让你因为你不能重新分配模板变量。它们是只读的。

    #something语法解释

    语法#something 用于获取对模板中某些元素或组件的引用。它将变量 something 绑定到它所应用的元素,而不是相反。

    如果元素是一个组件 (&lt;app-child #something&gt;&lt;/app-child&gt;),模板变量 something 将被分配给组件 ChildComponent 的实例。如果您的.ts 中已有变量something,则模板中的变量不会修改它,但如果您尝试在模板中使用它,它将改用模板变量。

    同样,如果元素是一个基本的html元素(&lt;input type="text" #myInput),变量myInput将被赋值给一个HTMLInputElement

    例子:

    你有一个组件 app-child:

    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-child',
      template: '<span *ngIf="expanded">Hello world!</span>'
    })
    export class ChildComponent {
      expanded = false;
    
      toggle() {
        this.expanded = !this.expanded;
      }
    }
    

    现在在您的应用组件模板中:

    <div>
      <app-child #child></app-child>
      <button type="button" (click)="child.toggle()">Toggle</button>
    </div>
    
    <div>
      <input type="text" #input value="Input test" />
      <button type="button" (click)="input.select()">Select input text</button>
    </div>
    

    现在是#something="ngModel" 语法

    此语法允许您在通常无法获得的情况下获得对指令而不是组件的引用。

    如果您的应用组件模板中有这样的内容:

    <app-child #var appMy></app-child>
    

    现在var 将保存您的ChildComponent 组件实例,但假设您想要引用您的MyDirective (appMy)?这就是您需要不同语法的地方。

    要获得对指令的引用,您需要先向其添加 exportAs

    @Directive({
      selector: '[appMy]',
      exportAs: 'myDirective' // <-- Added exportAs here
    })
    export class MyDirective {}
    

    现在exportAs 告诉 Angular 你的指令将在myDirective 下可用,你现在可以这样做以获得参考:

    <app-child #var="myDirective" appMy></app-child>
    

    var 现在将持有MyDirective 的实例,而不是AppChildComponent

    如果查看ngModel directive的源代码,可以看到导出为ngModel

    @Directive({
      selector: '[ngModel]:not([formControlName]):not([formControl])',
      providers: [formControlBinding],
      exportAs: 'ngModel'
    })
    export class NgModel
    

    这里有一些示例的堆栈闪电战:https://stackblitz.com/edit/angular-ivy-pagmze

    【讨论】:

      【解决方案2】:

      好的,我知道你说过不要使用“指令”或“组件”,但它们是 Angular 框架的核心概念,所以请原谅。

      首先让我们看看#Y

      在 Angular 组件模板的上下文中,# 表示template reference。这些可以以两种形式存在:

      • 全局(意味着它们可通过@ViewChild 提供给组件控制器)
      • 作用域 - 在 structural directive 内部(即在 *ngIf、*ngFor、*ngTemplateOutlet 等内部)

      所以,基本上#Y 正在创建对&lt;input&gt; 元素的引用,该元素的类型为HTMLInputElement。如果您查看该元素的类型定义,您会注意到它没有validpristine 属性/获取器。这是因为该元素实际上是从 NgModel 指令继承了这些属性/getter,该指令最终从 AbstractControlDirective 继承了这些属性,这些属性都来自 Angular。

      那么,百万美元的问题,我们为什么需要#Y="ngModel"?最简单的答案是类型转换。所有额外的代码都在告诉您的模板将模板引用视为NgModel 指令 - 它就是!因此,您可以访问 NgModel 的属性,而不是访问 HTMLInputElement 的属性。

      所以,你有它。希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-02
        • 2012-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多