英文:
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('btn', { static: true, read: ElementRef}) buttonRef: ElementRef<any>;
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('my-class');
Here's a working stackblitz using your @ViewChild
approach.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论