feat(material): early version of md-input

Closes #1753
This commit is contained in:
Jeremy Elbourn 2015-05-07 09:10:41 -07:00 committed by Misko Hevery
parent 31cbec0857
commit ad23921814
4 changed files with 152 additions and 17 deletions

View File

@ -1,17 +1,126 @@
import {Directive} from 'angular2/src/core/annotations_impl/annotations';
import {Directive, onAllChangesDone} from 'angular2/src/core/annotations_impl/annotations';
import {Attribute} from 'angular2/src/core/annotations_impl/di';
import {Parent} from 'angular2/src/core/annotations_impl/visibility';
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
// TODO(jelbourn): validation (will depend on Forms API).
// TODO(jelbourn): textarea resizing
// TODO(jelbourn): max-length counter
// TODO(jelbourn): placeholder property
@Directive({
selector: 'md-input-container input'
selector: 'md-input-container input',
events: ['mdChange', 'mdFocusChange'],
hostProperties: {
'yes': 'class.md-input'
},
hostListeners: {
'input': 'updateValue($event)',
'focus': 'setHasFocus(true)',
'blur': 'setHasFocus(false)'
}
})
export class MdInput {
constructor() {
value: string;
yes: boolean;
}
// Events emitted by this directive. We use these special 'md-' events to communicate
// to the parent MdInputContainer.
mdChange: EventEmitter;
mdFocusChange: EventEmitter;
constructor(
@Attribute('value') value: String,
@Parent() container: MdInputContainer) {
// TODO(jelbourn): Remove this when #1402 is done.
this.yes = true;
this.value = value == null ? '' : value;
this.mdChange = new EventEmitter();
this.mdFocusChange = new EventEmitter();
container.registerInput(this);
}
updateValue(event) {
this.value = event.target.value;
ObservableWrapper.callNext(this.mdChange, this.value);
}
setHasFocus(hasFocus: boolean) {
ObservableWrapper.callNext(this.mdFocusChange, hasFocus);
}
}
@Directive({
selector: 'md-input-container'
selector: 'md-input-container textarea',
events: ['mdChange', 'mdFocusChange'],
hostProperties: {
'yes': 'class.md-input'
},
hostListeners: {
'input': 'updateValue($event)',
'focus': 'setHasFocus(true)',
'blur': 'setHasFocus(false)'
}
})
export class MdTextarea extends MdInput {
constructor(
@Attribute('value') value: String,
@Parent() container: MdInputContainer) {
super(value, container);
}
}
@Directive({
selector: 'md-input-container',
lifecycle: [onAllChangesDone],
hostProperties: {
'inputHasValue': 'class.md-input-has-value',
'inputHasFocus': 'class.md-input-focused'
}
})
export class MdInputContainer {
// The MdInput or MdTextarea inside of this container.
_input: MdInput;
// Whether the input inside of this container has a non-empty value.
inputHasValue: boolean;
// Whether the input inside of this container has focus.
inputHasFocus: boolean;
constructor() {
this._input = null;
this.inputHasValue = false;
this.inputHasFocus = false;
}
onAllChangesDone() {
// Enforce that this directive actually contains a text input.
if (this._input == null) {
throw 'No <input> or <textarea> found inside of <md-input-container>';
}
}
/** Registers the child MdInput or MdTextarea. */
registerInput(input) {
if (this._input != null) {
throw 'Only one text input is allowed per <md-input-container>.';
}
this._input = input;
this.inputHasValue = input.value != '';
// Listen to input changes and focus events so that we can apply the appropriate CSS
// classes based on the input state.
ObservableWrapper.subscribe(input.mdChange, value => {
this.inputHasValue = value != '';
});
ObservableWrapper.subscribe(input.mdFocusChange, hasFocus => {
this.inputHasFocus = hasFocus
});
}
}

View File

@ -1,10 +1,43 @@
<style>@import "angular2_material/src/components/input/input.css";</style>
<div md-theme="default">
<style>
body {
max-width: 500px;
}
</style>
<div>
<h2>input demo</h2>
<h3>Normal input</h3>
<md-input-container>
<label>Name</label>
<input>
<input md-input>
</md-input-container>
<h3>Pre-filled value</h3>
<md-input-container>
<label>Favorite Framework</label>
<input value="Angular">
</md-input-container>
<h3>Disabled input</h3>
<md-input-container>
<label>ID Number</label>
<input disabled>
</md-input-container>
<h3>Disabled, pre-filled input</h3>
<md-input-container>
<label>Best TV show</label>
<input disabled value="Firefly">
</md-input-container>
<h3>textarea</h3>
<md-input-container>
<label>What I did on my summer vaccation</label>
<textarea></textarea>
</md-input-container>
</div>

View File

@ -4,12 +4,11 @@
<meta charset="UTF-8">
<title>ng-material input demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style> * { font-family: RobotoDraft, Roboto; } </style>
<style> * { font-family: RobotoDraft, Roboto; }
</style>
</head>
<body>
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -1,5 +1,5 @@
import {bootstrap} from 'angular2/angular2';
import {MdCheckbox} from 'angular2_material/src/components/checkbox/checkbox'
import {MdInputContainer, MdInput, MdTextarea} from 'angular2_material/src/components/input/input'
import {UrlResolver} from 'angular2/src/services/url_resolver';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
import {bind} from 'angular2/di';
@ -14,17 +14,11 @@ import {View} from 'angular2/src/core/annotations_impl/view';
})
@View({
templateUrl: './demo_app.html',
directives: [MdCheckbox]
directives: [MdInputContainer, MdInput, MdTextarea]
})
class DemoApp {
toggleCount: number;
constructor() {
this.toggleCount = 0;
}
increment() {
this.toggleCount++;
}
}