angular 實現下拉列表元件
需求:
方案一
最開始就是用最簡單的方法,前臺請求資料,然後通過select和option在頁面上顯示,但是寫了一會兒發現出現了許多類似下面的 重複的程式碼
:
// 初始化年級選項 initGradeOptions() { this.gradeService.getAll().subscribe((res) => { this.gradeOptions = res; }, () => { console.log('get gradeOption error'); }); } <nz-select nzPlaceHolder="請選擇所屬年級" formControlName="grade"> <nz-option *ngFor="let grade of gradeOptions" [nzLabel]="grade.name" [nzValue]="grade"></nz-option> </nz-select>
每寫一個列表都要寫請求它的資料的方法和模板中的內容,非常繁瑣。
方案二
因為在專案中,不止一個地方用到了這樣的列表,所以就想著把這些列表單獨拿出來,寫成元件。
這裡就參考了樸世超組長的angular的輸入與輸出寫了這個元件
思路大概如下:
ts:
@Input() defaultValue: Grade;// 選中的值 @Output() selected = new EventEmitter<number>();// 輸出屬性 datas: Grade[];// 所有資料 constructor(private gradeService: GradeService) { } // 請求所有的資料 ngOnInit() { this.gradeService.getAll().subscribe((res) => { this.datas = res; }, () => { console.log('error'); }); } // 當則內容更改時,將已選中物件的id彈射到父元件繫結的事件上 dataChange() { this.selected.emit(this.defaultValue); }
html:
<nz-select nzPlaceHolder="所屬年級" class="wide" [(ngModel)]="defaultValue" (ngModelChange)="dataChange()"> <nz-option *ngFor="let data of datas" [nzLabel]="data.name" [nzValue]="data"></nz-option> </nz-select>
ps: 預設選中的功能還在完善,待更新
思考
當我照著上面的套路繼續寫 collegeList
, majorList
, klassList
,以後還會有 teacherList
, studentList
等等,這樣不也形成了很多重複的程式碼嗎?
於是我就想能不能設計一個元件:
我讓它是什麼列表,它就是什麼列表。
然後我就尋找這幾個元件的共性,發現它們請求資料的的特點:
- 都是使用get請求
- 返回的資料都是陣列
- url只有最後一項不同
那麼,我只要傳給元件一個url陣列,就能根據url請求對應的資料,再生成相應的模板
方案三(失敗)
子元件ts:
@Input() urls: String[][] = [];// 儲存傳遞過來的url datas: String[][] = [];// 儲存查詢結果 @Input() titles: String[][] = [];// 儲存提示語句 @Output() selectItems = new EventEmitter();// 已選中的物件 index = 0; items = []; constructor(public dataService: DataService) { } ngOnInit() { this.getData(this.index); } getData(index: number): void { if (index < this.urls.length) { const url = this.urls[index]; this.dataService.getAllData(url).subscribe((res) => { this.datas[index] = res; console.log(this.datas); }, () => { console.log('error'); }); } } dataChange(i: number) { console.log(this.items); this.selectItems.emit(this.items); this.getData(i + 1); }
子元件html:
<nz-select [nzPlaceHolder]="titles[i]" style="width: 150px;" (ngModelChange)="dataChange(i)" [(ngModel)]="items[i]" *ngFor="let url of urls,let i = index"> <nz-option *ngFor="let item of datas[i]" [nzValue]="item" [nzLabel]="item.name"> </nz-option> </nz-select>
父元件ts:
url = ['Grade', 'College', 'Major']; titels = ['年級', '學院', '專業']; getSelectItems(event) { console.log(event); }
父元件html:
<app-grade-list [urls]="url" [titles]="titels" (selectItems)="getSelectItems($event)"> </app-grade-list>
效果:
看起來還能用,但是再往後寫就發現這樣寫有致命的缺陷。
需要查詢url 不知道資料與實體的對應關係 不易維護
總結
雖然這些下拉列表有一定的共性,並且可以抽象出一些公共的功能來實現,但本身設計略複雜,且使用效果並不好,最後還是放棄了第三個方案。