英文:
How can i create reusable input field in Angular?
问题
我正在尝试创建一个可重复使用的字段,就像我们在react
中所做的那样。但我未能成功。我需要一些建议或指导来解决我的问题。实际上,我创建了一个包含输入字段的组件。现在我想在Angular表单中的任何地方使用该字段。请帮助我解决这个问题。
每当我尝试提交时,它总是返回undefined。
任何解决方案都会受到欢迎!
登录表单
<Modal [isOpen]="true" title="Login" actionLabel="Sign in" [onSubmit]="handleSubmit">
<form [formGroup]="loginForm">
<div class="flex flex-col gap-4">
<app-input placeholder="Email" type="email" controlName="email"
(formControlChange)="handleFormControl('email',$event)" />
<app-input placeholder="Password" type="password" controlName="password"
(formControlChange)="handleFormControl('password',$event)" />
</div>
</form>
</Modal>
export class LoginModalComponent implements OnInit {
loginForm!: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.loginForm = this.fb.group({
email: new FormControl(''),
password: new FormControl('')
})
}
handleFormControl(formControlName: string, formControl: FormControl) {
this.loginForm.setControl(formControlName, formControl);
}
handleSubmit(): void {
console.log(this.loginForm);
}
}
输入组件
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-input',
template: `
<input
[placeholder]="placeholder"
[formControl]="formControl"
class="
w-full
p-4
text-lg
bg-black
border-2
border-neutral-800
rounded-md
outline-none
text-white
focus:border-sky-500
focus:border-2
transition
disabled:bg-neutral-900
disabled:opacity-70
disabled:cursor-not-allowed
"
[type]="type"
>
`,
styles: [
]
})
export class InputComponent implements OnInit {
@Input('placeholder') placeholder: string = '';
@Input('controlName') controlName: string = '';
@Input('type') type: string = 'text';
@Input() required: boolean = false;
@Input() email: boolean = false;
@Output() formControlChange = new EventEmitter<FormControl>();
formControl!: FormControl;
ngOnInit(): void {
this.initializeFormControl()
this.subscribeToValueChange()
}
initializeFormControl(): void {
const validators = [];
if (this.required) {
validators.push(Validators.required)
}
if (this.email) {
validators.push(Validators.email);
}
this.formControl = new FormControl('', validators);
}
subscribeToValueChange(): void {
this.formControl.valueChanges.subscribe((value) => {
this.formControlChange.emit(this.formControl);
})
}
}
英文:
I am trying to create a reusable field as we do in react
. But I failed to do that. I need some suggestions or guidance to fix my issue. Actually, I created a component that holds the input field. Now I want to use that field everywhere in the Angular forms. Please help me to fix this.
>Whenever i try to submit it always return undefined.
Any solution appreciated!
Login Form
<Modal [isOpen]="true" title="Login" actionLabel="Sign in" [onSubmit]="handleSubmit">
<form [formGroup]="loginForm">
<div class="flex flex-col gap-4">
<app-input placeholder="Email" type="email" controlName="email"
(formControlChange)="handleFormControl('email',$event)" />
<app-input placeholder="Password" type="password" controlName="password"
(formControlChange)="handleFormControl('password',$event)" />
</div>
</form>
</Modal>
export class LoginModalComponent implements OnInit {
loginForm!: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.loginForm = this.fb.group({
email: new FormControl(''),
password: new FormControl('')
})
}
handleFormControl(formControlName: string, formControl: FormControl) {
this.loginForm.setControl(formControlName, formControl);
}
handleSubmit(): void {
console.log(this.loginForm);
}
}
Input Component
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-input',
template: `
<input
[placeholder]="placeholder"
[formControl]="formControl"
class="
w-full
p-4
text-lg
bg-black
border-2
border-neutral-800
rounded-md
outline-none
text-white
focus:border-sky-500
focus:border-2
transition
disabled:bg-neutral-900
disabled:opacity-70
disabled:cursor-not-allowed
"
[type]="type"
>
`,
styles: [
]
})
export class InputComponent implements OnInit {
@Input('placeholder') placeholder: string = '';
@Input('controlName') controlName: string = '';
@Input('type') type: string = 'text';
@Input() required: boolean = false;
@Input() email: boolean = false;
@Output() formControlChange = new EventEmitter<FormControl>();
formControl!: FormControl;
ngOnInit(): void {
this.initializeFormControl()
this.subscribeToValueChange()
// this.formControlChange.emit(this.formControl);
}
initializeFormControl(): void {
const validators = [];
if (this.required) {
validators.push(Validators.required)
}
if (this.email) {
validators.push(Validators.email);
}
this.formControl = new FormControl('', validators);
}
subscribeToValueChange(): void {
this.formControl.valueChanges.subscribe((value) => {
this.formControlChange.emit(this.formControl);
})
}
}
答案1
得分: 1
你的代码中我看不到 "submit" 部分。但你的代码也能正常工作。这是主要组件:
import 'zone.js/dist/zone';
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { InputComponent } from './input/input.component';
@Component({
selector: 'my-app',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, FormsModule, InputComponent],
template: `
<h1>Hello from {{name}}!</h1>
<a target="_blank" href="https://angular.io/start">
Learn more about Angular
</a>
<form [formGroup]="loginForm" (ngSubmit)="handleSubmit()">
<div class="flex flex-col gap-4">
<app-input placeholder="Email" type="email" controlName="email"
(formControlChange)="handleFormControl('email',$event)" />
<app-input placeholder="Password" type="password" controlName="password"
(formControlChange)="handleFormControl('password',$event)" />
</div>
<button>SUBMIT</button>
</form>
`,
})
export class App implements OnInit {
name = 'Angular';
loginForm!: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.loginForm = this.fb.group({
email: new FormControl(''),
password: new FormControl('')
})
}
handleFormControl(formControlName: string, formControl: FormControl) {
this.loginForm.setControl(formControlName, formControl);
}
handleSubmit(): void {
console.log(this.loginForm.value);
}
}
bootstrapApplication(App);
这是输入组件:
import { CommonModule } from '@angular/common';
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-input',
template: `
<input
[placeholder]="placeholder"
[formControl]="formControl"
class="
w-full
p-4
text-lg
bg-black
border-2
border-neutral-800
rounded-md
outline-none
text-white
focus:border-sky-500
focus:border-2
transition
disabled:bg-neutral-900
disabled:opacity-70
disabled:cursor-not-allowed
"
[type]="type"
>
`,
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
styles: [
]
})
export class InputComponent implements OnInit {
@Input('placeholder') placeholder: string = '';
@Input('controlName') controlName: string = '';
@Input('type') type: string = 'text';
@Input() required: boolean = false;
@Input() email: boolean = false;
@Output() formControlChange = new EventEmitter<FormControl>();
formControl!: FormControl;
ngOnInit(): void {
this.initializeFormControl()
this.subscribeToValueChange()
}
initializeFormControl(): void {
const validators = [];
if (this.required) {
validators.push(Validators.required)
}
if (this.email) {
validators.push(Validators.email);
}
this.formControl = new FormControl('', validators);
}
subscribeToValueChange(): void {
this.formControl.valueChanges.subscribe((value) => {
this.formControlChange.emit(this.formControl);
})
}
}
我只添加了 (ngSubmit)
并更改了 handleSubmit()
来打印 value。在 Stackblitz 上尝试并告诉我是否有任何问题。
英文:
In your code I see no "submit" part. But your code work as well. This is the main component:
import 'zone.js/dist/zone';
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { InputComponent } from './input/input.component';
@Component({
selector: 'my-app',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, FormsModule, InputComponent],
template: `
<h1>Hello from {{name}}!</h1>
<a target="_blank" href="https://angular.io/start">
Learn more about Angular
</a>
<form [formGroup]="loginForm" (ngSubmit)="handleSubmit()">
<div class="flex flex-col gap-4">
<app-input placeholder="Email" type="email" controlName="email"
(formControlChange)="handleFormControl('email',$event)" />
<app-input placeholder="Password" type="password" controlName="password"
(formControlChange)="handleFormControl('password',$event)" />
</div>
<button>SUBMIT</button>
</form>
`,
})
export class App implements OnInit {
name = 'Angular';
loginForm!: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.loginForm = this.fb.group({
email: new FormControl(''),
password: new FormControl('')
})
}
handleFormControl(formControlName: string, formControl: FormControl) {
this.loginForm.setControl(formControlName, formControl);
}
handleSubmit(): void {
console.log(this.loginForm.value);
}
}
bootstrapApplication(App);
And this the input component:
import { CommonModule } from '@angular/common';
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-input',
template: `
<input
[placeholder]="placeholder"
[formControl]="formControl"
class="
w-full
p-4
text-lg
bg-black
border-2
border-neutral-800
rounded-md
outline-none
text-white
focus:border-sky-500
focus:border-2
transition
disabled:bg-neutral-900
disabled:opacity-70
disabled:cursor-not-allowed
"
[type]="type"
>
`,
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
styles: [
]
})
export class InputComponent implements OnInit {
@Input('placeholder') placeholder: string = '';
@Input('controlName') controlName: string = '';
@Input('type') type: string = 'text';
@Input() required: boolean = false;
@Input() email: boolean = false;
@Output() formControlChange = new EventEmitter<FormControl>();
formControl!: FormControl;
ngOnInit(): void {
this.initializeFormControl()
this.subscribeToValueChange()
// this.formControlChange.emit(this.formControl);
}
initializeFormControl(): void {
const validators = [];
if (this.required) {
validators.push(Validators.required)
}
if (this.email) {
validators.push(Validators.email);
}
this.formControl = new FormControl('', validators);
}
subscribeToValueChange(): void {
this.formControl.valueChanges.subscribe((value) => {
this.formControlChange.emit(this.formControl);
})
}
}
I have only added the (ngSubmit)
and changed the handleSubmit()
to print the value. Try it on Stackblitz and tell me if anything goes wrong.
答案2
得分: 1
你可以使用 NG_VALUE_ACCESSOR 实现来创建可重用的自定义表单控件组件。
示例链接:https://stackblitz.com/edit/angular-module-4xcvpm?file=src%2Fapp%2Fmodel.compoennt.ts
input.component.ts
import { Component, Input, forwardRef, OnInit } from '@angular/core';
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
Validators,
FormControl,
ValidatorFn,
} from '@angular/forms';
@Component({
selector: 'app-input',
template: `
<input
[placeholder]="placeholder"
[formControl]="formControl"
class="
w-full
p-4
text-lg
bg-black
border-2
border-neutral-800
rounded-md
outline-none
text-white
focus:border-sky-500
focus:border-2
transition
disabled:bg-neutral-900
disabled:opacity-70
disabled:cursor-not-allowed
"
[type]="type"
>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputComponent),
multi: true,
},
],
styles: [],
})
export class InputComponent implements OnInit, ControlValueAccessor {
@Input('placeholder') placeholder: string = '';
@Input('type') type: string = 'text';
@Input() required: boolean = false;
@Input() email: boolean = false;
formControl!: FormControl;
onTouched: any;
onChange: any;
ngOnInit(): void {
const validators: ValidatorFn[] = [];
if (this.required) {
validators.push(Validators.required);
}
if (this.email) {
validators.push(Validators.email);
}
this.formControl = new FormControl('', validators);
}
writeValue(value: any): void {
this.formControl.setValue(value);
}
registerOnChange(fn: any): void {
this.onChange = fn;
this.formControl.valueChanges.subscribe(fn);
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
isDisabled ? this.formControl.disable() : this.formControl.enable();
}
}
login-modal.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-login-modal',
template: `
<Modal [isOpen]="true" title="Login" actionLabel="Sign in" (submit)="handleSubmit()">
<form [formGroup]="loginForm">
<div class="flex flex-col gap-4">
<app-input placeholder="Email" type="email" required="true" email="true" formControlName="email"></app-input>
<app-input placeholder="Password" type="password" required="true" formControlName="password"></app-input>
</div>
</form>
</Modal>
`,
styles: [],
})
export class LoginModalComponent implements OnInit {
loginForm!: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.loginForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', Validators.required],
});
this.loginForm.get('email')!.valueChanges.subscribe((value) => {
console.log('email value changed:', value);
});
this.loginForm.get('password')!.valueChanges.subscribe((value) => {
console.log('password value changed:', value);
});
}
handleSubmit(): void {
console.log('hello');
console.log(this.loginForm.value);
}
}
modal.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'Modal',
template: `
<div *ngIf="isOpen" class="modal">
<h2>{{ title }}</h2>
<ng-content></ng-content>
<button (click)="submit.emit()">{{ actionLabel }}</button>
</div>
`,
})
export class ModalComponent {
@Input() isOpen: boolean = false;
@Input() title: string = '';
@Input() actionLabel: string = '';
@Output() submit = new EventEmitter<void>();
}
英文:
You can use NG_VALUE_ACCESSOR implementation for reusable custom form control components
demo : https://stackblitz.com/edit/angular-module-4xcvpm?file=src%2Fapp%2Fmodel.compoennt.ts
input.component.ts
import { Component, Input, forwardRef, OnInit } from '@angular/core';
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
Validators,
FormControl,
ValidatorFn,
} from '@angular/forms';
@Component({
selector: 'app-input',
template: `
<input
[placeholder]="placeholder"
[formControl]="formControl"
class="
w-full
p-4
text-lg
bg-black
border-2
border-neutral-800
rounded-md
outline-none
text-white
focus:border-sky-500
focus:border-2
transition
disabled:bg-neutral-900
disabled:opacity-70
disabled:cursor-not-allowed
"
[type]="type"
>`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputComponent),
multi: true,
},
],
styles: [],
})
export class InputComponent implements OnInit, ControlValueAccessor {
@Input('placeholder') placeholder: string = '';
@Input('type') type: string = 'text';
@Input() required: boolean = false;
@Input() email: boolean = false;
formControl!: FormControl;
onTouched: any;
onChange: any;
ngOnInit(): void {
const validators: ValidatorFn[] = [];
if (this.required) {
validators.push(Validators.required);
}
if (this.email) {
validators.push(Validators.email);
}
this.formControl = new FormControl('', validators);
}
writeValue(value: any): void {
this.formControl.setValue(value);
}
registerOnChange(fn: any): void {
this.onChange = fn;
this.formControl.valueChanges.subscribe(fn);
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
isDisabled ? this.formControl.disable() : this.formControl.enable();
}
}
login-modal.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-login-modal',
template: `
<Modal [isOpen]="true" title="Login" actionLabel="Sign in" (submit)="handleSubmit()">
<form [formGroup]="loginForm">
<div class="flex flex-col gap-4">
<app-input placeholder="Email" type="email" required="true" email="true" formControlName="email"></app-input>
<app-input placeholder="Password" type="password" required="true" formControlName="password"></app-input>
</div>
</form>
</Modal>
`,
styles: [],
})
export class LoginModalComponent implements OnInit {
loginForm!: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.loginForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', Validators.required],
});
this.loginForm.get('email')!.valueChanges.subscribe((value) => {
console.log('email value changed:', value);
});
this.loginForm.get('password')!.valueChanges.subscribe((value) => {
console.log('password value changed:', value);
});
}
handleSubmit(): void {
console.log('heloo');
console.log(this.loginForm.value);
}
}
modal.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'Modal',
template: `
<div *ngIf="isOpen" class="modal">
<h2>{{ title }}</h2>
<ng-content></ng-content>
<button (click)="submit.emit()">{{ actionLabel }}</button>
</div>
`,
})
export class ModalComponent {
@Input() isOpen: boolean = false;
@Input() title: string = '';
@Input() actionLabel: string = '';
@Output() submit = new EventEmitter<void>();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论