Skip to content

Commit 7a42706

Browse files
tinayuangaojelbourn
authored andcommitted
feat(chip-list): implement FormFieldControl and ControlValueAccessor (#6686)
BREAKING CHANGES: - Deprecated: @output() select, and @output() deselect - Added @output() onSelectionChange = EventEmitter<MdChipSelectionChange>
1 parent 6fa9e6f commit 7a42706

File tree

12 files changed

+1416
-206
lines changed

12 files changed

+1416
-206
lines changed

src/demo-app/chips/chips-demo.html

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,22 @@ <h4>Form Field</h4>
4545
<code>&lt;md-form-field&gt;</code>.
4646
</p>
4747

48-
49-
<md-form-field>
50-
<md-chip-list mdPrefix #chipList1>
51-
<md-chip *ngFor="let person of people" [color]="color" [selectable]="selectable"
48+
<button md-button (click)="tabIndex = (tabIndex === 0 ? -1 : 0)">
49+
Set tabIndex to {{tabIndex === 0 ? -1 : 0}}
50+
</button>
51+
<md-form-field class="has-chip-list">
52+
<md-chip-list [tabIndex]="tabIndex" #chipList1 [(ngModel)]="selectedPeople" required>
53+
<md-chip *ngFor="let person of people" [color]="color" [selectable]="selectable"
5254
[removable]="removable" (remove)="remove(person)">
5355
{{person.name}}
5456
<md-icon mdChipRemove *ngIf="removable">cancel</md-icon>
5557
</md-chip>
58+
<input placeholder="New Contributor..."
59+
[mdChipInputFor]="chipList1"
60+
[mdChipInputSeparatorKeyCodes]="separatorKeysCodes"
61+
[mdChipInputAddOnBlur]="false"
62+
(mdChipInputTokenEnd)="add($event)" />
5663
</md-chip-list>
57-
<input mdInput placeholder="New Contributor..."
58-
[mdChipInputFor]="chipList1"
59-
[mdChipInputSeparatorKeyCodes]="separatorKeysCodes"
60-
[mdChipInputAddOnBlur]="addOnBlur"
61-
(mdChipInputTokenEnd)="add($event)" />
6264
</md-form-field>
6365

6466

@@ -68,21 +70,37 @@ <h4>Form Field</h4>
6870
With <code>mdChipInput</code> the input work with chip-list
6971
</p>
7072

71-
<md-chip-list #chipList2>
72-
<md-chip *ngFor="let person of people" [color]="color" [selectable]="selectable"
73-
[removable]="removable" (remove)="remove(person)">
74-
{{person.name}}
75-
<md-icon mdChipRemove *ngIf="removable">cancel</md-icon>
76-
</md-chip>
77-
</md-chip-list>
7873
<md-form-field>
79-
<input mdInput placeholder="New Contributor..."
74+
<md-chip-list [tabIndex]="tabIndex" #chipList2 [(ngModel)]="selectedPeople" required>
75+
<md-chip *ngFor="let person of people" [color]="color" [selectable]="selectable"
76+
[removable]="removable" (remove)="remove(person)">
77+
{{person.name}}
78+
<md-icon mdChipRemove *ngIf="removable">cancel</md-icon>
79+
</md-chip>
80+
</md-chip-list>
81+
<input placeholder="New Contributor..."
8082
[mdChipInputFor]="chipList2"
8183
[mdChipInputSeparatorKeyCodes]="separatorKeysCodes"
8284
[mdChipInputAddOnBlur]="addOnBlur"
8385
(mdChipInputTokenEnd)="add($event)" />
8486
</md-form-field>
8587

88+
<p>
89+
Chips list without input
90+
</p>
91+
92+
93+
<md-form-field class="has-chip-list">
94+
<md-chip-list #chipList3>
95+
<md-chip *ngFor="let person of people" [color]="color" [selectable]="selectable"
96+
[removable]="removable" (remove)="remove(person)">
97+
{{person.name}}
98+
<md-icon mdChipRemove *ngIf="removable">cancel</md-icon>
99+
</md-chip>
100+
</md-chip-list>
101+
</md-form-field>
102+
103+
86104
<p>
87105
The example above has overridden the <code>[separatorKeys]</code> input to allow for
88106
<code>ENTER</code>, <code>COMMA</code> and <code>SEMI COLON</code> keys.
@@ -108,6 +126,28 @@ <h4>Stacked Chips</h4>
108126
{{aColor.name}}
109127
</md-chip>
110128
</md-chip-list>
129+
130+
<h4>NgModel with chip list</h4>
131+
<md-chip-list [multiple]="true" [(ngModel)]="selectedColors">
132+
<md-chip *ngFor="let aColor of availableColors" color="{{aColor.color}}"
133+
[value]="aColor.name" (remove)="removeColor(aColor)">
134+
{{aColor.name}}
135+
<md-icon mdChipRemove>cancel</md-icon>
136+
</md-chip>
137+
</md-chip-list>
138+
139+
The selected colors are <span *ngFor="let color of selectedColors"> {{color}}</span>.
140+
141+
<h4>NgModel with single selection chip list</h4>
142+
<md-chip-list [(ngModel)]="selectedColor">
143+
<md-chip *ngFor="let aColor of availableColors" color="{{aColor.color}}"
144+
[value]="aColor.name" (remove)="removeColor(aColor)">
145+
{{aColor.name}}
146+
<md-icon mdChipRemove>cancel</md-icon>
147+
</md-chip>
148+
</md-chip-list>
149+
150+
The selected color is {{selectedColor}}.
111151
</md-card-content>
112152
</md-card>
113153
</div>

src/demo-app/chips/chips-demo.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@
2525
width: 150px;
2626
}
2727
}
28+
29+
.has-chip-list {
30+
width: 100%;
31+
}

