Как добавить" активный " класс, когда поле ввода не пустое
Я пытаюсь создать директиву 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>
результат, который я ожидаю, когда textfield не пуст
<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>
как я могу это сделать ?
Спасибо большое
6 ответов
вы можете создать директиву и ввести FormControlName
экземпляр для прослушивания изменений значений. И добавить или удалить метку активный класс при изменении значения.
директива
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>
вам не нужна никакая пользовательская директива для этого. Пример:
<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>
на самом деле существует более простая, встроенная угловая директива [класс.className] (см. мой предыдущий ответ), но если вы настаиваете на выполнении этого с помощью директивы, вот как я бы это сделал :
это ваши директивы makeactive.директива.ТС (не забудьте добавить его в ваше приложение.модуль.файл ТС в декларации):
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.деталь.HTML-код, вам нужно добавить директиву свойство элемента, к которому вы хотите применить класс (
<label>
элемент):<label [makeActive]="myInput">First Name</label>
-
тогда вам нужно объявить шаблон ссылочной переменной на ввода текста:
<input type="text" #myInput>
-
Вам также нужно зарегистрировать это событие" keyup "или" change", чтобы вызвать обнаружение угловых изменений (либо на размытие, либо на ключ вверх, как в моем предыдущем ответ):
<input type="text" #myInput (keyup)="true">
полный код шаблона:
<div class="md-form">
<input type="text" #myInput (keyup)="true">
<label [makeActive]="myInput">First Name</label>
</div>
самый простой способ быть с эталонная переменная шаблона (см. мой другой ответ для способа сделать это с помощью директивы):
-
определение эталонная переменная шаблона на вход элемент #myInput свойства
<input type="text" #myInput>
-
определите условную привязку свойства класса с помощью [класс.active]= " myInput.значение" с условием быть значением the #myInput элемент:
<label [class.active]="myInput.value" for="FirstName" >First Name</label>
-
определение (keyup) или (изменить) обработчик событий mock на элементе для запуска обнаружения угловых изменений.
-
событие"change" активирует класс на событии размытия элемента, тогда как (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>
Как упоминалось здесь, вам действительно не нужна отдельная директива для такой мелочи,но если вы этого хотите... хорошо, вот оно.
обновление
на самом деле, это можно сделать даже проще. Я обновил код.
app.модуль.ТС
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.деталь.ТС
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.деталь.в CSS
.active {
color: red;
}
app.деталь.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.директива.ТС
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) {
}
}