Angular 5结合Materialize CSS实现select/options数据绑定问题求助
解决Angular 5 + Materialize CSS的Select数据绑定问题
我太懂你现在的困扰了——明明能把选项正常渲染出来,可Angular的双向绑定就是不生效,点提交的时候newProject里的对应属性还是空的对吧?这锅其实得Materialize背,它的select组件会替换原生的select元素,导致Angular的变更检测根本捕捉不到选择事件。下面给你两个靠谱的解决方案:
方案一:手动监听Materialize选择事件,触发Angular变更检测
既然Materialize会绕开Angular的绑定机制,那我们就手动接管事件监听,同步更新绑定的属性,再通知Angular做变更检测。
修改component.ts代码
先注入变更检测器,然后在初始化Materialize select后监听change事件:
import { Component, OnInit, AfterViewInit, ChangeDetectorRef } from '@angular/core'; import { SectorService } from '../../../services/sector.service'; import { ProjectService } from '../../../services/project.service'; import { Sector } from '../../../models/sector'; import { Project } from '../../../models/project'; import { toast } from 'angular2-materialize'; declare var $: any; @Component({ selector: 'app-NewProject', templateUrl: './NewProject.component.html', providers: [SectorService, ProjectService] }) export class NewProjectComponent implements OnInit, AfterViewInit { sectors: Sector[] = []; newProject = new Project(); types = [ { value: 1, name: 'MS Access' }, { value: 2, name: 'Java' }, { value: 3, name: 'C#' } ]; risks = [ { value: 1, name: 'Low' }, { value: 2, name: 'Medium' }, { value: 3, name: 'High' } ]; constructor( private _serviceSector: SectorService, private _serviceProject: ProjectService, private cdr: ChangeDetectorRef // 注入变更检测器 ) { } ngOnInit() { this._serviceSector.GetAll().subscribe(sector => { this.sectors = sector; setTimeout(() => { $('select').material_select(); // 监听两个select的change事件 $('#types, #sectors').on('change', (e) => { const target = e.target as HTMLSelectElement; // 根据ID判断是哪个select,手动更新绑定属性 if (target.id === 'types') { this.newProject.type = target.value; } else if (target.id === 'sectors') { this.newProject.idSector = target.value; } // 手动触发Angular变更检测 this.cdr.detectChanges(); }); }, 200); }); } ngAfterViewInit() { // 这里不用重复初始化了,避免多次绑定事件 } public Submit(project) { console.log(this.newProject); toast('new project added !', 4000, 'rounded'); //this._serviceProject.CreateProject(project).subscribe(); } }
修改HTML代码
去掉[(ngModel)],改用原生value绑定,因为我们手动处理数据同步:
<div class="row"> <div class="input-field col s12"> <select name="types" id="types"> <option *ngFor="let type of types" [value]="type.name">{{type.name}}</option> </select> <label for="types">Technologies</label> </div> </div> <div class="row"> <div class="input-field col s12"> <select name="sectors" id="sectors" aria-required="true"> <option value="" disabled selected>Choose your sector</option> <option *ngFor="let sector of sectors" [value]="sector.id"> {{sector.name}} </option> </select> <label for="sectors">Sector</label> </div> </div>
方案二:换成Angular Material(更推荐长期方案)
Materialize本质是纯JS+CSS框架,和Angular的组件化、变更检测机制天生不兼容,后期还会遇到更多类似的坑。如果你打算长期用Angular开发,直接换成Angular Material吧——它是官方维护的Material Design组件库,完美支持双向绑定、响应式表单等Angular特性,根本不会出现这类绑定失效的问题。
额外提醒
- 每次更新
sectors这类数据源后,记得先调用$('select').material_select('destroy')销毁旧的实例,再重新初始化,不然新添加的选项不会显示 - 尽量少用
setTimeout延迟初始化,如果可以的话,用ngAfterContentChecked(注意加条件判断避免无限循环)替代
为什么会出现这个问题?
Materialize的select会把原生<select>隐藏,用自己的<ul>/<li>模拟下拉框。用户选择时,它会用原生JS更新原生select的value,但这个操作不会触发Angular的变更检测,所以Angular不知道ngModel的值已经变了。
内容的提问来源于stack exchange,提问作者anthonyp
相关产品推荐
相关产品推荐

