如何使用自定义指令使材料 <input matInput> 变为只读?

Posted

技术标签:

【中文标题】如何使用自定义指令使材料 <input matInput> 变为只读?【英文标题】:How to make material <input matInput> become readonly with custom directive? 【发布时间】:2021-01-05 02:24:02 【问题描述】:

我想使用我的自定义指令使使用材料matInput&lt;input&gt; 变为只读。指令isControlReadonly 将用于根据安全标准设置只读。问题是它适用于&lt;input&gt;,但对&lt;input matInput&gt;没有影响

所以.. 第一个输入有效,第二个无效:

  <!-- this works -->
  <input type="input" formControlName="test_field" isControlReadonly>

  <!-- this doesn't works -->
  <mat-form-field appearance="standard">
     <mat-label>Name</mat-label>
     <input matInput type="input" formControlName="customer_name" isControlReadonly>
  </mat-form-field>

这是指令:

import  Directive, ElementRef, OnInit, ViewChildren  from '@angular/core';
import  SecurityService  from './security.service';

@Directive(selector: '[isControlReadonly]')
export class IsReadonlyDirective implements OnInit 

  constructor(
    private elementRef: ElementRef,
    private securityService: SecurityService
  )  

  ngOnInit(): void 
    var ro = !this.securityService.user.canEdit
    this.elementRef.nativeElement.setAttribute('readonly', ro)
  

请帮助如何使该自定义指令与 matInput 一起使用?

编辑注意:我不想从反应形式设置只读,因为指令是更干净的代码。我不想在我的组件中添加逻辑,我想要指令中的逻辑,因为它是集中式的,将用于所有表单。

谢谢

【问题讨论】:

您在响应式表单中使用只读属性,请查看此anwser ***.com/a/54920060/6823766 我不想从响应式表单中设置只读,因为指令是更简洁的代码。我不想在我的组件中添加逻辑,我想要指令中的逻辑,因为它是集中式的,将用于所有表单。 通过使用响应式表单,您已经将逻辑移动到组件中。这就是响应式表单的全部意义——在打字稿代码中包含逻辑,而不是在整个模板中传播它。如果您想保留模板上的逻辑,那么模板驱动的表单是可行的方法。 请仔细阅读案例。问题是“为什么它不适用于 matInput”?在我的方法中,没有像你说的那样“遍布整个模板的代码”。这就是我使用指令的原因,所以逻辑将在指令中。你能想象我必须对我所有的反应形式进行安全检查吗?相反,我可以将逻辑放在指令中的单个位置。所以它比你建议的要干净得多 【参考方案1】:

编辑:之前提供了禁用解决方案。 要使输入只读移动您的逻辑到“ngAfterViewInit” 这是您的指令的一个工作示例:

@Directive(selector: '[isControlReadonly]')
export class IsReadonlyDirective implements OnInit, AfterViewInit 

  constructor(
    private elementRef: ElementRef,
    private control: NgControl,
    private securityService: SecurityService
  )  

  ngAfterViewInit(): void 
   var ro = !this.securityService.user.canEdit
   this.elementRef.nativeElement.setAttribute('readonly', ro)
  

【讨论】:

感谢它适用于disable(),但我需要readonly,因为它获得焦点并且没有变灰 我的错!将您的逻辑移动到“ngAfterViewInit”并实现“AfterViewInit”。然后一切都应该正常工作。 ngAfterViewInit(): void var ro = !this.securityService.user.canEdit this.elementRef.nativeElement.setAttribute('readonly', ro) 这就是我要找的。有用!非常感谢【参考方案2】:

您的指令适用于所有类型的输入,但在 mat-input 的情况下,由您的指令设置的 readonly 属性被 Angular Material 自己的readonly@Input 覆盖。

在此处参考 Mat-Input 的源代码:Mat-Input Readonly @Input 了解更多信息

因此,您可以做的是让设置属性的代码执行出堆栈并将其交给事件循环。这样,您的代码将在 Angular 操作之后执行。最常见的实现方式是setTimeout,延迟为 0 秒

setTimeout(() => 
      this.elementRef.nativeElement.setAttribute('readonly', ro) 
    );

这是一个有效的BLITZ

【讨论】:

以上是关于如何使用自定义指令使材料 <input matInput> 变为只读?的主要内容,如果未能解决你的问题,请参考以下文章

带有自定义指令的可拖动对话框 |角材料

vue全局自定义指令input自动获取焦点指令

vue全局自定义指令input自动获取焦点指令

vue 自定义指令input表单的数据验证

vue自定义指令,包装函数节流。

自定义指令 限制input 的输入位数