Property '_getHostElement' does not exist on type 'MatButton' module of @angular/material/button after upgrading to angular 15

huangapple go评论96阅读模式
英文:

Property '_getHostElement' does not exist on type 'MatButton' module of @angular/material/button after upgrading to angular 15

问题

After upgrading a codebase from Angular 14 to 15, I get the following TypeScript error on ng serve:

Error: src/app/control-module/button/button.component.ts:35:17 - error TS2339: Property '_getHostElement' does not exist on type 'MatButton'.

35     this.button._getHostElement().classList.add('ae-btn');
                   ~~~~~~~~~~~~~~~

The faulty component looks like this:

import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
import { MatButton } from '@angular/material/button';

@Component({
  selector: 'ae-button',
  templateUrl: './button.component.html',
  styleUrls: ['./button.component.scss'],
})
export class Button {
  @ViewChild('btn', { static: true }) button: MatButton;
  {...}
  ngOnInit() {
    this.button._getHostElement().classList.add('ae-btn');
  }
  {...}
}

Manifest dependency changes were the following:

dependencies:
-    "@angular/cdk": "14.2.1",
-    "@angular/common": "14.2.1",
-    "@angular/compiler": "14.2.1",
-    "@angular/material": "14.2.1",
+    "@angular/cdk": "^15.2.9",
+    "@angular/common": "^15.2.9",
+    "@angular/compiler": "^15.2.9",
+    "@angular/material": "^15.2.9",
devDependencies:
-    "@angular-devkit/build-angular": "14.2.2",
-    "@angular-eslint/builder": "14.0.4",
-    "@angular-eslint/eslint-plugin": "14.0.4",
-    "@angular-eslint/eslint-plugin-template": "14.0.4",
-    "@angular-eslint/schematics": "14.0.4",
-    "@angular-eslint/template-parser": "14.0.4",
-    "@angular/cli": "14.2.2",
-    "@angular/compiler-cli": "14.2.1",
+    "@angular-devkit/build-angular": "^15.2.8",
+    "@angular-eslint/builder": "^15.2.1",
+    "@angular-eslint/eslint-plugin": "^15.2.1",
+    "@angular-eslint/eslint-plugin-template": "^15.2.1",
+    "@angular-eslint/schematics": "^15.2.1",
+    "@angular-eslint/template-parser": "^15.2.1",
+    "@angular/cli": "^15.2.8",
+    "@angular/compiler-cli": "^15.2.9",
-    "typescript": "4.8.3",
+    "typescript": "^4.9.5"

I don't find mention of this in bug reports/release notes. How was this changed? Thanks!

英文:

After upgrading a codebase from Angular 14 to 15, i get the following typescript error on ng serve:

Error: src/app/control-module/button/button.component.ts:35:17 - error TS2339: Property '_getHostElement' does not exist on type 'MatButton'.

35     this.button._getHostElement().classList.add('ae-btn');
                   ~~~~~~~~~~~~~~~

The faulty component looks like this:

import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
import { MatButton } from '@angular/material/button';

@Component({
  selector: 'ae-button',
  templateUrl: './button.component.html',
  styleUrls: ['./button.component.scss'],
})
export class Button {
  @ViewChild('btn', { static: true }) button: MatButton;
  {...}
  ngOnInit() {
    this.button._getHostElement().classList.add('ae-btn');
  }
  {...}
}

Manifest dependency changes were the following:

dependencies: 
-    "@angular/cdk": "14.2.1",
-    "@angular/common": "14.2.1",
-    "@angular/compiler": "14.2.1",
-    "@angular/material": "14.2.1",
+    "@angular/cdk": "^15.2.9",
+    "@angular/common": "^15.2.9",
+    "@angular/compiler": "^15.2.9",
+    "@angular/material": "^15.2.9",
devDependencies: 
-    "@angular-devkit/build-angular": "14.2.2",
-    "@angular-eslint/builder": "14.0.4",
-    "@angular-eslint/eslint-plugin": "14.0.4",
-    "@angular-eslint/eslint-plugin-template": "14.0.4",
-    "@angular-eslint/schematics": "14.0.4",
-    "@angular-eslint/template-parser": "14.0.4",
-    "@angular/cli": "14.2.2",
-    "@angular/compiler-cli": "14.2.1",
+    "@angular-devkit/build-angular": "^15.2.8",
+    "@angular-eslint/builder": "^15.2.1",
+    "@angular-eslint/eslint-plugin": "^15.2.1",
+    "@angular-eslint/eslint-plugin-template": "^15.2.1",
+    "@angular-eslint/schematics": "^15.2.1",
+    "@angular-eslint/template-parser": "^15.2.1",
+    "@angular/cli": "^15.2.8",
+    "@angular/compiler-cli": "^15.2.9",
-    "typescript": "4.8.3"
+    "typescript": "^4.9.5"

I don't find mention of this in bug reports/release notes, how was this changed?
Thanks!

答案1

得分: 1

这不是你所描述的一个“错误”。_getHostElement() 从未是 v14 版本的 MatButton公共 API的一部分。所有对公共 API 的破坏性更改要么由迁移脚本自动处理,要么明确列在迁移文档中。你不能期望组件的内部结构不会发生变化。你所做的是一种不太好的实践,容易受到此类破坏性更改的影响。此外,直接操纵 DOM(你正在做的事情)可能也不是一个好主意 - 最好使用 Renderer2 来进行操作。

有其他获取 elementRef 的方式,不依赖于内部结构,例如使用 @ViewChild 装饰器的 read 属性:

@ViewChild('btn', { static: true, read: ElementRef }) buttonRef: ElementRef<any>;

除此之外,还有更好的动态应用类的方法,例如 ngClass 指令(除非你在使用自定义工厂并且确实可以在模板中应用这些指令)。

如果你坚决要保留以前的、不太可靠的行为,你可以随时查看旧版本的按钮代码,并查看 _getHostElement() 实际上是在这里做什么的:

_getHostElement() {
  return this._elementRef.nativeElement;
}

然后将你的代码更改为完全相同的方式:

this.button._elementRef.nativeElement.classList.add('my-class');

这里有一个使用你的 @ViewChild 方法的可工作的 stackblitz

英文:

It's not a "bug" as you described it. _getHostElement() was never a part of the public API of the MatButton in v14. All the breaking changes to the public API are either automatically handled by migration scripts, or explicitly listed in the migration docs. You can't expect internals of the component to NOT get changed. What you're doing is a rather bad practice, and it's prone to such breaking changes. In addition, directly manipulating DOM (which you are doing) is probably not a best idea either - you're better of using the Renderer2 for that.

There are other ways of getting the elementRef that don't rely on internals, e.g. using the read property on the @ViewChild decorator:

@ViewChild(&#39;btn&#39;, { static: true,  read: ElementRef}) buttonRef: ElementRef&lt;any&gt;;

Aside from that, there are better ways of dynamically applying classes, e.g. ngClass directive (unless you're using custom factory and can really apply those directives in the template).

If you're hellbent on retaining the previous, less reliable behavior, you can always look at the old version of the button code and look what the _getHostElement() was actually doing here:

_getHostElement() {
  return this._elementRef.nativeElement;
}

And change your code to the exactly same thing:

this.button._elementRef.nativeElement.classList.add(&#39;my-class&#39;);

Here's a working stackblitz using your @ViewChild approach.

huangapple
  • 本文由 发表于 2023年5月22日 19:10:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76305555.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定