Skip to content

Commit aff22e5

Browse files
fxckjelbourn
authored andcommitted
feat(textarea): initial md-textarea (#1562)
1 parent ce26cae commit aff22e5

File tree

7 files changed

+108
-11
lines changed

7 files changed

+108
-11
lines changed

src/demo-app/input/input-demo.html

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
<td><md-input placeholder="Long Last Name That Will Be Truncated" style="width: 100%"></md-input></td>
1111
</tr></table>
1212
<p>
13-
<md-input class="demo-full-width" placeholder="Address" value="1600 Amphitheatre Pkway"></md-input>
14-
<md-input class="demo-full-width" placeholder="Address 2"></md-input>
13+
<md-textarea class="demo-full-width" placeholder="Address" value="1600 Amphitheatre Pkway"></md-textarea>
14+
<md-textarea class="demo-full-width" placeholder="Address 2"></md-textarea>
1515
</p>
1616
<table style="width: 100%" cellspacing="0"><tr>
1717
<td><md-input class="demo-full-width" placeholder="City" value="Mountain View"></md-input></td>
@@ -39,22 +39,39 @@
3939
<md-card class="demo-card demo-basic">
4040
<md-toolbar color="primary">Divider Colors</md-toolbar>
4141
<md-card-content>
42+
<h4>Input</h4>
4243
<md-input dividerColor="primary" placeholder="Default Color" value="example"></md-input>
4344
<md-input dividerColor="accent" placeholder="Accent Color" value="example"></md-input>
4445
<md-input dividerColor="warn" placeholder="Warn Color" value="example"></md-input>
46+
47+
<h4>Textarea</h4>
48+
<md-textarea dividerColor="primary" placeholder="Default Color" value="example"></md-textarea>
49+
<md-textarea dividerColor="accent" placeholder="Accent Color" value="example"></md-textarea>
50+
<md-textarea dividerColor="warn" placeholder="Warn Color" value="example"></md-textarea>
51+
4552
</md-card-content>
4653
</md-card>
4754

4855
<md-card class="demo-card demo-basic">
4956
<md-toolbar color="primary">Hints</md-toolbar>
5057
<md-card-content>
58+
<h4>Input</h4>
5159
<p>
5260
<md-input placeholder="Character count (100 max)" maxLength="100" class="demo-full-width"
5361
value="Hello world. How are you?"
5462
#characterCountHintExample>
5563
<md-hint align="end">{{characterCountHintExample.characterCount}} / 100</md-hint>
5664
</md-input>
5765
</p>
66+
67+
<h4>Textarea</h4>
68+
<p>
69+
<md-textarea placeholder="Character count (100 max)" maxLength="100" class="demo-full-width"
70+
value="Hello world. How are you?"
71+
#characterCountHintExample>
72+
<md-hint align="end">{{characterCountHintExample.characterCount}} / 100</md-hint>
73+
</md-textarea>
74+
</p>
5875
</md-card-content>
5976
</md-card>
6077

src/demo-app/input/input-demo.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class InputDemo {
2121
{ value: 40 },
2222
{ value: 50 },
2323
];
24+
rows = 8;
2425

2526
addABunch(n: number) {
2627
for (let x = 0; x < n; x++) {

src/lib/input/README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# mdInput
1+
# mdInput / mdTextarea
22

33
Inputs are the basic input component of Material 2. The spec can be found [here](https://www.google.com/design/spec/components/text-fields.html).
44

55

66

77
## Notes
8-
* The `<md-input>` component fully support two-way binding of `ngModel`, as if it was a normal `<input>`.
8+
* The `<md-input>` / `<md-textara>` component fully support two-way binding of `ngModel`, as if it was a normal `<input>` and `<textarea>`.
99

1010

1111

@@ -18,7 +18,7 @@ The valid `type` attribute values are any supported by your browser, with the ex
1818

1919
## Placeholder
2020

21-
A placeholder is an indicative text displayed in the input zone when the input does not contain text. When text is present, the indicative text will float above this input zone.
21+
A placeholder is an indicative text displayed in the input zone when the input does not contain text. When text is present, the indicative text will float above this input zone.
2222

2323
You can set the `floatingPlaceholder` attribute to `false` to hide the indicative text instead when text is present in the input.
2424

@@ -106,6 +106,14 @@ export class MyComponent implements OnInit {
106106
}
107107
```
108108

109+
## Textareas
110+
111+
```html
112+
<md-textarea placeholder="Textarea with autosize"></md-textarea>
113+
```
114+
115+
### Example
116+
109117
## Full Forms
110118

111119
You can make a full form using inputs, and it will support autofill natively.
@@ -125,8 +133,8 @@ You can make a full form using inputs, and it will support autofill natively.
125133
<td><md-input placeholder="Long Last Name That Will Be Truncated" style="width: 100%"></md-input></td>
126134
</tr></table>
127135
<p>
128-
<md-input class="demo-full-width" placeholder="Address" value="1600 Amphitheatre Pkway"></md-input>
129-
<md-input class="demo-full-width" placeholder="Address 2"></md-input>
136+
<md-textarea class="demo-full-width" placeholder="Address" value="1600 Amphitheatre Pkway"></md-textarea>
137+
<md-textarea class="demo-full-width" placeholder="Address 2"></md-textarea>
130138
</p>
131139
<table style="width: 100%" cellspacing="0"><tr>
132140
<td><md-input class="demo-full-width" placeholder="City"></md-input></td>

src/lib/input/input.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
<div class="md-input-infix">
66
<input #input
7+
*ngIf="_elementType === 'input'"
78
class="md-input-element"
89
[class.md-end]="align == 'end'"
910
[attr.aria-label]="ariaLabel"
@@ -34,6 +35,37 @@
3435
[(ngModel)]="value"
3536
(change)="_handleChange($event)">
3637

38+
<textarea
39+
#input
40+
*ngIf="_elementType === 'textarea'"
41+
class="md-input-element md-input-element-textarea"
42+
[class.md-end]="align == 'end'"
43+
[attr.aria-label]="ariaLabel"
44+
[attr.aria-labelledby]="ariaLabelledBy"
45+
[attr.aria-disabled]="ariaDisabled"
46+
[attr.aria-required]="ariaRequired"
47+
[attr.aria-invalid]="ariaInvalid"
48+
[attr.autocomplete]="autocomplete"
49+
[attr.autocapitalize]="autocapitalize"
50+
[attr.cols]="cols"
51+
[attr.rows]="rows"
52+
[attr.wrap]="wrap"
53+
[autofocus]="autofocus"
54+
[disabled]="disabled"
55+
[id]="inputId"
56+
[attr.maxlength]="maxlength"
57+
[attr.minlength]="minlength"
58+
[readonly]="readonly"
59+
[required]="required"
60+
[spellcheck]="spellcheck"
61+
[attr.tabindex]="tabindex"
62+
[attr.name]="name"
63+
(focus)="_handleFocus($event)"
64+
(blur)="_handleBlur($event)"
65+
[(ngModel)]="value"
66+
(change)="_handleChange($event)"></textarea>
67+
68+
3769
<label class="md-input-placeholder"
3870
[attr.for]="inputId"
3971
[class.md-empty]="empty"

src/lib/input/input.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ $md-input-underline-disabled-background-image:
1515
width: 100% / $md-input-floating-placeholder-scale-factor;
1616
}
1717

18-
md-input {
18+
md-input, md-textarea {
1919
display: inline-block;
2020
position: relative;
2121
font-family: $md-font-family;

src/lib/input/input.spec.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ describe('MdInput', function () {
5757
MdInputTextTestController,
5858
MdInputPasswordTestController,
5959
MdInputNumberTestController,
60+
MdTextareaWithBindings,
6061
],
6162
});
6263

@@ -611,12 +612,28 @@ describe('MdInput', function () {
611612

612613
it('supports a name attribute', () => {
613614
let fixture = TestBed.createComponent(MdInputWithNameTestController);
615+
616+
fixture.detectChanges();
617+
614618
const inputElement: HTMLInputElement = fixture.debugElement.query(By.css('input'))
615619
.nativeElement;
616-
fixture.detectChanges();
617620

618621
expect(inputElement.name).toBe('some-name');
619622
});
623+
624+
describe('md-textarea', () => {
625+
it('supports the rows, cols, and wrap attributes', () => {
626+
let fixture = TestBed.createComponent(MdTextareaWithBindings);
627+
628+
fixture.detectChanges();
629+
630+
const textarea: HTMLTextAreaElement = fixture.nativeElement.querySelector('textarea');
631+
expect(textarea.rows).toBe(4);
632+
expect(textarea.cols).toBe(8);
633+
expect(textarea.wrap).toBe('hard');
634+
});
635+
});
636+
620637
});
621638

622639
@Component({template: `<md-input id="test-id"></md-input>`})
@@ -789,3 +806,11 @@ class MdInputPasswordTestController {
789806
class MdInputNumberTestController {
790807
placeholder: string = '';
791808
}
809+
810+
@Component({template:
811+
`<md-textarea [rows]="rows" [cols]="cols" [wrap]="wrap" placeholder="Snacks"></md-textarea>`})
812+
class MdTextareaWithBindings {
813+
rows: number = 4;
814+
cols: number = 8;
815+
wrap: string = 'hard';
816+
}

src/lib/input/input.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {Observable} from 'rxjs/Observable';
2626

2727
const noop = () => {};
2828

29+
2930
export const MD_INPUT_CONTROL_VALUE_ACCESSOR: any = {
3031
provide: NG_VALUE_ACCESSOR,
3132
useExisting: forwardRef(() => MdInput),
@@ -86,14 +87,13 @@ export class MdHint {
8687
@Input() align: 'start' | 'end' = 'start';
8788
}
8889

89-
9090
/**
9191
* Component that represents a text input. It encapsulates the <input> HTMLElement and
9292
* improve on its behaviour, along with styling it according to the Material Design.
9393
*/
9494
@Component({
9595
moduleId: module.id,
96-
selector: 'md-input',
96+
selector: 'md-input, md-textarea',
9797
templateUrl: 'input.html',
9898
styleUrls: ['input.css'],
9999
providers: [MD_INPUT_CONTROL_VALUE_ACCESSOR],
@@ -167,6 +167,11 @@ export class MdInput implements ControlValueAccessor, AfterContentInit, OnChange
167167
@Input() type: string = 'text';
168168
@Input() name: string = null;
169169

170+
// textarea-specific
171+
@Input() rows: number = null;
172+
@Input() cols: number = null;
173+
@Input() wrap: 'soft' | 'hard' = null;
174+
170175
private _floatingPlaceholder: boolean = true;
171176
private _autofocus: boolean = false;
172177
private _disabled: boolean = false;
@@ -229,6 +234,15 @@ export class MdInput implements ControlValueAccessor, AfterContentInit, OnChange
229234

230235
@ViewChild('input') _inputElement: ElementRef;
231236

237+
_elementType: 'input' | 'textarea';
238+
239+
constructor(elementRef: ElementRef) {
240+
// Set the element type depending on normalized selector used(md-input / md-textarea)
241+
this._elementType = elementRef.nativeElement.nodeName.toLowerCase() === 'md-input' ?
242+
'input' :
243+
'textarea';
244+
}
245+
232246
/** Set focus on input */
233247
focus() {
234248
this._inputElement.nativeElement.focus();

0 commit comments

Comments
 (0)