Skip to content

Commit ad23921

Browse files
jelbournmhevery
authored andcommitted
feat(material): early version of md-input
Closes angular#1753
1 parent 31cbec0 commit ad23921

File tree

4 files changed

+152
-17
lines changed

4 files changed

+152
-17
lines changed
Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,126 @@
1-
import {Directive} from 'angular2/src/core/annotations_impl/annotations';
1+
import {Directive, onAllChangesDone} from 'angular2/src/core/annotations_impl/annotations';
2+
import {Attribute} from 'angular2/src/core/annotations_impl/di';
3+
import {Parent} from 'angular2/src/core/annotations_impl/visibility';
4+
5+
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
6+
7+
// TODO(jelbourn): validation (will depend on Forms API).
8+
// TODO(jelbourn): textarea resizing
9+
// TODO(jelbourn): max-length counter
10+
// TODO(jelbourn): placeholder property
211

312
@Directive({
4-
selector: 'md-input-container input'
13+
selector: 'md-input-container input',
14+
events: ['mdChange', 'mdFocusChange'],
15+
hostProperties: {
16+
'yes': 'class.md-input'
17+
},
18+
hostListeners: {
19+
'input': 'updateValue($event)',
20+
'focus': 'setHasFocus(true)',
21+
'blur': 'setHasFocus(false)'
22+
}
523
})
624
export class MdInput {
7-
constructor() {
25+
value: string;
26+
yes: boolean;
827

28+
// Events emitted by this directive. We use these special 'md-' events to communicate
29+
// to the parent MdInputContainer.
30+
mdChange: EventEmitter;
31+
mdFocusChange: EventEmitter;
32+
33+
constructor(
34+
@Attribute('value') value: String,
35+
@Parent() container: MdInputContainer) {
36+
// TODO(jelbourn): Remove this when #1402 is done.
37+
this.yes = true;
38+
39+
this.value = value == null ? '' : value;
40+
this.mdChange = new EventEmitter();
41+
this.mdFocusChange = new EventEmitter();
42+
43+
container.registerInput(this);
44+
}
45+
46+
updateValue(event) {
47+
this.value = event.target.value;
48+
ObservableWrapper.callNext(this.mdChange, this.value);
49+
}
50+
51+
setHasFocus(hasFocus: boolean) {
52+
ObservableWrapper.callNext(this.mdFocusChange, hasFocus);
953
}
1054
}
1155

56+
@Directive({
57+
selector: 'md-input-container textarea',
58+
events: ['mdChange', 'mdFocusChange'],
59+
hostProperties: {
60+
'yes': 'class.md-input'
61+
},
62+
hostListeners: {
63+
'input': 'updateValue($event)',
64+
'focus': 'setHasFocus(true)',
65+
'blur': 'setHasFocus(false)'
66+
}
67+
})
68+
export class MdTextarea extends MdInput {
69+
constructor(
70+
@Attribute('value') value: String,
71+
@Parent() container: MdInputContainer) {
72+
super(value, container);
73+
}
74+
}
1275

1376
@Directive({
14-
selector: 'md-input-container'
77+
selector: 'md-input-container',
78+
lifecycle: [onAllChangesDone],
79+
hostProperties: {
80+
'inputHasValue': 'class.md-input-has-value',
81+
'inputHasFocus': 'class.md-input-focused'
82+
}
1583
})
1684
export class MdInputContainer {
85+
// The MdInput or MdTextarea inside of this container.
86+
_input: MdInput;
87+
88+
// Whether the input inside of this container has a non-empty value.
89+
inputHasValue: boolean;
90+
91+
// Whether the input inside of this container has focus.
92+
inputHasFocus: boolean;
93+
94+
constructor() {
95+
this._input = null;
96+
this.inputHasValue = false;
97+
this.inputHasFocus = false;
98+
}
99+
100+
onAllChangesDone() {
101+
// Enforce that this directive actually contains a text input.
102+
if (this._input == null) {
103+
throw 'No <input> or <textarea> found inside of <md-input-container>';
104+
}
105+
}
106+
107+
/** Registers the child MdInput or MdTextarea. */
108+
registerInput(input) {
109+
if (this._input != null) {
110+
throw 'Only one text input is allowed per <md-input-container>.';
111+
}
112+
113+
this._input = input;
114+
this.inputHasValue = input.value != '';
115+
116+
// Listen to input changes and focus events so that we can apply the appropriate CSS
117+
// classes based on the input state.
118+
ObservableWrapper.subscribe(input.mdChange, value => {
119+
this.inputHasValue = value != '';
120+
});
121+
122+
ObservableWrapper.subscribe(input.mdFocusChange, hasFocus => {
123+
this.inputHasFocus = hasFocus
124+
});
125+
}
17126
}
Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,43 @@
11
<style>@import "angular2_material/src/components/input/input.css";</style>
2-
<div md-theme="default">
2+
3+
<style>
4+
body {
5+
max-width: 500px;
6+
}
7+
</style>
8+
9+
<div>
310
<h2>input demo</h2>
411

12+
13+
<h3>Normal input</h3>
514
<md-input-container>
615
<label>Name</label>
7-
<input>
16+
<input md-input>
17+
</md-input-container>
18+
19+
<h3>Pre-filled value</h3>
20+
<md-input-container>
21+
<label>Favorite Framework</label>
22+
<input value="Angular">
23+
</md-input-container>
24+
25+
<h3>Disabled input</h3>
26+
<md-input-container>
27+
<label>ID Number</label>
28+
<input disabled>
29+
</md-input-container>
30+
31+
<h3>Disabled, pre-filled input</h3>
32+
<md-input-container>
33+
<label>Best TV show</label>
34+
<input disabled value="Firefly">
35+
</md-input-container>
36+
37+
<h3>textarea</h3>
38+
<md-input-container>
39+
<label>What I did on my summer vaccation</label>
40+
<textarea></textarea>
841
</md-input-container>
942

1043
</div>

modules/examples/src/material/input/index.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
<meta charset="UTF-8">
55
<title>ng-material input demo</title>
66
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
7-
<style> * { font-family: RobotoDraft, Roboto; } </style>
7+
<style> * { font-family: RobotoDraft, Roboto; }
8+
</style>
89
</head>
910
<body>
10-
1111
<demo-app>Loading...</demo-app>
12-
1312
$SCRIPTS$
1413
</body>
1514
</html>

modules/examples/src/material/input/index.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {bootstrap} from 'angular2/angular2';
2-
import {MdCheckbox} from 'angular2_material/src/components/checkbox/checkbox'
2+
import {MdInputContainer, MdInput, MdTextarea} from 'angular2_material/src/components/input/input'
33
import {UrlResolver} from 'angular2/src/services/url_resolver';
44
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
55
import {bind} from 'angular2/di';
@@ -14,17 +14,11 @@ import {View} from 'angular2/src/core/annotations_impl/view';
1414
})
1515
@View({
1616
templateUrl: './demo_app.html',
17-
directives: [MdCheckbox]
17+
directives: [MdInputContainer, MdInput, MdTextarea]
1818
})
1919
class DemoApp {
20-
toggleCount: number;
21-
2220
constructor() {
23-
this.toggleCount = 0;
24-
}
2521

26-
increment() {
27-
this.toggleCount++;
2822
}
2923
}
3024

0 commit comments

Comments
 (0)