Skip to content

Commit d262ff7

Browse files
committed
feat(chip-list): Implement FormFieldControl
BREAKING CHANGES: - Deprecated: @output() select, and @output() deselect - Added @output() onSelectionChange = EventEmitter<MdChipSelectionChange>
1 parent 5ec538e commit d262ff7

File tree

12 files changed

+1255
-202
lines changed

12 files changed

+1255
-202
lines changed

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

Lines changed: 46 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,17 @@ <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 [(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>.
111140
</md-card-content>
112141
</md-card>
113142
</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: 18 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,22 @@ 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'];
7997
}

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: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,18 @@
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+
Optional,
16+
Renderer2,
17+
Self,
18+
} from '@angular/core';
19+
import {FormGroupDirective, NgControl, NgForm} from '@angular/forms';
20+
import {Platform} from '@angular/cdk/platform';
1021
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1122
import {ENTER} from '@angular/material/core';
1223
import {MdChipList} from './chip-list';
@@ -16,24 +27,29 @@ export interface MdChipInputEvent {
1627
value: string;
1728
}
1829

30+
/**
31+
* Directive that adds chip-specific behaviors to an input element inside <md-form-field>.
32+
* May be placed inside or outside of an <md-chip-list>.
33+
*/
1934
@Directive({
2035
selector: 'input[mdChipInputFor], input[matChipInputFor]',
2136
host: {
22-
'class': 'mat-chip-input',
37+
'class': 'mat-chip-input mat-input-element',
2338
'(keydown)': '_keydown($event)',
24-
'(blur)': '_blur()'
39+
'(blur)': '_blur()',
40+
'(focus)': '_focus()',
2541
}
2642
})
2743
export class MdChipInput {
28-
44+
focused: boolean = false;
2945
_chipList: MdChipList;
3046

3147
/** Register input for chip list */
3248
@Input('mdChipInputFor')
3349
set chipList(value: MdChipList) {
3450
if (value) {
3551
this._chipList = value;
36-
this._chipList.registerInput(this._inputElement);
52+
this._chipList.registerInput(this);
3753
}
3854
}
3955

@@ -68,10 +84,22 @@ export class MdChipInput {
6884
get matSeparatorKeyCodes() { return this.separatorKeyCodes; }
6985
set matSeparatorKeyCodes(v: number[]) { this.separatorKeyCodes = v; }
7086

87+
@Input() placeholder: string = '';
88+
89+
get empty(): boolean {
90+
let value: string | null = this._elementRef.nativeElement.value;
91+
return value == null || value === '';
92+
}
93+
7194
/** The native input element to which this directive is attached. */
7295
protected _inputElement: HTMLInputElement;
7396

74-
constructor(protected _elementRef: ElementRef) {
97+
constructor(protected _elementRef: ElementRef,
98+
protected _renderer: Renderer2,
99+
protected _platform: Platform,
100+
@Optional() @Self() public ngControl: NgControl,
101+
@Optional() protected _parentForm: NgForm,
102+
@Optional() protected _parentFormGroup: FormGroupDirective) {
75103
this._inputElement = this._elementRef.nativeElement as HTMLInputElement;
76104
}
77105

@@ -85,6 +113,17 @@ export class MdChipInput {
85113
if (this.addOnBlur) {
86114
this._emitChipEnd();
87115
}
116+
this.focused = false;
117+
// Blur the chip list if it is not focused
118+
if (!this._chipList.focused) {
119+
this._chipList._blur();
120+
}
121+
this._chipList.stateChanges.next();
122+
}
123+
124+
_focus() {
125+
this.focused = true;
126+
this._chipList.stateChanges.next();
88127
}
89128

90129
/** Checks to see if the (chipEnd) event needs to be emitted. */
@@ -100,4 +139,6 @@ export class MdChipInput {
100139
}
101140
}
102141
}
142+
143+
focus() { this._elementRef.nativeElement.focus(); }
103144
}

0 commit comments

Comments
 (0)