输入字段不为空时如何添加 "Active" class
How to add "Active" class when input field is not empty
我正在尝试创建一个 Angular 4 指令,当文本字段不为空时,它将在标签上添加 class="active"
<div class="md-form">
<input appMdbInputInit type="text" name="" id="FirstName"
class="form-control" formControlName="firstName">
<label for="FirstName" >First Name</label>
</div>
当文本字段不为空时我期望的结果
<div class="md-form">
<input appMdbInputInit type="text" name="" id="FirstName"
class="form-control" formControlName="firstName">
<label class="Active" for="FirstName" >First Name</label>
</div>
我该怎么做?
非常感谢
您不需要任何自定义指令即可执行此操作。示例:
<form [formGroup]="group">
<input appMdbInputInit type="text" name="" id="FirstName"
class="form-control" formControlName="firstName">
<label [class.Active]="group.get('firstName').value.length" for="FirstName">First Name</label>
</form>
您可以使用 ngClass for this one created plunker.
<form [formGroup]="group">
<input appMdbInputInit type="text" name="" id="FirstName"
class="form-control" formControlName="firstName">
<label [ngClass]="{'active': group.get('firstName').value.length}" for="FirstName">First Name</label>
您可以创建指令并注入 FormControlName
实例来监听值的变化。并在值更改时添加或删除标签 active class。
指令
import { Directive, OnInit, OnDestroy, ElementRef } from '@angular/core';
import { FormControlName } from '@angular/forms';
import { Subscription } from 'rxjs/Subscription';
@Directive({
selector: '[setLabelActive]'
})
export class SetLabelActiveDirective implements OnDestroy {
valueSub: Subscription;
constructor(
private el: ElementRef,
private formControlName: FormControlName // Inject FormControlName
) {
}
ngOnInit() {
// Listen value changes
this.valueSub = this.formControlName.valueChanges.subscribe(value => {
// Get label
const inputId = this.el.nativeElement.getAttribute('id'),
label = document.querySelector(`label[for="${inputId}"]`);
// Toggle `active` class
if (label) {
label.classList.toggle('active', value);
}
});
}
ngOnDestroy() {
// Unlisten value changes
this.valueSub.unsubscribe();
}
}
用法
<form [formGroup]="myForm">
<div>
<input setLabelActive type="text" id="FirstName" formControlName="firstName">
<label for="FirstName">First Name</label>
</div>
</form>
正如其他人在这里提到的,对于这么小的东西,您真的不需要单独的指令,但是如果您想要那样...好的,就在这里。
更新
其实还可以做得更简单。我更新了代码。
app.module.ts
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';
import {AppMdbInputInitDirective} from './app-mdb-input-init.directive';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
AppMdbInputInitDirective
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
app.component.ts
import {Component} from '@angular/core';
import {FormBuilder, FormGroup} from '@angular/forms';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
formGroup: FormGroup;
activeFlag$: Observable<boolean>;
constructor(fb: FormBuilder) {
this.formGroup = fb.group({
firstName: fb.control('')
});
this.activeFlag$ = this.formGroup.get('firstName').valueChanges.map(v => !!v);
}
}
app.component.css
.active {
color: red;
}
app.component.html
<div class="md-form" [formGroup]="formGroup">
<input type="text" name="" id="FirstName" class="form-control" formControlName="firstName">
<label for="FirstName" [appMdbInputInit]="activeFlag$ | async" labelClassName="active">First Name</label>
</div>
最后,最有趣的部分 - app-mdb-input-init.directive.ts
import {Directive, ElementRef, Input, Renderer2} from '@angular/core';
@Directive({
selector: '[appMdbInputInit]'
})
export class AppMdbInputInitDirective {
@Input()
labelClassName: string;
@Input()
set appMdbInputInit(val: boolean) {
if (val) {
this.renderer.addClass(this.elementRef.nativeElement, this.labelClassName);
} else {
this.renderer.removeClass(this.elementRef.nativeElement, this.labelClassName);
}
}
constructor(private elementRef: ElementRef, private renderer: Renderer2) {
}
}
最简单的方法是使用 模板引用变量(有关使用指令执行此操作的方法,请参阅我的其他答案):
使用 #myInput[=47 在 input 元素上定义一个 模板引用变量 =] 属性
<input type="text" #myInput>
定义条件 class 属性 与 [class.active]="myInput.value" 绑定条件是 #myInput 元素的值:
<label [class.active]="myInput.value" for="FirstName" >First Name</label>
在要触发的元素上定义一个 (keyup) 或 (change) 模拟事件处理程序 Angular 变化检测。
"change" 事件将激活 class on 元素模糊事件,而
(keyup) 会在启动时启用它。这是你的选择
根据需要选择:
好了!
完整示例代码:
<div class="md-form">
<input type="text" #myInput (keyup)="true"
class="form-control" formControlName="firstName">
<label [class.active]="myInput.value" for="FirstName" >First Name</label>
</div>
实际上有一个更简单的内置 Angular 指令 [class.className](请参阅我之前的回答),但是如果您坚持要完成这是一个指令,这就是我的做法:
这是你的指令,makeactive.directive.ts(不要忘记将它作为声明添加到你的 app.module.ts 文件中):
import {Directive, ElementRef, Input, Renderer2} from '@angular/core';
@Directive({
selector: '[makeActive]'
})
export class ActiveDirective
{
input;
@Input() set makeActive(input) {
this.input = input;
}
ngDoCheck() {
let fn = (this.input && this.input.value) ? 'addClass' : 'removeClass';
this.renderer[fn](this.el.nativeElement, 'active');
}
constructor(private el: ElementRef, private renderer: Renderer2) {}
}
在您的模板 app.component.html 中,您需要将指令 属性 添加到要应用 class 到(<label>
元素):
<label [makeActive]="myInput">First Name</label>
然后需要在文本输入上声明一个模板引用变量:
<input type="text" #myInput>
您还需要注册它的 "keyup" 或 "change" 事件来触发 Angular 变化检测(无论是模糊还是按键,就像我之前答案):
<input type="text" #myInput (keyup)="true">
完整的模板代码:
<div class="md-form">
<input type="text" #myInput (keyup)="true">
<label [makeActive]="myInput">First Name</label>
</div>
我正在尝试创建一个 Angular 4 指令,当文本字段不为空时,它将在标签上添加 class="active"
<div class="md-form">
<input appMdbInputInit type="text" name="" id="FirstName"
class="form-control" formControlName="firstName">
<label for="FirstName" >First Name</label>
</div>
当文本字段不为空时我期望的结果
<div class="md-form">
<input appMdbInputInit type="text" name="" id="FirstName"
class="form-control" formControlName="firstName">
<label class="Active" for="FirstName" >First Name</label>
</div>
我该怎么做?
非常感谢
您不需要任何自定义指令即可执行此操作。示例:
<form [formGroup]="group">
<input appMdbInputInit type="text" name="" id="FirstName"
class="form-control" formControlName="firstName">
<label [class.Active]="group.get('firstName').value.length" for="FirstName">First Name</label>
</form>
您可以使用 ngClass for this one created plunker.
<form [formGroup]="group">
<input appMdbInputInit type="text" name="" id="FirstName"
class="form-control" formControlName="firstName">
<label [ngClass]="{'active': group.get('firstName').value.length}" for="FirstName">First Name</label>
您可以创建指令并注入 FormControlName
实例来监听值的变化。并在值更改时添加或删除标签 active class。
指令
import { Directive, OnInit, OnDestroy, ElementRef } from '@angular/core';
import { FormControlName } from '@angular/forms';
import { Subscription } from 'rxjs/Subscription';
@Directive({
selector: '[setLabelActive]'
})
export class SetLabelActiveDirective implements OnDestroy {
valueSub: Subscription;
constructor(
private el: ElementRef,
private formControlName: FormControlName // Inject FormControlName
) {
}
ngOnInit() {
// Listen value changes
this.valueSub = this.formControlName.valueChanges.subscribe(value => {
// Get label
const inputId = this.el.nativeElement.getAttribute('id'),
label = document.querySelector(`label[for="${inputId}"]`);
// Toggle `active` class
if (label) {
label.classList.toggle('active', value);
}
});
}
ngOnDestroy() {
// Unlisten value changes
this.valueSub.unsubscribe();
}
}
用法
<form [formGroup]="myForm">
<div>
<input setLabelActive type="text" id="FirstName" formControlName="firstName">
<label for="FirstName">First Name</label>
</div>
</form>
正如其他人在这里提到的,对于这么小的东西,您真的不需要单独的指令,但是如果您想要那样...好的,就在这里。
更新
其实还可以做得更简单。我更新了代码。
app.module.ts
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';
import {AppMdbInputInitDirective} from './app-mdb-input-init.directive';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
AppMdbInputInitDirective
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
app.component.ts
import {Component} from '@angular/core';
import {FormBuilder, FormGroup} from '@angular/forms';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
formGroup: FormGroup;
activeFlag$: Observable<boolean>;
constructor(fb: FormBuilder) {
this.formGroup = fb.group({
firstName: fb.control('')
});
this.activeFlag$ = this.formGroup.get('firstName').valueChanges.map(v => !!v);
}
}
app.component.css
.active {
color: red;
}
app.component.html
<div class="md-form" [formGroup]="formGroup">
<input type="text" name="" id="FirstName" class="form-control" formControlName="firstName">
<label for="FirstName" [appMdbInputInit]="activeFlag$ | async" labelClassName="active">First Name</label>
</div>
最后,最有趣的部分 - app-mdb-input-init.directive.ts
import {Directive, ElementRef, Input, Renderer2} from '@angular/core';
@Directive({
selector: '[appMdbInputInit]'
})
export class AppMdbInputInitDirective {
@Input()
labelClassName: string;
@Input()
set appMdbInputInit(val: boolean) {
if (val) {
this.renderer.addClass(this.elementRef.nativeElement, this.labelClassName);
} else {
this.renderer.removeClass(this.elementRef.nativeElement, this.labelClassName);
}
}
constructor(private elementRef: ElementRef, private renderer: Renderer2) {
}
}
最简单的方法是使用 模板引用变量(有关使用指令执行此操作的方法,请参阅我的其他答案):
使用 #myInput[=47 在 input 元素上定义一个 模板引用变量 =] 属性
<input type="text" #myInput>
定义条件 class 属性 与 [class.active]="myInput.value" 绑定条件是 #myInput 元素的值:
<label [class.active]="myInput.value" for="FirstName" >First Name</label>
在要触发的元素上定义一个 (keyup) 或 (change) 模拟事件处理程序 Angular 变化检测。
"change" 事件将激活 class on 元素模糊事件,而 (keyup) 会在启动时启用它。这是你的选择 根据需要选择:
好了!
完整示例代码:
<div class="md-form">
<input type="text" #myInput (keyup)="true"
class="form-control" formControlName="firstName">
<label [class.active]="myInput.value" for="FirstName" >First Name</label>
</div>
实际上有一个更简单的内置 Angular 指令 [class.className](请参阅我之前的回答),但是如果您坚持要完成这是一个指令,这就是我的做法:
这是你的指令,makeactive.directive.ts(不要忘记将它作为声明添加到你的 app.module.ts 文件中):
import {Directive, ElementRef, Input, Renderer2} from '@angular/core';
@Directive({
selector: '[makeActive]'
})
export class ActiveDirective
{
input;
@Input() set makeActive(input) {
this.input = input;
}
ngDoCheck() {
let fn = (this.input && this.input.value) ? 'addClass' : 'removeClass';
this.renderer[fn](this.el.nativeElement, 'active');
}
constructor(private el: ElementRef, private renderer: Renderer2) {}
}
在您的模板 app.component.html 中,您需要将指令 属性 添加到要应用 class 到(
<label>
元素):<label [makeActive]="myInput">First Name</label>
然后需要在文本输入上声明一个模板引用变量:
<input type="text" #myInput>
您还需要注册它的 "keyup" 或 "change" 事件来触发 Angular 变化检测(无论是模糊还是按键,就像我之前答案):
<input type="text" #myInput (keyup)="true">
完整的模板代码:
<div class="md-form">
<input type="text" #myInput (keyup)="true">
<label [makeActive]="myInput">First Name</label>
</div>