Skip to content

Commit e9f2efb

Browse files
committed
feat(md-input): add back placeholder as a portal directive
1 parent 9e80283 commit e9f2efb

File tree

12 files changed

+266
-38
lines changed

12 files changed

+266
-38
lines changed

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,43 @@
4949
</p>
5050
</md-card-content>
5151
</md-card>
52+
53+
<md-card class="demo-card demo-basic">
54+
<md-toolbar color="primary">Divider Colors</md-toolbar>
55+
<md-card-content>
56+
<h4>Input</h4>
57+
<input md-input dividerColor="primary" placeholder="Default Color">
58+
<input md-input dividerColor="accent" placeholder="Accent Color">
59+
<input md-input dividerColor="warn" placeholder="Warn Color">
60+
61+
<h4>Textarea</h4>
62+
<textarea md-textarea dividerColor="primary" placeholder="Default Color"></textarea>
63+
<textarea md-textarea dividerColor="accent" placeholder="Accent Color"></textarea>
64+
<textarea md-textarea dividerColor="warn" placeholder="Warn Color"></textarea>
65+
66+
</md-card-content>
67+
</md-card>
68+
69+
<md-card class="demo-card">
70+
<md-toolbar color="primary">Placeholder Templates</md-toolbar>
71+
72+
<md-card-content>
73+
<p>
74+
<input md-input [placeholder]="placeholderTemplate1">
75+
76+
<template #placeholderTemplate1>
77+
Example of a <b>placeholder</b> template
78+
</template>
79+
</p>
80+
81+
<p>
82+
<input md-input [placeholder]="placeholderTemplate2">
83+
<br/>
84+
Value: <input [(ngModel)]="value">
85+
86+
<template #placeholderTemplate2>
87+
Value: {{value}}
88+
</template>
89+
</p>
90+
</md-card-content>
91+
</md-card>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ let max = 5;
1010
styleUrls: ['input-demo.css'],
1111
})
1212
export class InputDemo {
13+
value: string = 'test';
1314
dividerColor: boolean;
1415
requiredField: boolean;
1516
floatingLabel: boolean;

src/lib/input/_input-theme.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
$input-underline-disabled-color: md-color($foreground, hint-text);
2222
$input-underline-focused-color: md-color($primary);
2323

24-
.md-input-placeholder {
24+
.md-placeholder {
2525
color: $input-placeholder-color;
2626

2727
// :focus is applied to the input, but we apply md-focused to the other elements
@@ -39,7 +39,7 @@
3939
}
4040

4141
// See md-input-placeholder-floating mixin in input.scss
42-
.md-input-wrapper input:-webkit-autofill + .md-input-placeholder, .md-input-placeholder.md-float.md-focused {
42+
.md-input-wrapper input:-webkit-autofill + .md-placeholder, .md-placeholder.md-float.md-focused {
4343

4444
.md-placeholder-required {
4545
color: $input-required-placeholder-color;

src/lib/input/index.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,27 @@
1+
import {CommonModule} from '@angular/common';
2+
import {ModuleWithProviders, NgModule} from '@angular/core';
3+
4+
import {ProjectionModule, PortalModule} from '../core';
5+
6+
import {MdInput} from './input';
7+
import {MdPlaceholder, MdPlaceholderContent} from './placeholder';
8+
9+
110
export * from './input';
11+
export * from './placeholder';
12+
13+
14+
@NgModule({
15+
declarations: [MdPlaceholderContent, MdPlaceholder, MdInput],
16+
imports: [PortalModule, ProjectionModule, CommonModule],
17+
exports: [MdPlaceholder, MdInput],
18+
entryComponents: [MdPlaceholderContent]
19+
})
20+
export class MdInputModule {
21+
static forRoot(): ModuleWithProviders {
22+
return {
23+
ngModule: MdInputModule,
24+
providers: []
25+
};
26+
}
27+
}

src/lib/input/input.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
<dom-projection-host></dom-projection-host>
1212
</div>
1313

14-
<div class="md-input-suffix"><template [ngTemplateOutlet]="_suffixTemplate()"></template></div>
14+
<div class="md-input-suffix">
15+
<template #suffixWrapper portalHost></template>
16+
<template [ngTemplateOutlet]="_suffixTemplate()"></template>
17+
</div>
1518
<template #suffix>{{mdSuffix}}</template>
1619
</div>
1720

src/lib/input/input.scss

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
@import '../core/style/form-common';
33

44

5-
$md-input-floating-placeholder-scale-factor: 0.75 !default;
5+
$md-floating-placeholder-scale-factor: 0.75 !default;
66

77
// Gradient for showing the dashed line when the input is disabled.
88
$md-input-underline-disabled-background-image:
99
linear-gradient(to right, rgba(0, 0, 0, 0.26) 0%, rgba(0, 0, 0, 0.26) 33%, transparent 0%);
1010

1111
// Applies a floating placeholder above the input itself.
12-
@mixin md-input-placeholder-floating {
12+
@mixin md-placeholder-floating {
1313
display: block;
1414
padding-bottom: 5px;
15-
transform: translateY(-100%) scale($md-input-floating-placeholder-scale-factor);
16-
width: 100% / $md-input-floating-placeholder-scale-factor;
15+
transform: translateY(-100%) scale($md-floating-placeholder-scale-factor);
16+
width: 100% / $md-floating-placeholder-scale-factor;
1717
}
1818

1919
.md-input-wrapper {
@@ -57,7 +57,7 @@ $md-input-underline-disabled-background-image:
5757
}
5858

5959
// The Input element proper.
60-
input[md-input], textarea[md-input] {
60+
input[md-input], textarea[md-textarea] {
6161
// Font needs to be inherited, because by default <input> has a system font.
6262
font: inherit;
6363

@@ -93,15 +93,15 @@ input[md-input], textarea[md-input] {
9393
// Once the autofill is committed, a change event happen and the regular md-input
9494
// classes take over to fulfill this behaviour.
9595
// Assumes the autofill is non-empty.
96-
&:-webkit-autofill + .md-input-placeholder.md-float {
97-
@include md-input-placeholder-floating;
96+
&:-webkit-autofill + .md-placeholder.md-float {
97+
@include md-placeholder-floating;
9898
}
9999
}
100100

101101
// The placeholder label. This is invisible unless it is. The logic to show it is
102102
// basically `empty || (float && (!empty || focused))`. Float is dependent on the
103103
// `floatingPlaceholder` input.
104-
.md-input-placeholder {
104+
.md-placeholder {
105105
// The placeholder is after the <input>, but needs to be aligned top-left of the
106106
// infix <div>.
107107
position: absolute;
@@ -133,7 +133,7 @@ input[md-input], textarea[md-input] {
133133

134134
// Show the placeholder above the input when it's not empty, or focused.
135135
&.md-float:not(.md-empty), &.md-float.md-focused {
136-
@include md-input-placeholder-floating;
136+
@include md-placeholder-floating;
137137
}
138138

139139
[dir='rtl'] & {

src/lib/input/input.spec.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
import {Component} from '@angular/core';
66
import {FormsModule} from '@angular/forms';
77
import {By} from '@angular/platform-browser';
8-
import {MdInput, MdInputModule} from './input';
8+
import {MdInput, MdInputModule} from './index';
99
import {ProjectionModule} from '../core/projection/projection';
1010

1111
describe('MdInput', function () {
@@ -34,8 +34,8 @@ describe('MdInput', function () {
3434
// TODO(kara): update when core/testing adds fix
3535
it('support ngModel', async(() => {
3636
let fixture = TestBed.createComponent(MdInputBaseTestController);
37-
3837
fixture.detectChanges();
38+
3939
let instance = fixture.componentInstance;
4040
let el: HTMLInputElement = fixture.debugElement.query(By.css('input')).nativeElement;
4141

@@ -61,8 +61,9 @@ describe('MdInput', function () {
6161

6262
it('counts characters', async(() => {
6363
let fixture = TestBed.createComponent(MdInputBaseTestController);
64-
let instance = fixture.componentInstance;
6564
fixture.detectChanges();
65+
66+
let instance = fixture.componentInstance;
6667
let inputInstance = fixture.debugElement.query(By.directive(MdInput)).componentInstance;
6768
expect(inputInstance.characterCount).toEqual(0);
6869

@@ -95,7 +96,6 @@ describe('MdInput', function () {
9596
expect(textarea.wrap).toBe('hard');
9697
});
9798
});
98-
9999
});
100100

101101
@Component({template: `<input md-input type="number" class="test-class" style="color: 123456">`})
@@ -107,6 +107,15 @@ class MdInputNumberTypeConservedTestComponent {
107107
value: number = 0;
108108
}
109109

110+
@Component({template: `<input md-input placeholder="string placeholder">`})
111+
class MdInputPlaceholderStringTestController { }
112+
113+
@Component({template: `
114+
<input md-input [placeholder]="p">
115+
<template #p>template placeholder</template>
116+
`})
117+
class MdInputPlaceholderTemplateTestController { }
118+
110119
@Component({template: `<input md-input type="file">`})
111120
class MdInputInvalidTypeTestController { }
112121

src/lib/input/input.ts

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,20 @@ import {
55
ViewChild,
66
ElementRef,
77
OnInit,
8-
NgModule,
9-
ModuleWithProviders,
108
ViewEncapsulation,
119
HostListener,
12-
TemplateRef,
10+
TemplateRef, forwardRef,
1311
} from '@angular/core';
14-
import {CommonModule} from '@angular/common';
1512
import {DomSanitizer, SafeStyle} from '@angular/platform-browser';
1613
import {
17-
ProjectionModule,
1814
DomProjection,
1915
DomProjectionHost,
2016
MdError,
2117
coerceBooleanProperty
2218
} from '../core';
19+
import {MD_PLACEHOLDER_HOST_TOKEN, MdPlaceholderHost} from './placeholder';
20+
import {PortalHost} from '../core/portal/portal';
21+
import {PortalHostDirective} from '../core/portal/portal-directives';
2322

2423

2524
export class MdInputUnsupportedTypeError extends MdError {
@@ -46,6 +45,9 @@ const MD_INPUT_INVALID_INPUT_TYPE = [
4645
templateUrl: 'input.html',
4746
styleUrls: ['input.css'],
4847
encapsulation: ViewEncapsulation.None,
48+
providers: [
49+
{ provide: MD_PLACEHOLDER_HOST_TOKEN, useExisting: forwardRef(() => MdInput) }
50+
],
4951
host: {
5052
// This is to remove the properties of the `input md-input` itself. We still want to use them
5153
// as an @Input though, so we use HostBinding.
@@ -54,10 +56,12 @@ const MD_INPUT_INVALID_INPUT_TYPE = [
5456
'attr.align': ''
5557
}
5658
})
57-
export class MdInput implements OnInit {
59+
export class MdInput implements OnInit, MdPlaceholderHost {
5860
@ViewChild(DomProjectionHost) _host: DomProjectionHost;
5961
@ViewChild('suffix') _suffix: TemplateRef<any>;
6062
@ViewChild('prefix') _prefix: TemplateRef<any>;
63+
64+
@ViewChild('suffixWrapper', { read: PortalHostDirective }) placeholderPortalHost: PortalHost;
6165
private _focused: boolean = false;
6266

6367
@Input('class') _cssClass: string = '';
@@ -122,7 +126,6 @@ export class MdInput implements OnInit {
122126
@Input() mdPrefix: string | TemplateRef<any>;
123127
@Input() mdSuffix: string | TemplateRef<any>;
124128

125-
126129
@HostListener('focus') _onFocus() {
127130
this._focused = true;
128131
}
@@ -134,18 +137,3 @@ export class MdInput implements OnInit {
134137
this._ref.nativeElement.focus();
135138
}
136139
}
137-
138-
139-
@NgModule({
140-
declarations: [MdInput],
141-
imports: [ProjectionModule, CommonModule],
142-
exports: [MdInput],
143-
})
144-
export class MdInputModule {
145-
static forRoot(): ModuleWithProviders {
146-
return {
147-
ngModule: MdInputModule,
148-
providers: []
149-
};
150-
}
151-
}

src/lib/input/placeholder.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<label class="md-placeholder"
2+
[attr.for]="placeholder?.inputId"
3+
[class.md-empty]="placeholder?.empty"
4+
[class.md-focused]="placeholder?._focused"
5+
[class.md-float]="placeholder?._floatingPlaceholder"
6+
[class.md-accent]="placeholder?.dividerColor == 'accent'"
7+
[class.md-warn]="placeholder?.dividerColor == 'warn'">
8+
<template [ngTemplateOutlet]="_template()"></template>
9+
<span class="md-placeholder-required" *ngIf="placeholder?._required">*</span>
10+
</label>
11+
12+
<template #stringTemplate>{{content}}</template>

src/lib/input/placeholder.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+

0 commit comments

Comments
 (0)