src/demo-app/chips/chips-demo.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface DemoColor {
2020
styleUrls: ['chips-demo.css']
2121
})
2222
export class ChipsDemo {
23+
tabIndex: number = 0;
2324
visible: boolean = true;
2425
color: string = '';
2526
selectable: boolean = true;
@@ -30,6 +31,8 @@ export class ChipsDemo {
3031
// Enter, comma, semi-colon
3132
separatorKeysCodes = [ENTER, COMMA, 186];
3233

34+
selectedPeople = null;
35+
3336
people: Person[] = [
3437
{ name: 'Kara' },
3538
{ name: 'Jeremy' },
@@ -73,7 +76,23 @@ export class ChipsDemo {
7376
}
7477
}
7578

79+
removeColor(color: DemoColor) {
80+
let index = this.availableColors.indexOf(color);
81+
82+
if (index >= 0) {
83+
this.availableColors.splice(index, 1);
84+
}
85+
86+
index = this.selectedColors.indexOf(color.name);
87+
88+
if (index >= 0) {
89+
this.selectedColors.splice(index, 1);
90+
}
91+
}
92+
7693
toggleVisible(): void {
7794
this.visible = false;
7895
}
96+
selectedColors: any[] = ['Primary', 'Warn'];
97+
selectedColor = 'Accent';
7998
}

src/lib/chips/chip-input.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {async, TestBed, ComponentFixture} from '@angular/core/testing';
22
import {MdChipsModule} from './index';
33
import {Component, DebugElement} from '@angular/core';
4+
import {PlatformModule} from '../core/platform/index';
45
import {MdChipInput, MdChipInputEvent} from './chip-input';
56
import {By} from '@angular/platform-browser';
67
import {Directionality} from '@angular/material/core';
@@ -21,7 +22,7 @@ describe('MdChipInput', () => {
2122

2223
beforeEach(async(() => {
2324
TestBed.configureTestingModule({
24-
imports: [MdChipsModule],
25+
imports: [MdChipsModule, PlatformModule],
2526
declarations: [TestChipInput],
2627
providers: [{
2728
provide: Directionality, useFactory: () => {

src/lib/chips/chip-input.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Directive, Output, EventEmitter, ElementRef, Input} from '@angular/core';
9+
import {
10+
Directive,
11+
ElementRef,
12+
Output,
13+
EventEmitter,
14+
Input,
15+
} from '@angular/core';
1016
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1117
import {ENTER} from '@angular/material/core';
1218
import {MdChipList} from './chip-list';
@@ -16,24 +22,29 @@ export interface MdChipInputEvent {
1622
value: string;
1723
}
1824

25+
/**
26+
* Directive that adds chip-specific behaviors to an input element inside <md-form-field>.
27+
* May be placed inside or outside of an <md-chip-list>.
28+
*/
1929
@Directive({
2030
selector: 'input[mdChipInputFor], input[matChipInputFor]',
2131
host: {
22-
'class': 'mat-chip-input',
32+
'class': 'mat-chip-input mat-input-element',
2333
'(keydown)': '_keydown($event)',
24-
'(blur)': '_blur()'
34+
'(blur)': '_blur()',
35+
'(focus)': '_focus()',
2536
}
2637
})
2738
export class MdChipInput {
28-
39+
focused: boolean = false;
2940
_chipList: MdChipList;
3041

3142
/** Register input for chip list */
3243
@Input('mdChipInputFor')
3344
set chipList(value: MdChipList) {
3445
if (value) {
3546
this._chipList = value;
36-
this._chipList.registerInput(this._inputElement);
47+
this._chipList.registerInput(this);
3748
}
3849
}
3950

@@ -68,6 +79,13 @@ export class MdChipInput {
6879
get matSeparatorKeyCodes() { return this.separatorKeyCodes; }
6980
set matSeparatorKeyCodes(v: number[]) { this.separatorKeyCodes = v; }
7081

82+
@Input() placeholder: string = '';
83+
84+
get empty(): boolean {
85+
let value: string | null = this._inputElement.value;
86+
return value == null || value === '';
87+
}
88+
7189
/** The native input element to which this directive is attached. */
7290
protected _inputElement: HTMLInputElement;
7391

@@ -85,6 +103,17 @@ export class MdChipInput {
85103
if (this.addOnBlur) {
86104
this._emitChipEnd();
87105
}
106+
this.focused = false;
107+
// Blur the chip list if it is not focused
108+
if (!this._chipList.focused) {
109+
this._chipList._blur();
110+
}
111+
this._chipList.stateChanges.next();
112+
}
113+
114+
_focus() {
115+
this.focused = true;
116+
this._chipList.stateChanges.next();
88117
}
89118

90119
/** Checks to see if the (chipEnd) event needs to be emitted. */
@@ -100,4 +129,6 @@ export class MdChipInput {
100129
}
101130
}
102131
}
132+
133+
focus() { this._inputElement.focus(); }
103134
}

0 commit comments

Comments
 (0)