我对Angular很新,我正在尝试使用Angular和Bootstrap 4创建注册表单。
我想要的结果是使用Bootstrap的样式和Angular的验证。 更准确地说,在验证表单时,Angular在两个不同的位置应用样式(ng-valid,ng-invalid等):input元素和表单元素。
两个问题:
1)由于Bootstrap使用'has-danger'和'has-success'而不是'ng- [in] valid',是否可以配置angular来使用这些样式而不是默认样式。目前,我正在考虑通过添加角度样式来扩展引导程序(使用@extend has-danger / success)
2)Angular将样式应用于输入和表单元素,而bootstrap则在form-group元素上使用它。是否可以将角度放在那里而不是输入元素(或两者?)
我正在使用反应形式,我想避免像(未经测试)这样的事情:
mtcars$condition <- with(mtcars, ifelse(cyl < 6, 1, 0))
ggplot(mtcars, aes(x=qsec, y=hp, color= factor(carb))) +
geom_point() +
geom_point(data = subset(mtcars, condition == 1), color = "green") +
scale_colour_brewer( type = "seq", palette = "Reds") +
theme_bw()
有没有一种简单的方法(不是太冗长)实现这个目标?
答案 0 :(得分:18)
如果您正在使用SASS,则无需重写所有CSS即可执行以下操作。
.ng-touched.ng-invalid {
@extend .is-invalid;
}
注意:您需要导入引导程序作为SASS构建的一部分,而不是直接引用它。
如果您不使用SASS,那么安装起来就会看到这里 Angular CLI SASS options
答案 1 :(得分:8)
另一个选择是这个指令:
import {Directive, HostBinding, Self} from '@angular/core';
import {NgControl} from '@angular/forms';
@Directive({
selector: '[formControlName],[ngModel],[formControl]',
})
export class BootstrapValidationCssDirective {
constructor(@Self() private cd: NgControl) {}
@HostBinding('class.is-invalid')
get isInvalid(): boolean {
const control = this.cd.control;
return control ? control.invalid && control.touched : false;
}
}
如果字段被触摸或无效,它只会将is-invalid
类添加到每个字段。它基本上与Oliver的SASS解决方案相同,但是在没有SASS的情况下可以使用,并且可能还有较小的编译输出。
答案 2 :(得分:1)
在查看角度文档时,我遇到的最好的想法是使用指令。 我的实现仅适用于Reactive表单,如果要应用该样式的元素包含表单控件(如果使用bootstrap则为该情况)。应该扩展以与select和textarea兼容。
import { Directive, ElementRef, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms'
@Directive({ selector: '[formValidationStyle]' })
export class FormValidationStyleDirective implements OnInit {
@Input('formValidationStyle') private formGroup: FormGroup;
private component: FormControl;
static VALID_STYLE: string = 'has-success';
static INVALID_STYLE: string = 'has-danger';
constructor(private el: ElementRef) { }
ngOnInit(): void {
let componentName: string;
let inputElement = this.el.nativeElement.querySelector('input');
if (inputElement) {
componentName = inputElement.getAttribute('formControlName');
}
if (!componentName) {
console.error('FormValidationStyleDirective: Unable to get the control name. Is the formControlName attribute set correctly?')
return;
}
let control = this.formGroup.get(componentName)
if (!(control instanceof FormControl)) {
console.error(`FormValidationStyleDirective: Unable to get the FormControl from the form and the control name: ${componentName}.`)
return;
}
this.component = control as FormControl;
this.component.statusChanges.subscribe((status) => {
this.onStatusChange(status);
});
this.onStatusChange(this.component.status);
}
onStatusChange(status: string): void {
let cl = this.el.nativeElement.classList;
if (status == 'VALID') {
cl.add(FormValidationStyleDirective.VALID_STYLE)
cl.remove(FormValidationStyleDirective.INVALID_STYLE)
} else if (status == 'INVALID') {
cl.add(FormValidationStyleDirective.INVALID_STYLE)
cl.remove(FormValidationStyleDirective.VALID_STYLE)
}
}
}
示例:
组件:
@Component({
selector: 'security-register',
templateUrl: './register.component.html'
})
export class RegisterComponent {
registerForm: FormGroup;
constructor(private http: Http, private fb: FormBuilder) {
this.registerForm = this.fb.group({
username: ['', Validators.required]
});
}
}
及其模板:
<form [formGroup]="registerForm" novalidate>
<div class="form-group" [formValidationStyle]="registerForm">
<label class="form-control-label" for="dbz-register-username">Login</label>
<input formControlName="username" type="text" class="form-control" id="dbz-register-username" required>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Register</button>
</div>
</form>