Angular 16迁移后ngSwitch绑定错误及entryComponents问题求解
Angular 16迁移+自定义库升级后「Can't bind to 'ngSwitch' since it isn't a known property of 'div'」错误排查与解决
近期将项目从Angular 15迁移至Angular 16,同时把自定义库从v8升级到v9。原项目有entryComponents数组,但Angular 16不再支持该配置,于是将entryComponents中的组件全部移到@NgModule的declarations数组中,但仍出现「Can't bind to 'ngSwitch' since it isn't a known property of 'div'」错误。
相关代码片段
om-common.module.ts
export const LIB_IMPORTS = [ ButtonModule, InputModule, SelectModule, RadioModule, CheckboxModule, TextareaModule, ToggleModule, ModalModule, CommonTableModule, ToolbarModule, ProgressbarModule ]; const IMPORT = [ ...LIB_IMPORTS, FormsModule, ReactiveFormsModule, BsDropdownModule.forRoot(), TreeModule.forRoot(), SelectInputModule, QueryBuilderModule, ToggleSwitchModule, PrettyJsonModule, MultiSelectModule ]; const DECLARATIONS = [ PropertySelectComponent, PropertyModalComponent, ObjectPathPickerComponent, ManageVariablesLoaderComponent, DeactivateWarningModal ]; const ENTRYCOMPONENT = [ PropertySelectComponent, LoadingModalComponent, PropertyModalComponent, ExpressionInputComponent, ExpressionEditorComponent, ObjectPathPickerComponent, PathPickerInputComponent ]; const PROVIDERS = [ NgbActiveModal, PLORModalService, AppUtilityService ]; @NgModule({ declarations: [...DECLARATIONS], imports: [ CommonModule, ...IMPORT, TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: TranslationService, deps: [HttpClient] } }) ], exports: [...DECLARATIONS], //entryComponents: [...ENTRYCOMPONENT], providers: [...PROVIDERS], }) export class OmCommonModule { static forRoot(): ModuleWithProviders<OmCommonModule> { return { ngModule: OmCommonModule, providers: [...PROVIDERS] }; } }
app.module.ts
export const MODULES = [ ...LIB_MODULES, BrowserModule, AppRoutingModule, ModelerModule.forRoot(), OmCommonModule.forRoot(), FormsModule, ReactiveFormsModule, CommonModule, BrowserAnimationsModule, ImportExportProcessModule, CompareVersionModule.forRoot(), ProcessExecutionModule ];
package.json
"dependencies": { "@angular/animations": "^16.2.12", "@angular/cdk": "^16.2.12", "@angular/common": "^16.2.12", "@angular/compiler": "^16.2.12", "@angular/core": "^16.2.12", "@angular/forms": "^16.2.12", "@angular/localize": "^16.2.12", "@angular/platform-browser": "^16.2.12", "@angular/platform-browser-dynamic": "^16.2.12", "@angular/platform-server": "^16.2.12", "@angular/router": "^16.2.12", "@angular/service-worker": "^16.2.12", "@ng-bootstrap/ng-bootstrap": "^15.0.0", "@ngrx/effects": "^16.2.0", "@ngrx/store": "^16.3.0", "@ngrx/store-devtools": "^16.3.0", "@ngx-translate/core": "^15.0.0", "@ngx-translate/http-loader": "^8.0.0", "@popperjs/core": "^2.11.8", "angular-tree-component": "^8.2.0", "angular2-prettyjson": "^3.0.1", "awesome-typescript-loader": "2.2.1", "bootstrap": "~5.2.0", "clone": "^2.1.1", "core-js": "^2.5.4", "d3-shape": "^3.2.0", "gojs": "2.3.10", "jquery": "^3.6.0", "karma-spec-reporter": "0.0.32", "moment": "^2.22.1", "ngx-bootstrap": "^5.5.0", "ngx-toastr": "^16.0.1", "rxjs": "6.6.7", "rxjs-tslint": "0.1.5", "sass-loader": "^10.1.1", "shortid": "^2.2.8", "ts-md5": "^1.2.9", "tslib": "^2.0.0", "uuid": "^9.0.0", "zone.js": "~0.13.3" }, "devDependencies": { "@angular-devkit/build-angular": "^16.2.12", "@angular/cli": "^16.2.12", "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@babel/helper-module-transforms": "^7.23.0", "@ngrx/schematics": "^12.3.0", "@schematics/angular": "^0.4.8", "@schematics/package-update": "^0.4.8", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "^2.0.10", "@types/node": "^14.11.1", "codelyzer": "^6.0.0", "colors": "1.4.0", "husky": "^0.14.3", "jasmine-core": "~3.8.0", "jasmine-marbles": "~0.8.3", "jasmine-spec-reporter": "7.0.0", "karma": "^6.3.12", "karma-chrome-launcher": "~3.1.0", "karma-coverage": "^2.0.3", "karma-firefox-launcher": "^1.2.0", "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "~1.7.0", "lint-staged": "^7.2.0", "ng-event-source": "^1.0.14", "ng-packagr": "^16.2.3", "prettier": "^1.13.7", "protractor": "~7.0.0", "sonar-scanner": "3.1.0", "ts-node": "~5.0.1", "tslint": "~6.1.0", "typescript": "~4.9.5" },
已执行的迁移步骤
- 删除项目目录下的Node modules
- 执行
npm cache verify - 运行命令
ng update @angular/cli@16 @angular/core@16 - 执行
npm install - 尝试导入CommonModule(NgSwitch、NgClass等指令均来自该模块),但错误仍未解决。
解决方案
1. 检查组件所属模块的CommonModule导入
ngSwitch属于CommonModule,如果报错的组件(比如LoadingModalComponent、ExpressionInputComponent)不在OmCommonModule的DECLARATIONS数组中,而是属于其他模块,需要确保对应模块的imports数组已导入CommonModule。
2. 显式导出CommonModule
子模块不会自动继承父模块的导入,若OmCommonModule中的组件要在其他模块使用,需将CommonModule加入OmCommonModule的exports数组,让外部组件能访问到该模块的指令:
@NgModule({ declarations: [...DECLARATIONS], imports: [ CommonModule, ...IMPORT, // 其他导入 ], exports: [...DECLARATIONS, CommonModule], // 新增CommonModule到exports providers: [...PROVIDERS], }) export class OmCommonModule { ... }
3. 彻底清理缓存并重构
缓存残留可能导致旧配置生效,执行以下命令清理:
- Windows:
rd /s /q node_modules && del package-lock.json yarn.lock - macOS/Linux:
rm -rf node_modules package-lock.json yarn.lock - 接着执行:
npm cache clean --force && npm install && ng build
4. 升级第三方库到兼容版本
项目中部分第三方库版本与Angular 16不匹配:
ngx-bootstrap@5.5.0需升级到16.x.x版本,执行ng update ngx-bootstrap@16angular-tree-component@8.2.0建议替换为维护活跃的分叉版本@circlon/angular-tree-component,并升级到适配Angular 16的版本
5. 补全组件声明
确认所有从entryComponents移来的组件(比如LoadingModalComponent、ExpressionInputComponent)都已加入对应模块的declarations数组,避免组件因未正确声明而无法访问模块指令。
内容的提问来源于stack exchange,提问作者Yashu Jain
相关产品推荐
相关产品推荐

