[x] feature request
ãªã¢ã¯ãã£ããã©ãŒã ã¯è€éãªãã©ãŒã ã§äœ¿çšããããšãç®çãšããŠããŸãããã³ã³ãããŒã«ã®valueChanges
ã¯Observable<any>
ã§ãããè€éãªã³ãŒãã®ã°ãããã©ã¯ãã£ã¹ã«å®å
šã«åããŠããŸãã
匷ãåä»ãããããã©ãŒã ã³ã³ãããŒã«ãäœæããæ¹æ³ãããã¯ãã§ãã
é¢é£ïŒ11279
ããã¯ïŒ11279ãšã¯é¢ä¿ãããŸããã
ãããã©ã®ããã«é¢é£ããŠããªãã説æããŠãã ããã
ããªããæãã®ã¯ãæœè±¡å¶åŸ¡ãäžè¬çãªæš©å©ã§ãããšããããšã§ããïŒ ããããvalueChangesãObservable<any>
以å€ã®åãæã€ããšãã§ããå¯äžã®æ¹æ³ã§ãããåãæšæž¬ããä»ã®æ¹æ³ã¯ãããŸããã
ããã¯ãŸãã«ïŒ5404ãæ±ããŠããããšã§ãããããã¯ïŒ11279ã«é¢é£ããŠããããšãæå³ããŸã
AbstractControlããžã§ããªãã¯ã«ããããšãªããããå®è£
ã§ããå¥ã®æ¹æ³ãããå Žåã¯ãããã説æããŠãã ããã
ïŒ11279ã®ããã«get<Type>
ã䜿çšããããšã¯ãæããã«ééã£ã解決çã§ãã TypeScriptã«JavaUnbounded Wildcardã®ãããªãã®ãããå Žåã get
ã¯ããã䜿çšãã any
ã¯äœ¿çšããŸããã ãã¶ãã空ã®ã€ã³ã¿ãŒãã§ã€ã¹ã§åãæ¹æ³ã§äœããè¡ãããšãã§ããŸããïŒ
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html keyof
ããããŸãã TypeScript 2.1ã®æ©èœã¯ã匷ãåä»ãããããã©ãŒã ã³ã³ãããŒã«ãå®è£
ããããã«ç 究ããã®ã«éåžžã«èå³æ·±ããããããŸããã
æ®å¿µãªãããçŸåšã®ããã«å€§ããªã¢ããªã«äœ¿ãããšã¯æããªãã®ã§ããã®äžã«äœãããã¶ã€ã³ããå¿ èŠããããŸãã
TS 2.2ïŒhttps://github.com/Microsoft/TypeScript/wiki/Roadmap#22-february-2017ïŒã§ãããã©ã«ãã®ãžã§ããªãã¯åïŒhttps://github.com/Microsoft/TypeScript/ïŒãèšç»ããŠããããšã«æ°ã¥ããŸãããæã
ã¯ããããããåé¡/ 2175ïŒã¯ãç§ã¯ç§ãã¡ãäœãããšãã§ããã®ã§ããã®åé¡ãåæ€èšããããšããå§ããããããªããšæãAbstractControl
ã®ãããªäžè¬çãªAbstractControl<T = any>
ãšããT
ã¿ã€ãã§ãvalueChanges
ã«ãã£ãŠè¿ãããå€ãããã¯Observable<T>
ãŸãã ããã¯å€§èŠæš¡ãªé倧ãªå€æŽã«ãªããããçŸåšãããè¡ãã®ã¯è¯ãèãã§ã¯ãããŸããããããã©ã«ãã®ãžã§ããªãã¯ã§ã¯ã誀解ããªãéããé倧ãªå€æŽã«ã¯ãªããŸããã
ããã«é¢ããå°ããªæŽæ°ã¯ãããã©ã«ãã®ãžã§ããªãã¯ãTS2.3ã«ç§»åããããã
ããã©ã«ãã®ãžã§ããªãã¯åã䜿çšããTypeScript2.3ã¯ãã§ã«ããã«ãããŸãããAngularã§ã®TS 2.3ã®ãµããŒãã®æºåãæŽãäºå®ã¯ãããŸããïŒ
@desferoã¯ãã«ããTS2.3ã«ã¢ããã°ã¬ãŒããããã®ãïŒ16707ã§åŸ æ©ããŠããŸã
+1ã¯ãã®æ©èœãèŠãããšæã£ãŠããŸãã 誰ããããã«åãçµãã§ããŸããïŒ
çŸåšhttps://github.com/Microsoft/TypeScript/issues/16229ã§ãããã¯ãããŠã
ããã¯åœ¹ã«ç«ã€ãããããŸãã
ããã«é¢ããå°ããªæŽæ°ïŒ
ããã§ã®ç§ã®ã³ã¡ã³ãã«ãããšïŒ https ïŒ
ãžã§ããªãã¯ã¹ãçŸåšã®FormsAPIã«å®è£
ããã«ã¯ãå€æŽãå ããå¿
èŠããããŸãã
ãããã£ãŠãããããã®é倧ãªå€æŽãå¿
èŠã§ã
ãŸãã¯å®å
šãªãã©ãŒã ã®æžãçŽã
ã ããç§ã®åã®ã³ã¡ã³ãã¯ééã£ãŠããããšãããããŸããã
ããã«è¡šç€ºãããŠããããã«ãçŸåšã®Forms APIã«ãããå®è£
ã§ããŸããïŒ20040
@Toxicableã¯ãå®å šã«ãªãã¡ã¯ã¿ãªã³ã°ããæ©èœãäžè¶³ããŠãããšããåé¡ããããŸãã ããšãã°ãgetïŒ 'person'ïŒã¯ãå®éã«ã¯ã·ã³ãã«èªäœã䜿çšããŠããŸããã äžèšã®@rpbeukesã®äŸã§ã¯ãåºæ¬çã«ãªããžã§ã¯ãã·ã³ãã«ã䜿çšããããã«æ¹è¯ãããŠããŸãã æååã䜿çšããã«getïŒobj.personïŒã ããã¯ããªã¿ãŒã³ã¿ã€ãã ãã䜿çšãããããåªå ãããŸãã
@howiempt
ããšãã°ãgetïŒ 'person'ïŒã¯ãå®éã«ã¯ã·ã³ãã«èªäœã䜿çšããŠããŸãã
ãããäœãæå³ããã®ãããããŸããããããã§ã©ã®èšå·ãåç
§ããŠããŸããïŒ
ç§ã®å®è£
ã§ã¯ã次ã®ãããªããšãã§ããŸã
let g = new FormGroup({
'name': new FormControl('Toxicable'),
'age': new FormControl(22),
})
g.get('name') //AbstractControl<string>
g.get('age') //AbstractControl<number>
æååã䜿çšããã«getïŒobj.personïŒ
ããã«ã¯ãè€æ°ã®FormGroupããã©ããŒã¹ããæ©èœããããŸããã
ç§ã®æ¹æ³ã§ã¯ãã®ã·ããªãªã§åãæšæž¬ããããšã¯ã§ããŸããããç§ã®PRã®ã¢ã€ãã¢ã¯ãå€æŽãå£ããããæ°ããAPIïŒãžã§ããªãã¯ãé€ãïŒãå°å
¥ãããããã«ãžã§ããªãã¯åãè¿œå ããããšã§ãã
@Toxicableããªãã®å€åã¯ç©äºãå£ããªãããšãæå³ããããªãã®è§£æ±ºçãæ¹å€ããããšããªãããšãæå³ããŠãããšç§ã¯ç解ããŠããŸãã ãã1ã€ã®å®è£ ïŒåŸä»ãïŒã§ã¯ãæååã§ã¯ãªãå®éã®ããããã£ã䜿çšã§ããŸãã æååã§ãã£ãŒã«ããåç §ããããšã«ããããã®ããããã£åãå€æŽãããå ŽåãbreakãäœæãããŸãããããã¯ç§ã«ãšã£ãŠã¯ããŸãå®å šã§ã¯ãããŸããã ããšãã°ããã£ãŒã«ãåããnameããããfirstNameãã«å€æŽãããšããã¹ãŠã®g.getïŒ 'name'ïŒåç §ãå€æŽããªãã£ãå Žåã«æ©èœããªããªããŸãã ç§ãäœããããããšãã§ããã°
class PersonDetails {
name: string;
age: number;
}
let g = new FormGroup<PersonDetails>({
name: new FormControl('Toxicable'),
age: new FormControl(22),
})
g.get(name) //AbstractControl<string>
g.get(age) //AbstractControl<number>
ãããã¯ãã¹ãŠå³å¯ãªåç §ã«ãªããŸãã ã¬ãããã£ãããœãªã¥ãŒã·ã§ã³ã¯å°ãããã¯ãªæ¹æ³ã§ãããè¡ããŸããããã®åé¡ã解決ããŸãã
@ææ¯ãªPRã«
ç§ã¯@howiemptã«åæã
g.get(x => x.name) //AbstractControl
ç¹°ãè¿ãã«ãªããŸããããããããåºãç¯å²ã§ã©ãã»ã©å®çŸå¯èœãã¯ããããŸããã
ç§ã¯ããªãã®å€æãä¿¡é ŒããŸãã
è¯ãä»äºãç¶ããŠãè¿ éãªå¯Ÿå¿ã«æè¬ããŸãã
ä»ã®ã³ã³ãããŒã«ã«ã¢ã¯ã»ã¹ãããã®æ¹æ³ã¯ããžã§ããªãã¯ã¹ã®è¿œå ãšã¯é¢ä¿ããªããšæããŸãã
ãã ããããã«ã€ããŠå¥ã®åé¡ãéããŠãã ãã
æ»ãåãèšå®ããããšãå®éã«ã¯ã匷ãåä»ããããŠããããšã¯æããŸãããå®è£ ã®ååãå¿ èŠãªããã§ãããããã¯æ£ããæ¹åãžã®äžæ©ã§ãã
ããã«ã¡ã¯ããã®åé¡ã®åé¿çãšããŠhttps://github.com/Quramy/ngx-typed-formsããªãªãŒã¹ããŸããã ãã²ãã§ãã¯ããŠãã ããð
@Quramyç§ã¯æ°é±éåã«ããªãã®ããã±ãŒãžã䜿ãããšããŸããããããŠç§ãèŠããŠããããã«ãããã¯å®éã«ã¯å€ãã®åŒ·å¶ãããŸãã:(
+1ã å®è£ ãããã£ãã®ã«ã€ã³ã¹ã¿ã³ã¹æ°ãã«ãŠã³ãã§ããŸããã
åãã
Angular Reactiveãã©ãŒã ã¯ãä»ã®ãã¬ãŒã ã¯ãŒã¯ãå®éã«åé§ããæ©èœã®1ã€ã§ãã ãªã¢ã¯ãã£ããã©ãŒã ã匷ãåä»ããããšãããã次ã®ã¬ãã«ã«ãªãã競äºãšã®ã®ã£ãããããã«åºãããŸã:)
ããã¯ãæ¡ä»¶ä»ããããåãšååž°ã䜿çšããŠå®è¡ã§ããŸã.....æ¡ä»¶ä»ããããåã¯typescriptã«ããŒãžãããŸããã ãããå ¬éãããå Žåã匷ãåä»ããã©ãŒã ãå¯èœã«ãããã£ã³ã¹ããããŸã
åŸ ãŠãªãïŒ
@Quramyãœãªã¥ãŒã·ã§ã³ã¯ãæ®å¿µãªããããã¹ãŠã®åŒæ°ã®æ§é ãFormBuilder
匷å¶ããŸããã ãŸããæ±çšã®FormGroup<T>
ã FormControll<T>
ãããã³FormArray<T>
ã¯ã AbtractControl<T>
ã€ãã³ãæ¡åŒµããªãã€ã³ã¿ãŒãã§ãŒã¹ã§ãããããçŽæ¥äœ¿çšããããšã¯ã§ããŸããã ããã¯ç§ãã¡ã®çŸåšã®ãããžã§ã¯ãã«ã¯ååã§ã¯ãããŸããã§ããã
ngx-strongly-typed-formsã䜿çšããŠã匷ãåä»ããã©ãŒã ãããžã§ã¯ããèªåã§ãªãªãŒã¹ããŸãã
ããã©ã«ãã®ãžã§ããªãã¯ã䜿çšããªããããäžäœäºææ§ãå°ãæãªãããŸãã ãã®ãããã³ã³ãããŒã«ã«ä»»æã®ã¿ã€ããæ瀺çã«æå®ããå¿
èŠããããŸãããä»ã®ãã¹ãŠã®éšåã«ããã«å€ãã®ã¿ã€ãã»ãŒããã£ãè¿œå ãã@ angle / formsã®çŸåšã®å®è£
ãšAPIäºæã§ãã
ããããããã¯ããã®æ©èœãAngularã«å®è£
ããããŸã§ã¯æå¹ãªä»£æ¿æ段ã§ãã
+1ããã¯åŒ·åãªæ©èœã§ãã
ã§ããã ãæ©ãå®è£ ããå¿ èŠããããŸãïŒ
ã³ãŒãã£ã³ã°ã®æ¹æ³
ãã®ãªãŒãã³ãœãŒã¹ãœãããŠã§ã¢ïŒAGPLïŒã«ã¯èå³æ·±ãå®è£ ããããŸã
https://github.com/concentricsky/badgr-ui/blob/master/src/app/common/util/typed-forms.ts
ç§ã¯ãããäžæçãªåé¿çãšããŠäœ¿çšããŸããïŒ
ããã圹ã«ç«ãŠã°å¹žã
import { FormControl, AbstractControl } from "@angular/forms";
export class NumberControl extends FormControl{
_value: Number;
get value(){
return this._value;
}
set value(value){
this._value = Number(value);
}
}
ããã¯ãç§ãåãçµãã ãããžã§ã¯ãã§äœåºŠãèããããšã§ãããJavaScriptãããã·ãååã«äœ¿çšããŠããªãããããããã®å€ãç£èŠãããã®ã«ããã©ãŒãã³ã¹ãäžãã圱é¿ãç¥ãããšãã§ããŸããã
FormBuilderã¬ãã«ã§ã«ã¹ã¿ã åé¿çãäœæããã ãã§ãã
import { Injectable } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
type ExtraProperties = { [key: string]: any } | null;
interface IModelConstructor { new(...args: any[]): any }
@Injectable({
providedIn: 'root'
})
export class TypedFormBuilder {
array = this.formBuilder.array;
control = this.formBuilder.control;
group = this.formBuilder.group;
constructor(private formBuilder: FormBuilder) {}
typedGroup<TGroupModel extends object>(ModelType: IModelConstructor, extraProps?: ExtraProperties): FormGroup & TGroupModel {
const formGroup: any = this.group({
...new ModelType(),
...extraProps
});
return new Proxy<FormGroup & TGroupModel>(formGroup, {
get: (target: FormGroup & TGroupModel, propName: string | number | symbol) => {
if (propName in target) {
return target[propName];
} else {
const property = target.get(propName as string);
return property && property.value;
}
},
set: (target: FormGroup & TGroupModel, propName: string | number | symbol, value: any, _: any) => {
if (propName in target) {
target[propName] = value;
} else {
target.setValue({ [propName]: value });
}
return true;
}
});
}
}
ãã®ãœãªã¥ãŒã·ã§ã³ã¯å®å šã«æŽç·Žããããã®ã§ã¯ãªããFormGroupã§çæãããããããã£ã®å€ã«ã¢ã¯ã»ã¹ããã®ãããããæåã§ãããïŒmyGroup.fieldsãªã©ããfieldsãã¯æå®ãããã¿ã€ãã«ãªããŸãïŒã ããããããã¯åŒ·ãåä»ããæäŸããŸãã ããã䜿çšããã«ã¯ïŒ
generateFormGroup() {
this.theGroup = builder.typedGroup<MyModel>(MyModel);
this.theGroup.someProperty = 5;
}
ç§ã¯ãçŸåšã®ãããžã§ã¯ãã§ãã©ãŒã ã®å ¥åã䜿çšã
ãããããžã§ããªãã¯ã¹ãçŸåšã®APIã«é
眮ããããšãæ£ãã決å®ã§ãããã©ããã«ã€ããŠã話ãåããããšæããŸãã ãã¹ãŠã®ãã©ãŒã ã³ã³ãããŒã«ã®åãäœæããŠãããšãã«ãéçåä»ãã¯ãã®æç¹ã§ã¯äžå¯èœã§ãããæ倧ã®æžå¿µäºé
ã®1ã€ã§ã¯ãªããšæããããå
¥åãäžå¯èœãŸãã¯æ±ãã«ãããšããžã±ãŒã¹ããã®ãããããèŠã€ããŸããã
æ®å¿µãªãããããã¯AbstractControl#value
ã®äž»ãªæ©èœã察象ãšããŠããŸããããã¯ã DeepPartial<T>
ããŸãã¯ãµãã¯ã©ã¹ããšã«ç°ãªãå®è£
ãæã€AbstractControl#get
ãããªãã®ã§ãªããã°ãªããŸããã
äžäœäºææ§ããããšã any
ã¿ã€ãã®ãã©ãŒã«ã¹ã«ãŒã±ãŒã¹ã«ãã£ãŠåŒãèµ·ããããã¿ã€ãã®å®å
šæ§ã®äžéšã倱ãããŸãã
ããããããªã¢ã¯ãã£ããã©ãŒã çšã®æ°ããAPIãæ€èšããããšãããã®åé¡ã®ãªãã·ã§ã³ã§ããïŒ
ã ãããããã¯å®éã®è§£æ±ºçãèµ·ãã£ãŠããéã«ç§ããã£ãããšã§ãã
å 責äºé ...ç§ã¯Angularãå§ããã°ããã§ãããTypescriptã«ç²ŸéããŠããããããªã¢ã¯ãã£ããã©ãŒã ãå®å šã«ã¯ç解ããŠããŸãã...ãããç§ã«ãšã£ãŠããŸãããçµæã§ããããã¡ããå®å šã§ã¯ãããŸãããFormGroupãšå ¥åããã ãã§ããããã©ãŒã ã«ã€ããŠè©³ããç¥ãã«ã€ããŠããã£ãšå€ãã®ããšãå ¥åããå¿ èŠããããšç¢ºä¿¡ããŠããŸã...
import { FormGroup } from '@angular/forms';
export class FormGroupTyped<T> extends FormGroup {
public get value(): T {
return this.value;
}
}
ãããŠãç§ã¯ããããã®ããã«äœ¿ãããšãã§ããŸã
import { FormGroupTyped } from 'path/to/your/form-group-typed.model';
interface IAuthForm {
email: string;
password: string;
}
const authForm: FormGroupTyped<IAuthForm> = fb.group({
email: ['', [Validators.required]],
password: ['', [Validators.required]],
});
const formValues: IAuthForm = this.authForm.value;
const email: string = formValues.email;
const invalidKeyVar: string = formValues.badBoy; // [ts] Property 'badBoy' does not exist on type 'IAuthForm'. [2339]
const invalidTypeVar: number = formValues.password; // [ts] Type 'string' is not assignable to type 'number'. [2322]
@Toxicable Lolã¯ãã®æ£ç¢ºãªåé¡ãæ¢ããŠããŸããïŒ ã¯ã¯
@cafesanuã³ã³ã¹ãã©ã¯ã¿ãŒããã§ãã¯ããããã«ãåæå®ãããFormGroupãå°ãæ¹åããŸããã
import { AbstractControl, AbstractControlOptions, AsyncValidatorFn, FormGroup, ValidatorFn } from '@angular/forms';
export class FormGroupTyped<T> extends FormGroup {
readonly value: T;
readonly valueChanges: Observable<T>;
constructor(controls: { [key in keyof T]: AbstractControl; },
validatorOrOpts?: ValidatorFn | Array<ValidatorFn> | AbstractControlOptions | null,
asyncValidator?: AsyncValidatorFn | Array<AsyncValidatorFn> | null) {
super(controls, validatorOrOpts, asyncValidator);
}
patchValue(value: Partial<T> | T, options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}): void {
super.patchValue(value, options);
}
get(path: Array<Extract<keyof T, string>> | Extract<keyof T, string>): AbstractControl | never {
return super.get(path);
}
}
å©çšæ¹æ³ ïŒ
export class SearchModel {
criteria: string;
}
const searchForm = new FormGroupTyped<SearchModel >({
criteria: new FormControl('', Validators.required) // OK
badBoy: new FormControl('', Validators.required) // TS2345: Object literal may only specify known properties, and 'badBoy' does not exist in type '{ criteria: AbstractControl; }'.
});
ãã«ããŒã®åŒã³åºãã«åºã¥ããŠããŒã¿ã®ã¿ã€ããåçã«çæã§ããããã«ããFromControlã®å°ããªã©ãããŒãäœæããŸããïŒ https ïŒ
åçã«æ§ç¯ãããåã¯ãã€ã³ã¿ãŒãã§ã€ã¹åãäºåã«å®£èšããŠããããã©ãŒã ãäœæããããã®é©åãªåŒã³åºããè¡ãå¿ èŠããªãããã©ãŒã ã®åœ¢ç¶ãæåŸ ã«äžèŽããããšãä¿èšŒããŸãã
ãã€ãAngularã§ããã«äŒŒããã®ãèŠããã§ãã
䜿çšæ³ã¯æ¬¡ã®ããã«ãªããŸãã
// Create a typed form whose type is dynamically constructed by the builder calls
const group = new TypedFormGroup()
.add("firstName", typedControl("", Validators.required))
.add("lastName", typedControl("", Validators.required))
.add(
"address",
typedGroup()
.add("street", typedControl("2557 Kincaid"))
.add("city", typedControl("Eugene"))
.add("zip", typedControl("97405"))
)
.addArray(
"items",
typedGroup()
.addControl("itemName", "")
.addControl("itemId", 0)
)
;
// All these are type checked:
group.value.address.street.trim();
group.controls.firstName.value;
group.untypedControls.firstName.value;
group.value.items[0].itemId;
ããã«ã¡ã¯ãéå»3æ¥éãç§ã¯d.ts gist
ã䜿çšããŠãå
ã®è§åºŠã¯ã©ã¹ãšäºææ§ã®ããæ°ããTypedã€ã³ã¿ãŒãã§ã€ã¹ãäœæããReactiveFormsã¯ã©ã¹ã®ããå³å¯ãªå®çŸ©ãå®çŸ©ããå®éšãããŠã
ç§ã¯ãããããªãã®åé¡ã®å¯èœãªè§£æ±ºç/åé¿çãããããªããšæããŸãð
//BASIC TYPES DEFINED IN @angular/forms + rxjs/Observable
type FormGroup = import("@angular/forms").FormGroup;
type FormArray = import("@angular/forms").FormArray;
type FormControl = import("@angular/forms").FormControl;
type AbstractControl = import("@angular/forms").AbstractControl;
type Observable<T> = import("rxjs").Observable<T>;
type STATUS = "VALID" | "INVALID" | "PENDING" | "DISABLED"; //<- I don't know why Angular Team doesn't define it https://github.com/angular/angular/blob/7.2.7/packages/forms/src/model.ts#L15-L45)
type STATUSs = STATUS | string; //<- string is added only becouse Angular base class use string insted of union type https://github.com/angular/angular/blob/7.2.7/packages/forms/src/model.ts#L196)
//OVVERRIDE TYPES WITH STRICT TYPED INTERFACES + SOME TYPE TRICKS TO COMPOSE INTERFACE (https://github.com/Microsoft/TypeScript/issues/16936)
interface AbstractControlTyped<T> extends AbstractControl {
// BASE PROPS AND METHODS COMMON TO ALL FormControl/FormGroup/FormArray
readonly value: T;
valueChanges: Observable<T>;
readonly status: STATUSs;
statusChanges: Observable<STATUS>;
get<V = unknown>(path: Array<string | number> | string): AbstractControlTyped<V> | null;
setValue<V>(value: V extends T ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
patchValue<V>(value: V extends Partial<T> ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
reset<V>(value?: V extends Partial<T> ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
}
interface FormControlTyped<T> extends FormControl {
// COPIED FROM AbstractControlTyped<T> BECOUSE TS NOT SUPPORT MULPILE extends FormControl, AbstractControlTyped<T>
readonly value: T;
valueChanges: Observable<T>;
readonly status: STATUSs;
statusChanges: Observable<STATUS>;
get<V = unknown>(path: Array<string | number> | string): AbstractControlTyped<V> | null;
setValue<V>(value: V extends T ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
patchValue<V>(value: V extends Partial<T> ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
reset<V>(value?: V extends Partial<T> ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
}
interface FormGroupTyped<T> extends FormGroup {
// PROPS AND METHODS SPECIFIC OF FormGroup
//controls: { [P in keyof T | string]: AbstractControlTyped<P extends keyof T ? T[P] : any> };
controls: { [P in keyof T]: AbstractControlTyped<T[P]> };
registerControl<P extends keyof T>(name: P, control: AbstractControlTyped<T[P]>): AbstractControlTyped<T[P]>;
registerControl<V = any>(name: string, control: AbstractControlTyped<V>): AbstractControlTyped<V>;
addControl<P extends keyof T>(name: P, control: AbstractControlTyped<T[P]>): void;
addControl<V = any>(name: string, control: AbstractControlTyped<V>): void;
removeControl(name: keyof T): void;
removeControl(name: string): void;
setControl<P extends keyof T>(name: P, control: AbstractControlTyped<T[P]>): void;
setControl<V = any>(name: string, control: AbstractControlTyped<V>): void;
contains(name: keyof T): boolean;
contains(name: string): boolean;
get<P extends keyof T>(path: P): AbstractControlTyped<T[P]>;
getRawValue(): T & { [disabledProp in string | number]: any };
// COPIED FROM AbstractControlTyped<T> BECOUSE TS NOT SUPPORT MULPILE extends FormGroup, AbstractControlTyped<T>
readonly value: T;
valueChanges: Observable<T>;
readonly status: STATUSs;
statusChanges: Observable<STATUS>;
get<V = unknown>(path: Array<string | number> | string): AbstractControlTyped<V> | null;
setValue<V>(value: V extends T ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
patchValue<V>(value: V extends Partial<T> ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
reset<V>(value?: V extends Partial<T> ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
}
interface FormArrayTyped<T> extends FormArray {
// PROPS AND METHODS SPECIFIC OF FormGroup
controls: AbstractControlTyped<T>[];
at(index: number): AbstractControlTyped<T>;
push<V = T>(ctrl: AbstractControlTyped<V>): void;
insert<V = T>(index: number, control: AbstractControlTyped<V>): void;
setControl<V = T>(index: number, control: AbstractControlTyped<V>): void;
getRawValue(): T[];
// COPIED FROM AbstractControlTyped<T[]> BECOUSE TS NOT SUPPORT MULPILE extends FormArray, AbastractControlTyped<T[]>
readonly value: T[];
valueChanges: Observable<T[]>;
readonly status: STATUSs;
statusChanges: Observable<STATUS>;
get<V = unknown>(path: Array<string | number> | string): AbstractControlTyped<V> | null;
setValue<V>(value: V extends T[] ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
patchValue<V>(value: V extends Partial<T>[] ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
reset<V>(value?: V extends Partial<T>[] ? V : never, options?: { onlySelf?: boolean; emitEvent?: boolean }): void;
}
stackblitzã§ã®äœ¿çšãã¹ã-ã³ãŒããããŠã³ããŒãããŠããŒã«ã«VSCodeã§å®è¡ããŠãã ããstackblitzã§setValueãšpathValueã®ãšã©ãŒãæ£ãããªãçç±ãããããŸãã...
ãã®ãã€ãã¿ãŒã¹ã¬ããã§ãããã€ãã®ãå°æ¥ã®ã¢ã€ãã¢ãã«ã€ããŠ@IgorMinarãšè©±ãåããŸãïŒV8 +以éïŒ
ã³ã¡ã³ããææ¡ããã«ãã¯å€§æè¿ã§ãïŒ
ç§ã®ãœãªã¥ãŒã·ã§ã³ã¯@ng-stack/forms
ãšåŒã°ããŠããŸãã èå³æ·±ãæ©èœã®1ã€ã¯ããã©ãŒã ã¿ã€ãã®èªåæ€åºã§ãã
ãããã£ãŠãã³ã³ããŒãã³ãã§ãããè¡ãå¿ èŠã¯ãããŸããã
get userName() {
return this.formGroup.get('userName') as FormControl;
}
get addresses() {
return this.formGroup.get('addresses') as FormGroup;
}
ä»ãããè¡ããŸãïŒ
// Note here form model UserForm
formGroup: FormGroup<UserForm>;
get userName() {
return this.formGroup.get('userName');
}
get addresses() {
return this.formGroup.get('addresses');
}
詳现ã«ã€ããŠã¯ã @ ng-stack / formsãåç §ããŠãã ããã
ãããç§ãã¡ã¯æè¿@zakhenryãš2ã€ã®ããšã«åãçµãã§ããŸããïŒ
@dmorosinottoã®ããã«ãã¹ãŠã®ã¿ã€ãã
誰ããlibã調ã¹ããå ŽåïŒ ngx-sub-form
ããã«ã¡ã¯@ maxime1992ç§ã¯Controls<T>
ãèŠãŸããããããã¯AbstractControl to <T[K]>
å³å¯ã«ããŸãã
çç±ãèããŠãããã§ããïŒ å®è¡æã«setControlãregisterControlã¡ãœãããªã©ã䜿çšããŠFormControlãšé¢é£ããåãåå®çŸ©ããã³å€æŽããå¿
èŠããããšæããããããåãªããã®ãŸãŸã«ããŸããïŒ
TypedForms.d.tsã¯å°ãå³å¯ã§ã AbstractControlTyped to the type T<P>
ãã匷å¶ãããããã§ããããã®çš®ã®éžæã§ãå
ã®ReactiveForms APIã§èš±å¯ããã䜿çšãããå¯èœæ§ã®ãããã®ã匷å¶/ç¡å¹ã«ãããã©ããã¯ããããŸããã誰ã...
äœãèãã¯ãããŸããïŒ èæ
®ãã¹ãå®éã®ã±ãŒã¹ã¯ãããŸããïŒ
ããã«é¢ããã³ã¡ã³ãã¯ãç§ãäœæããå®çŸ©ãšç§ãåãçµãã§ããPRãå€æŽããæ¹æ³ã決å®ããã®ã«åœ¹ç«ã€ãããããŸãã...
ããããšã
PSïŒngx-sub-formã®ãã°ãããäœæ¥ðControlValueAccessorã䜿çšããŠãµããã©ãŒã ãåŠçãããšããã¢ã€ãã¢ã¯ãç§ãå®éšããŠãããã®ã§ãð
@ ng-stack / formsã®å ŽåããµããŒãåã®æ€èšŒãè¿œå ãããŸããã
ã¯ã©ã¹FormControl
ã FormGroup
ã FormArray
ããã³FormBuilder
ãã¹ãŠã®ã¡ãœãã
ãžã§ããªãã¯ã®2çªç®ã®ãã©ã¡ãŒã¿ãŒãšããŠããšã©ãŒæ€èšŒã¢ãã«ããåãå
¥ããŸãã
class ValidationModel {
someErrorCode: { returnedValue: 123 };
}
const control = new FormControl<string, ValidationModel>('some value');
control.getError('someErrorCode'); // OK
control.errors.someErrorCode; // OK
control.getError('notExistingErrorCode'); // Error: Argument of type '"notExistingErrorCode"' is not...
control.errors.notExistingErrorCode; // Error: Property 'notExistingErrorCode' does not exist...
ããã©ã«ãã§ã¯ã ValidatorsModel
ãšåŒã°ããç¹æ®ãªã¿ã€ãã䜿çšãããŸãã
const control = new FormControl('some value');
control.getError('required'); // OK
control.getError('email'); // OK
control.errors.required // OK
control.errors.email // OK
control.getError('notExistingErrorCode'); // Error: Argument of type '"notExistingErrorCode"' is not...
control.errors.notExistingErrorCode // Error: Property 'notExistingErrorCode' does not exist...
ValidatorsModel
ã¯ã typeof Validators
ããæœåºãããããããã£ã®ãªã¹ããšãæåŸ
ãããåçã¿ã€ããå«ãŸããŠããŸãã
class ValidatorsModel {
min: { min: { min: number; actual: number } };
max: { max: { max: number; actual: number } };
required: { required: true };
requiredTrue: { required: true };
email: { email: true };
minLength: { minlength: { requiredLength: number; actualLength: number } };
maxLength: { requiredLength: number; actualLength: number };
pattern: { requiredPattern: string; actualValue: string };
}
@dmorosinottoã©ããããããšãããããŸãããã䜿çšã§ããŸããValidators.compose([Validators.required, Validators.maxLength(20), Validators.minLength(3)])
ããã«ã¡ã¯@youssefshariefããªããŒã¿ãŒã«é¢ããåé¡ã®è©³çŽ°ãæããŠããã ããŸããïŒ .d.tsã䜿çšããŠã©ã®ãããªãšã©ãŒ/åé¡ãèŠã€ããŸãããïŒ
ãµã³ãã«ã³ãŒããŸãã¯stackblitzãæçš¿ã§ããå Žåã¯ããããç£èŠãã解決çãèŠã€ãã£ãå Žåã¯åé¡ã®è§£æ±ºãæ¯æŽããããšããŸãð
@ng-stack/forms
å Žåã input[type="file"]
ãµããŒããè¿œå ãããŸããã
stackblitzã®äŸãåç §ããŠãã ãã
FormData
ã䜿çšããŠãã¡ã€ã«ãã¢ããããŒããããã¯ã©ã·ãã¯ãã¢ãããŒãã䜿çšããŸããããããã€ãã®å©ç¹ããããŸãã
<input type="file" name="someName">
-> formControl.value
ãšsomeName
ãã£ãŒã«ãåãmultiple
å±æ§ããµããŒãããŸãïŒããã§ã¯userpic[]
泚æããŠãã ããïŒ<input type="file" multiple name="userpic" [formControl]="formControl">
`` `ts
formData.appendïŒ 'userpic []'ãmyFileInput.files [0]ïŒ;
formData.appendïŒ 'userpic []'ãmyFileInput.files [1]ïŒ;
- `Validators` have four static methods for files
```ts
import { Validators } from '@ng-stack/forms';
Validators.fileRequired;
Validators.fileMaxSize(1024);
Validators.filesMaxLength(10);
Validators.filesMinLength(2);
ãããŸã§ã«èŠã@KostyaTretyakã¯ãAngular ReactiveFormsã§ã®çŸåšã®ã¿ã€ãã³ã°ã®åé¡ã«å¯Ÿããåªãããœãªã¥ãŒã·ã§ã³ã®ããã§ãã ç¬èªã®å®è£ ãè¡ã代ããã«ãAngularèªäœã«è²¢ç®ããããšãèããããšã¯ãããŸããïŒ
ç§ãã¡ã¯ã»ãŒAngular8ã«ããŸããã100ïŒ TypeScriptç°å¢ã§ã¯ãããã«äœ¿çšã§ããåä»ããã©ãŒã ããŸã ãããŸãããããã¯ç§ã«ã¯ããªãå¥åŠã«æããŸãã
@kroeder ãçŸåšã®åé¡ã2幎以äžåã«äœæãããããšãããããŸãïŒAngular 2ã®ãªãªãŒã¹ã®ã»ãŒçŽåŸïŒãåæ§ã®ãã«ãªã¯ãšã¹ãã1ã5幎åã«ããŒãžãªãã§äœæãããããšãããããŸã...
ãããã @ng-stack/forms
ã人æ°ããããAngular 8+ãšäºææ§ãããå Žåã¯ãå°æ¥çã«ãã«ãªã¯ãšã¹ããäœæããå¯èœæ§ããããŸãã
@KostyaTretyakããã§ãã:)ãã®ã¹ã¬ããã§åè¿°ãã @ no0x9dã«ãã£ãŠäœæãããhttps://github.com/no0x9d/ngx-strongly-typed-formsã䜿çšããŠããŸããã©ã€ãã©ãªã¯ãããšã©ã®ããã«ç°ãªããŸããïŒ
@ZNS ãããããŸããããç°¡åã«ç¢ºèªãããšããã ngx-strongly-typed-forms
ã«ã¯æ€èšŒçšã®ãžã§ããªãã¯ããªãããã©ãŒã ã³ã³ãããŒã«ã®é©åãªã¿ã€ããèªåçã«æ€åºããããšãã§ããªããšæã
@ ZNS @ KostyaTretyakããã«ã¡ã¯ã äžã§è¿°ã¹ãããã«ãç§ã¯ngx-strongly-typed-formsã®äœè
ã§ãã
@ng-stack/forms
ã®æ©èœã»ãããç°¡åã«ç¢ºèªããŸããããããã€ãã®å°ããªéãããããšæããŸãã
ã»ãŒãã¹ãŠã®ãœãªã¥ãŒã·ã§ã³ãŸãã¯åé¿çãšç§ã®ãããžã§ã¯ãã®éã«ã¯æŠå¿µçãªéãããããŸãã
ã»ãšãã©ã®å Žåãå
ã®Angular FormControlã¯ããããã·ã«ãã£ãŠæ¡åŒµãŸãã¯ã©ãããããŠããŸãã äžéšã®ã¡ãœããã¯ä»ã®åã·ã°ããã£ãŒã§ãªãŒããŒã©ã€ããããå
ã®é¢æ°ã«å§ä»»ãããŸãã
ããã«ãããããã©ãŒãã³ã¹ãžã®åœ±é¿ã¯ããããããªæ°ããã¬ã€ã€ãŒãå°å
¥ãããŸãããããéèŠãªã®ã¯ãç¶æããå¿
èŠãããããããžã§ã¯ãã«ãã°ãããããå¯èœæ§ã®ããã³ãŒãã§ãã
ç§ã®æèŠã§ã¯ãããã¯ã³ã³ãã€ã«æã®éçãã§ãã¯ã«ã¯äžèŠã§ãã å¯äžã®å®è¡æã®éšåã¯ãåæå®ãããFormBuilderãæäŸããNgModuleã§ããããã¯ãå®éã«ã¯å
ã®AngularFormBuilderã§ãã ãã以å€ã¯ãã¹ãŠAngularã³ãŒãã§ãã
çŽæ¥æ¯èŒãããšãValidationModelãšããªããžã§ã¯ãããFormGroupsãžã®å€æãããã³ArraysããFormArraysãžã®å€æã¯ãããŸããããåã®å®å
šæ§ãé«ããããªããŒã¿ãŒåŒæ°ãåä»ãããããã«ã AbstractControl#get
ã«ããã€ãã®æèŠã®å€æŽãè¡ããŸããã
ããã€ãã®å°ããªè¿œå ã§ãç§ã®ã³ãŒãã¯äžäœäºææ§ãããããã«ãªã¯ãšã¹ããäœæã§ããŸãã ããããåæ§ã®ãã«ãªã¯ãšã¹ãã¯é·ãéå€ããªã£ãŠããŸãã
ããããAngularã§ãããå®çŸããããã®åªåãããã°ãç§ã¯åãåãããŠåãã§ããŸãã å察ã«ãå³å¯ã«åæå®ãããããã«èšèšããããã©ãŒã çšã®æ°ããAPIãèŠãŠã¿ãããšæããŸãã 詳现ã«ã€ããŠã¯ç§ã®ã³ã¡ã³ããåç
§ããŠãã ããã
+1ã¯ãã®æ©èœãèŠãããšæã£ãŠããŸãã 誰ããããã«åãçµãã§ããŸããïŒ
è§åºŠã®ããããŒã ã«ã¶ã€ããïŒ
圌ãã¯éçºè ãæ°ã«ããŸããã 圌ãã¯ããã©ãã¯ãžã£ãã¯ãšçŽ æŽããã-5ïŒ æžå°ãã³ãã«ãµã€ãºã®æ©èœãåããç¬èªã®ããã¯ãã°ãæã£ãŠããŸãã
@ Lonli-Lokli
圌ãã¯éçºè ãæ°ã«ããŸããã
æ¹å€ã¯ç°¡åã§ãã ä»ã®éçºè
ããã£ãšæ°ã«ããŸããïŒ
ãã©ãŒã ãæ¹åããããã®PRããç©äºãåé²ãããããã®å»ºèšçãªã³ã¡ã³ããRFCãèŠãããšããããŸããïŒman_shruggingïŒ
圌ãã¯ç¬èªã®ããã¯ãã°ãæã£ãŠããŸã
ãŸããïŒæãããïŒïŒ
人ã
ã¯äŒç€Ÿã_ [圌ãã«ãéãæã£ãŠãã] _ãå¿
èŠãšãããã®ãåªå
ããŠããŸããïŒ
æ®å¿µã ïŒ
çŽ æŽããã-5ïŒ -ãã³ãã«ãµã€ãºã®æ©èœãæžãããŸãã
ããªãã¯æããã«ã¢ã€ããŒãšïŒçŸåšïŒãã³ãã«ãµã€ãºã®éåžžã«å°ããªéãã«ã€ããŠè©±ããŠããã
ã¢ã€ããŒã¯çŸåšå®éšçã§ããããªããã€ã³ããå¿
èŠããããŸããé©ãã¹ãããšã«ããŸã å®ç§ã§ã¯ãããŸããã ïŒèãïŒ
ã¯ããIvyã¯ãã³ãã«ãµã€ãºãçž®å°ããããŒã«ãã¢ããªã§ããè¯ãããªãŒã·ã§ã€ã¯ãå®è¡ã§ããããã«ããã®ã«åœ¹ç«ã€ãšèšãããŠããŸãã ãããŠããŸãããã°ããããæ¥ãã§ãããïŒ ä»ã®ãšããã圌ãã¯ãããäœããå£ããŠããªãããšã確èªããããã ãã«åãçµãã§ãããåŸã§ããè¯ããããã°æ
å ±ãã¢ãžã¥ãŒã«ããŒã¹ã§ã¯ãªãã³ã³ããŒãã³ãããŒã¹ã§ã®ã€ã³ã¯ãªã¡ã³ã¿ã«ã³ã³ãã€ã«ãããã³ããªãŒã·ã§ã€ã¯ãè¡ãã®ã«åœ¹ç«ã¡ãŸãã ãããããã®ããªãŒãæºãã¶ãããŒã«ã¯åŸã§æ©èœããŸãã
ãããã£ãŠãæ¬æãæãããªãŒãã³ãœãŒã¹ãã¬ãŒã ã¯ãŒã¯ãç¡æã§æäŸããŠãã人ã ããŽãç®±ã«æšãŠãªãããã«ããŠãã ããã ç©äºã¯å®ç§ã§ã¯ãªããé²è¡äžã®å·šå€§ãªäœæ¥ã§ãã確ãã«ãããã€ãã®åé¡ãæ®ãããŠããããã«æããŸããããã®ãªãã¡ã¯ã¿ãªã³ã°ãå¿ èŠã§ããããã®ãããªå€§ããªãã®ãäœãã®ã«è¯ãæéã¯æ±ºããŠãããŸãããããã¯ããæç¹ã§èµ·ãããªããã°ãªããŸããã§ããã
éçç£çãªããšã«ã€ããŠè©±ããŠãããã®ã¹ã¬ãããç¬å ããããªãã®ã§ãä»ç§ã¯ãã®è°è«ããå€ããŠããŸãã *é£ã³å»ããŸã*
@ maxime-allex
ä»ã«ãããããã®PRããããŸããïŒçŸåš386ïŒããã1ã€ã¯äœããå€ãããšæããŸããïŒ
ãã®åé¡ã«ã€ããŠèšãã°ããã®é¢é£ããPRïŒhttps://github.com/angular/angular/pull/20040ïŒã¯ãŸã ããŒãžãããŠããŸããã
ãªãã¡ã¯ã¿ãªã³ã°ãšèšãã°ãIvyã¯1幎åã«èšåãããŸããã 誰ããæ±ãããšãã§ããã®ã¯éçºè
ã«ãšã£ãŠã®äž»èŠãªæ©èœã§ããããšãç§ã¯ç¥ã£ãŠããŸãããå人çã«ã¯ãä¿®æ£ãã§ããã ãå€ãã®éçºè
ã«ãšã£ãŠéèŠã§ããããšãæãã§ããŸãã
https://github.com/angular/angular/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc
AngularãããŒã±ãã£ã³ã°ã§ã¯ãªãéçºè åãã§ãããã³ãã¥ããã£ã®åå¿ã«åºã¥ããŠããå€ãã®åé¡ã解決ãããããšãæåŸ ããŠããŸãã ãããç§ã®è³ªåã§ããããã§ã®åªå äºé ã¯äœã§ããã
æããã«ããã®åé¡ã¯æ¢åã®APIãæŽæ°ããããšã§è§£æ±ºã§ããŸããããããšã¯å¥ã«ãReactiveFormsModuleãæ¹åããŠããã®åé¡ãå«ãå€ãã®æªè§£æ±ºã®åé¡ã«å¯ŸåŠããææ¡ãäœæããŸããã
察åŠããããã®ä»ã®åé¡ã«ã¯ãä»»æã®ããããã£ã®æŽæ°ããµãã¹ã¯ã©ã€ãããæ©èœããïŒ asyncValidator
ã§ã¯ãªãïŒãµãŒãã¹ãä»ããŠã³ã³ãããŒã«ãéåæçã«æ€èšŒããæ©èœãå«ãŸããŸãã 詳现ã«ã€ããŠã¯ãïŒ31963ãã芧ãã ããã ãã£ãŒãããã¯ãæè¿ããŸãïŒ
以åã«çŽæããããã«ããã«ãªã¯ãšã¹ããäœæããŸããã ãã®PRã«ã¯ã @ng-stack/forms
æ©èœã®äžéšã®ã¿ãå«ãŸããŠããŸãïŒæ€èšŒããã©ãŒã å¶åŸ¡ã®èªåæ€åºãinput [file]ã®ãµããŒãã¯å«ãŸããŠããŸããïŒã
ãããAngularããŒã ããã®ææ°æ å ±ãå ±æããããšæããŸããããã¯å€§ããªåé¡ç¹ã ãšèããŠããŸãã éããªãããã匷ãåä»ãããããã©ãŒã ã®äœæ¥ãéå§ããŸããããã«ã¯ãæ¢åã®PRã確èªãããã¹ãŠã®ã³ã¡ã³ããå床確èªããããšãå«ãŸããŸãã æéãå²ããŠèããæ®ããŠãããçããã«æè¬ããŸãïŒ
ããïŒïŒïŒïŒïŒ çµäºããŸãïŒ
ããã¯éåžžã«è¯ããã¥ãŒã¹ã§ããAngularããŒã ãããããšãïŒ
ãªãªãŒã¹ããã次第ã angular-typesafe-reactive-forms-helperãå»æ¢ããŸãã
YESSSS !!!!
ç§ã¯ãšãŠãè奮ããŠããŸãïŒïŒ ããããšããAngularããŒã !!
åå¿ã¹ãã ã§æ¢ããããŸããïŒ
https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/ã察象ãšããŠãããããåå¿ã«ã¯çµµæåã䜿çšããŠ
AngularããŒã ã¯ã匷ãåä»ãããããªã¢ã¯ãã£ããã©ãŒã ã«åãçµãããšã確èªããŸããã ã¹ã ãŒãºãªéçåä»ãéçºãšã¯ã¹ããªãšã³ã¹ãåŸãããã«ã infer
åã
FormGroupã®ãã¶ã€ã³ãå§ãããšãT
ãšããŠäœ¿çšããŸããã
FormGroup<{ id: string, username: string | null }>
ããããè€éãªããŒãã«ãã©ãŒã ã¢ãŒããã¯ãã£ãåŠçããå¿ èŠãããå ŽåãAngularHTMLã§ã¿ã€ãã»ãŒããªãã€ã³ãã£ã³ã°ãå®è¡ããã®ã¯éåžžã«é£ããããšãããããŸããã
type User = { id: string, username: string | null }
const table: FormArray<User> = new FormArray([{ id: '0', username: 'gaplo917'}])
const row: FormGroup<User> = table.at(0) as FormGroup<User> // you must do a type cast
// NO way to get type-safe binding in Angular HTML
<input [formControl]="table.at(i).controls.id" />
äžèšã®å®è£ ã§ã¯ãéçºè ã¯é¢åã§ãšã©ãŒãçºçããããã«ã¹ã¿ã åãã£ã¹ããå®è¡ããå¿ èŠããããŸããã ç§èŠãããã¯åŒ·ãåä»ãããããªã¢ã¯ãã£ããã©ãŒã ã䜿çšããçç±ãå®å šã«å€±ããŸãã
åçŽãªå€åã䜿çšãããšã¹ã ãŒãºã«æ©èœããŸããã KeyValueControlã䜿çšããå¥ã®ã¢ã€ãã¢ãæãã€ããŸãT
ããã³äœ¿çšinfer
KeyValueControlããæœåºå€åã
export type KeyValueControl<V> = {
[key in keyof V]: V[key] & AbstractControl
}
export type InferTypedForm<Type> = Type extends TypedFormControl<infer X>
? X
: Type extends Array<TypedFormControl<infer X1>>
? X1[]
: Type extends Array<TypedFormGroup<infer X2>>
? Array<InferTypedFormGroup<X2>>
: Type extends TypedFormGroup<infer X3>
? InferTypedFormGroup<X3>
: Type extends TypedFormArray<infer X4>
? Array<InferTypedForm<X4>>
: never
export type InferTypedFormGroup<T> = { [key in keyof T]: InferTypedForm<T[key]> }
export type InferTypedFormArray<T> = InferTypedForm<T[]>
export class TypedFormGroup<T extends KeyValueControl<T>> extends FormGroup {
readonly controls: T
readonly valueChanges: Observable<InferTypedFormGroup<T>>
readonly statusChanges: Observable<FormStatus>
readonly value: InferTypedFormGroup<T>
...
}
çµæãšããŠã
interface Foo {
first: TypedFormControl<string | null>
last: TypedFormControl<string | null>
}
const table: FormArray<FormGroup<Foo>>
const row: FormGroup<Foo> = table.at(0) // typescript compile OK!
// type-safe binding in Angular HTML, all auto-complete (`id`, `username`) finally works!
<input [formControl]="table.at(0).controls.id" />
ããã¯ãè€éãªåœ¢åŒã§ã®çã®ãªãŒãã³ã³ããªãŒããšã¯ã¹ããªãšã³ã¹ã§ãã
æ¢åã®ãªã¢ã¯ãã£ããã©ãŒã ã¢ãžã¥ãŒã«ãš100ïŒ
äºææ§ããããŸã
https://github.com/gaplo917/angular-typed-forms
ã³ã¡ã³ããæ¹åãæè¿ããŸãã ä»åŸã®åŒ·ãåä»ãããããªã¢ã¯ãã£ããã©ãŒã ããããŒãã«ããã¹ãããããµããã©ãŒã ãªã©ã®è€éãªãã©ãŒã ã¢ãã«ãåŠçã§ããããšãé¡ã£ãŠããŸãã
@ IgorMinar ã Angularã³ã¢ããŒã ãããã³Angularã³ãã¥ããã£ã¡ã³ããŒã
ãã®é·ãã³ã¡ã³ãã¯ããã±ããäœæè ããæ £ç¿ã«åããããšã匷ãã¿ã€ããããããšãã2ã€ã®ã¹ããŒãã¡ã³ãã«å®å šã«çŠç¹ãåœãŠãŠããŸãã
匷ãåä»ãããããªã¢ã¯ãã£ããã©ãŒã ã®ã€ã³ã¿ãŒãã§ã€ã¹ããŒã¹ã®ã¢ãããŒãã®ä»£ããã«ãã¯ã©ã¹ããŒã¹ã®ã¢ãããŒããéžæããããšããå§ãããŸããã ng-stacks / formsã«èšèŒãããŠããæ¹æ³ã§ã¯éžæããªãã§ãã ããã ãŸããAngular Ractive Formsã®ã³ãŒãããŒã¹ãå€æŽããããšã¯ãå§ãããŸãããããã¯ãããŸããŸãªæ¹æ³ã§ã³ãŒãããŒã¹ãå€æŽããªããŠãã匷ãåä»ãããããã©ãŒã ãå®çŸã§ããããã§ãã ã€ã³ã¿ãŒãã§ã€ã¹é§ååã¢ãããŒããšã¯ã©ã¹é§ååã¢ãããŒãã§èŠãããé«ã¬ãã«ã®èª²é¡ã¯ä»ã®ãã®ãããçŽæçã§ãããFormGroupãªããžã§ã¯ãã¯åŒ·ãåä»ããããŠããŸãã ã©ã¡ãã®å ŽåããFormGroupãªããžã§ã¯ãã¯åŒ·ãåä»ããããŠãããã¯ã©ã¹ããŒã¹ã®ã¢ãããŒãã§TypeScriptTypeã®èœåã倱ãããšã¯ãããŸããã
ç§ãã¡å šå¡ãOOPãã©ã¯ãã£ã¹ã«ç²ŸéããŠããã®ã§ããã®ã¯ã©ã¹ã¯ã³ãŒãã®æè»æ§ãšä¿å®æ§ãåäžãããŸãã 以äžã§åŒ·èª¿ããŠããå©ç¹ã®ããã€ãïŒ
*ngIf
ãé
眮ããããã«ããã³ãã¬ãŒãã«ããžãã¹ããžãã¯ãèšè¿°ããå¿
èŠã¯ãããŸããã ãã³ãã¬ãŒãã¯ããžãã¹ããžãã¯ãæžãããã®ãã®ã§ã¯ãªããšæããŸããäžèšã®ã€ã³ã¿ãŒãã§ã€ã¹ã³ãŒããClass
å€æããæ€èšŒãã³ã¬ãŒã¿ãClass
ããããã£ã«é©çšããŸãã ããã§ã¯ãåäžè²¬ä»»ååã®å®è·µã«åŸã£ãŠããŸãã 以äžã®ã³ãŒããã芧ãã ããã
ããã€ãã®ã±ãŒã¹ãèããŠãäž¡æ¹ã®éããç解ããã®ã«åœ¹ç«ã€ã€ã³ã¿ãŒãã§ãŒã¹ããã³ã¯ã©ã¹é§ååã®åŒ·ãåã®ã¢ãããŒããšæ¯èŒããŠã¿ãŸãããã
1.ãã©ãŒã ã°ã«ãŒããäœæããŸã
ããã§ã¯ãåãã€ã³ã¹ã¿ã³ã¹ã䜿çšããŠããFormBuilder
ãšåãæ¹æ³group
ã ããããã€ã³ããŒãã¢ãžã¥ãŒã«åã¯æ¬¡ã®ããã«ç°ãªããã®ã«ãªããŸãReactiveTypedFormsModule
ã®ä»£ããã«ReactiveFormsModule
ã FormGroup
äœæããŸãããïŒ
äžèšã®ã³ãŒãã«åŸã£ãŠã質åãæ¥ãŸãã
ReactiveTypedFormsModule
ã€ã³ããŒãããåŸãçŸåšã®ã¢ãããŒãã¯æ©èœããŸããïŒ
ã¯ããåäœããŸããReactiveTypedFormsModule
ã€ã³ããŒãããåŸã¯äœãå€æŽãããŸããã
ä»ã®ã±ãŒã¹ããã°ããèŠãŠããã®æçš¿ãç· ãããããŸãããã
2.FormControlã®å€ãå€æŽããŸã
setValue
ã¡ãœãããåŒã³åºã代ããã«ã Class
ããããã£ã«å€ãçŽæ¥å²ãåœãŠãããšãã§ããŸãã FormControl
å€ãèªåçã«èšå®ãããŸãã
3.FormControlã®å€ã®å€æŽã«åºã¥ããŠããžãã¹ããžãã¯ãå®è¡ããŸã
FormControl ValueChanges
ããµãã¹ã¯ã©ã€ããã代ããã«ãTypeScriptã®setter
ã¡ãœããã®åã䜿çšããŠãã ããã
4.å
¥åå€ãå€æããŸã
匷ãåã«çŠç¹ãåœãŠãŠããŸãããæ¥ä»ã®ããã«å
¥åã³ã³ãããŒã«ããååŸãããå€ã«ã€ããŠã¯ã©ãã§ããããã String
圢åŒã§å€ãååŸããŠããŸãããTSã³ãŒãã§ã¯Date
圢åŒãæåŸ
ããŠããŸãããã®åé¡ãå
æããããã«ãå¿
èŠã«å¿ããŠå€ãå€æãããã£ã¬ã¯ãã£ããŸãã¯ã¡ãœãããäœæããŸãã ãã£ã¬ã¯ãã£ããäœæããŠäœãšãäœãšãããå¿
èŠããããããçŸåšã®ã³ãŒãã¯å°ãäžåšçšãªã®ã§ãããã§ã¯ç€ºããŸãããðããã§ãã¯ã©ã¹é§ååã¢ãããŒãã®ã³ãŒããããã«ç€ºããŸãã
@toDate() // this will convert the value before assigning the value in 'dob' property.
dob:Date;
4.ãã¹ããããFormGroupFormControlã®å€ãå€æŽããŸã
ãã¹ããããFormGroupãªããžã§ã¯ããååŸããŠSetValue
ã¡ãœãããåŒã³åºãã®ã§ã¯ãªããããããã®ããããã£ã«å€ãçŽæ¥å²ãåœãŠãããšãã§ããŸãã
5.ãã¹ããããFormArrayã«FormGroupãè¿œå ãã
ãã以äžèšãããšã¯ãããŸããã以äžã®ã³ãŒããèŠãŠãã ããðã
ã·ã³ãã«ãªã³ãŒãðã HTMLãã³ãã¬ãŒãã§ã¯äœãå€æŽãããŸããããHTMLãã³ãã¬ãŒãã§ãããã«å€æŽãããŸãã 以äžã®ã³ãŒããåç §ããŠãã ãã
<form [formGroup]="user.formGroup">
<input type="text" formControlName="firstName"/>
<small >{{user.formGroup.controls.firstName.errorMessage}}</small>
<!--Nested FormGroup-->
<div [formGroup]="user.address.formGroup">...</div>
<!--Nested FormArray - Skills-->
<div *ngFor="let skill of user.skills">
<div [formGroup]="skill.formGroup">...</div>
</div
</form>
Stackblitz Link ïŒåŒ·ãã¿ã€ãã®åå¿åãã©ãŒã ã®äœæ¥äŸ
Githubã®äŸïŒåŒ·ãåä»ãããããªã¢ã¯ãã£ããã©ãŒã
@ajayojha ãç§ãééã£ãŠããå Žåã¯èšæ£ããŠãã ããã
setValue()
ãšvalueChanges()
å¿
èŠãªã®ã§ããïŒç§ã¯ã©ãæããŸããïŒ
setValue()
ã«å ããŠã patchValue()
ã reset()
ãããããããã¯ãã©ãŒã å€ã§ãæ©èœããŸãã setValue()
ã®ã¿ãã»ãã¿ãŒã«çœ®ãæãããšãã³ãŒãã«äžè²«æ§ããªããªããŸãã ããã«ããã©ãŒã ã¢ãã«ããããã£ããšã«ã»ãã¿ãŒãäœæããå¿
èŠãããå Žåãã²ãã¿ãŒã®å Žåã®ããã©ãŒãã³ã¹ãªãŒããŒãããã ãã§ãªããã³ãŒããªãŒããŒãããã倧å¹
ã«å¢å ããŸãã ãã©ãŒã ã¢ãã«ã®ããããã£åãšãã©ãŒã ã³ã³ãããŒã«ã®ããããã£ãæ··åšãããããšããç§ã®æèŠã§ã¯æªãèãã§ãã@KostyaTretyak ãç§ã®ã³ã¡ã³ãã«æžå¿µããå¯ãããã ãããããšãããããŸããåãããã«åçãããŠããã ããŸããããã«å¿ããŠã以äžã®ã³ã¡ã³ããã芧ãã ãã:)ã
- TypeScriptã¿ã€ãã«äŒŽããªãŒããŒãããã¯æªãã§ãã
åèãŸã§ã«ãformgroupãªããžã§ã¯ãã¯åŒ·ãåä»ããããŠããŸãã ã€ã³ã¿ãŒãã§ã€ã¹ã¯åªããŠããŸããããã¹ãŠã®é åã«é©ããŠããããã§ã¯ãããŸãããTypeScriptã®åãæªããšèšã£ãŠããããã§ã¯ãããŸãããã©ããã§ãåãæªããšèšã£ãããšã¯ãªããšæããŸãã ç§ã®å¯äžã®æžå¿µã¯ã€ã³ã¿ãŒãã§ãŒã¹ã«é¢ãããã®ã§ãããªããªããã€ã³ã¿ãŒãã§ãŒã¹ã¢ãããŒãã§ãœãããŠã§ã¢èšèšã®æ £è¡ãèŠããŠããããã§ãããããã¯ãééã£ãå Žæã§ã€ã³ã¿ãŒãã§ãŒã¹ã¢ãããŒãã䜿çšããŠããŠãç§ã®ææ¡ããã¢ãããŒãã¯ã¯ã©ã¹ã§ãããšèšããŸãã ã¯ã©ã¹ã¢ãããŒãã«ããç§ã®ç解ã®éãã§ã¯ãã€ã³ã¿ãŒãã§ã€ã¹ã§åŸãããTypeScriptã¿ã€ãã®å©ç¹ãæãªãããšã¯ãããŸããããããã¯ãèªã¿ããããã¹ã±ãŒã©ããªãã£ãããã³ä¿å®æ§ã®ç¹ã§ãã€ã³ã¿ãŒãã§ã€ã¹ã¢ãããŒã以äžã®ãã®ãåŸãããšãã§ããŸãã
匷ãåä»ããããåå¿åãã©ãŒã ã®ã€ã³ã¿ãŒãã§ãŒã¹ã®æ£ããæ¹æ³ã䜿çšããŠããŸããïŒ
ã€ã³ã¿ãŒãã§ãŒã¹ã®èŠ³ç¹ããããå°ã説æãããŠãã ãããããã¯ã匷ãåä»ãããããªã¢ã¯ãã£ããã©ãŒã ã®æªãç¿æ £ã§ãïŒç§ã«ãããšïŒã
TypeScriptã¿ã€ãã¯åªããŠããŸãããã€ã³ã¿ãŒãã§ã€ã¹ã®åé¡ã«ã€ããŠæ確ã«è¿°ã¹ãããã«ããœãããŠã§ã¢ã®æ £äŸã«åŸããªããã®ãã©ãã§ãæ··ä¹±ãããå¿ èŠãããããšã¯ç€ºåãããŠããŸããã ã€ã³ã¿ãŒãã§ãŒã¹ã«é¢ããç§ã®åŒ·èª¿ãããæžå¿µã«ã€ããŠèããŠã¿ãŠãã ããã ç§ã®ã±ãŒã¹ãå ±æããŸãããã6k以äžã®ã³ã³ããŒãã³ããå«ãç§ã®ãšã³ã¿ãŒãã©ã€ãºã¢ããªã±ãŒã·ã§ã³ã®1ã€ã§ãã ã€ã³ã¿ãŒãã§ã€ã¹ã¢ãããŒãã䜿çšããå ŽåãéçºããŒã ã¯å€æŽãè¡ãåã«è¯ã質åãããŸãã
ããã§ãäžèšã®ã±ãŒã¹ããã倧ããªèŠç¹ã§èãã匷ãåä»ãããããªã¢ã¯ãã£ããã©ãŒã ã®ã€ã³ã¿ãŒãã§ã€ã¹ãåããTypeScriptã¿ã€ããšæ¯èŒããŸãã ç§ã¯ããã¹ãŠã®åªããã¢ãããŒããéçºæéãç¯çŽãããšä¿¡ããŠããããã®ã¢ãããŒãã§ã¯ããœãããŠã§ã¢èšèšã®ååãšå®è·µã«ãããšãäœã®ã¡ãªãããèŠãããªããšèšã£ãŠç³ãèš³ãããŸããã
- ãã³ã¬ãŒã¿ã®å©ããåããã©ã³ã¿ã€ã æ€èšŒ-ããã¯è¯ãããšã§ãã
ãããã¯è¯ãããšããããªãã®ã³ã¡ã³ãã«åæããŸããã€ã³ã¿ãŒãã§ã€ã¹ã¢ãããŒãã§ã¯éæã§ããªããã³ã¬ãŒã¿ã¢ãããŒãã§ãã ãããTypeScriptã®æã匷åãªæ©èœã§ãããšç§ã¯ä¿¡ããŠããŸãããããªãããªããªã¢ã¯ãã£ããã©ãŒã ã¢ãããŒãã§åããã®ã䜿çšã§ãããéçºããŒã ã«ãªããžã§ã¯ãããããã£ã®å®å šãªå¶åŸ¡ãäžããããšãã§ããªãã®ã§ããã
- ã»ãã¿ãŒãããã®ã«ãªãsetValueïŒïŒãå¿ èŠãªã®ã§ããïŒ
'setValueïŒïŒ'ãå¿ èŠã ãšèšã£ããšããã¯ïŒ setValueã¯å¿ èŠãããŸããããŸããã¯ã©ã¹ããªãã³ã¢ãããŒãã§setValueã¡ãœãããåŒã³åºãäŸã«ã¯ç€ºããŠããŸããã ç§ãééã£ãŠããå Žåã¯èšæ£ããŠãã ããã
- TypeScriptã¿ã€ãã®èšè¿°ã¯ãéçãã¹ãã®èšè¿°ã«äŒŒãŠããŸãã äžå¿ èŠã ãšæã£ãŠãã¹ããªãã§ã¢ããªã±ãŒã·ã§ã³ãäœæãã人ããããããããŸããããããã¯æªãç¿æ £ã§ãã
TypeScriptã¿ã€ããéçãã¹ããæžããããªãã®ã ãšèšã£ãŠããã®ã§ã¯ãããŸããã ãããããªã¢ã¯ãã£ããã©ãŒã ã®åºæ¬ã¯ã©ã¹ã§ã®ã³ãããã®å€æŽã«ã¯åæããŸãããã¯ã©ã¹å®çŸ©ã«è§Šããããšãªãåãããšãéæã§ãããšæããŸãã ããã§ã¯ããããŸã§ã®ã³ãããã«åŸã£ãŠäœ¿çšããŠããªãã€ã³ã¿ãŒãã§ã€ã¹ã®å®éã®èœåã䜿çšã§ããŸããããã¯ãããžãã¯ãé·æéå®è¡ãããããã©ã«ãå€ã® 'ãèšå®ããŠãžã§ããªãã¯åãè¿œå ããããšããå§ãããŸããã©ãã'ïŒ
Reactive Formã®åºæ¬ã¯ã©ã¹ã«è§Šããããšãªããåãããšãéæã§ãããšæããŸãã åºæ¬ã¯ã©ã¹ã®å®çŸ©ãå€æŽããããä»æ§ãå€æŽããããã代ããã«ããªãããã§ã€ã³ã¿ãŒãã§ã€ã¹ãå©çšããªãã®ãããããŸããã
- ãã³ã¬ãŒã¿ã®å©ããåããã©ã³ã¿ã€ã æ€èšŒ-ããã¯è¯ãèããããããŸãããåæããŸãã
ç§ãã¡äºäººãšããã®ããŒãžã§åãããŒãžã§ããããšãç¥ã£ãŠãããšããã§ããã:)ã
- setValueïŒïŒã«å ããŠãpatchValueïŒïŒãresetïŒïŒããããŸãããããã¯ããã©ãŒã å€ã§ãæ©èœããŸãã setValueïŒïŒã®ã¿ãã»ãã¿ãŒã«çœ®ãæãããšãã³ãŒãã«äžè²«æ§ããªããªããŸãã ããã«ããã©ãŒã ã¢ãã«ã®ããããã£ããšã«ã»ãã¿ãŒãäœæããå¿ èŠãããå Žåã¯ãããã©ãŒãã³ã¹ã®ãªãŒããŒãããã ãã§ãªããã³ãŒãã®ãªãŒããŒããããå€§å¹ ã«å¢å ããŸãã ãã©ãŒã ã¢ãã«ã®ããããã£åãšãã©ãŒã ã³ã³ãããŒã«ã®ããããã£ãæ··åšãããããšããç§ã®æèŠã§ã¯æªãèãã§ãã
äžèšã®ç¹ããã¡ãœããã®åŒã³åºããã»ãã¿ãŒã®ããã©ãŒãã³ã¹ãªãŒããŒããããããã³ãã©ãŒã ã¢ãã«ããããã£ã®æ··åã®3ã€ã®ã»ã¯ã·ã§ã³ã§èª¬æããŸãã
ã¡ãœããã®åŒã³åºãïŒäºæ³ã©ããããã®æçš¿ãæžããŠãããšãã«ã誰ãããpatchValueããŸãã¯ãresetãã¡ãœããã®äœ¿çšãææ¡ããå¯èœæ§ããããšèããŠããŸããã ç¹°ãè¿ãã«ãªããŸãããå®éã®ã±ãŒã¹ã§ã¯ãã»ãšãã©ã®éçºããŒã ãpatchValueããã®ä»ã®ã¡ãœããã®ä»£ããã«ãsetValueãã¡ãœããã䜿çšããŠããŸãïŒããã¯ãAngular Application CodeReviewããã³StackoverflowPostsã®setValueãšpatchValueã«ããç§ã®çµéšã§ãïŒã ç§ã®çŠç¹ã¯ãã©ã®ã¡ãœãããåŒã³åºããŠãããã«é¢ä¿ãªããå€ãå²ãåœãŠãããã®ã¡ãœãããåŒã³åºãããšã§ãã
ã»ãã¿ãŒã®ããã©ãŒãã³ã¹ïŒ@Inputãã³ã¬ãŒã¿ã䜿çšããŠè€æ°ã®ã³ã³ããŒãã³ãã§äœ¿çšããŠããã®ãšåãã¢ãããŒãã®ãã1ã€ã¯ããã®çš®ã®ããã©ãŒãã³ã¹ã®åé¡ãå æããããã«ã代æ¿ããŒã ãŸãã¯AngularããŒã ãå¥ã®ãœãªã¥ãŒã·ã§ã³ïŒç§ã¯ä¿¡ããŠããŸãïŒãæäŸããå¿ èŠãããããšãèŠã€ããå¿ èŠããããŸãã ã§ããããããã¯å€§ããªåé¡ã§ã¯ãªããšæããŸãã ããã©ãŒãã³ã¹ã®åé¡ã«ã€ããŠã¯ãæ¢åã®ã¢ãããŒããšã»ãã¿ãŒã¡ãœããã®ã¢ãããŒããæ¯èŒããŠãã ããïŒããã¯ãªãã·ã§ã³ã§ããéçºããŒã ã¯ãAngularã®ChangeDetectionStrategyãšåãããã«éžæã§ããŸããéžæã«ã€ããŠã¯ãrxwebããã¥ã¡ã³ããµã€ãã®äŸãåç §ããŠãã ããããã®å Žåãå€ã®å€æŽããµãã¹ã¯ã©ã€ããããšãã«åŒã³åºããŠããé¢æ°ã®æ°ãå€æããå€ãèšå®ããåŸããŸãã¯setterã¡ãœãããçŽæ¥åŒã³åºããåŸãå€ã®å€æŽã«æ¯ã¹ãŠã³ãŒãã®å®è¡ãå°ãªãããã«ãã®ãµã€ãºãå°ãããšããç¹ã§ãããã¯ã¯ããã«çŽæçã ãšæããŸãããã±ãŒãžãã³ãŒãã®èªã¿ãããããã®ä»å€ãã®åªããç¹ã
ããããã£ã®æ··åïŒããã§ãããªãã®æèŠã¯ããµãŒããŒãè¿ããããããã£åãšã¯ç°ãªãFormControlããããã£åãå²ãåœãŠãŠãããšããããšã§ãã ã¯ãã®å ŽåããµãŒããŒã«æçš¿ããåã«ããããã£åãå€æŽããå¿
èŠããããããããã¯ã³ãŒãã®å€§ããªåé¡ã§ãããšèšããŸããç³ãèš³ãããŸããããã¢ããªã±ãŒã·ã§ã³å
šäœã§ããããã£åãå€æŽããããšã¯æãŸãããããŸããã å¹³å40以äžã®ãã£ãŒã«ããå«ãç§ã®ã¢ããªã±ãŒã·ã§ã³ãã©ãŒã ã«å¯Ÿããããªãã®è¯ãæèŠãèãããšããã¹ãŠã®ããããã£å€ãæåã§èšå®ããå¿
èŠããããŸããå€ãšè£œåãã«ããµã€ãºãå²ãåœãŠãããã®ã³ã³ããŒãã³ãã®ã³ãŒãã«ã€ããŠèããŠã¿ãŠãã ããã ããã¯ã¯ã©ã¹ã¢ãããŒããããè¯ãæèŠã§ããïŒ
ããã§ãææ¡ããããœãªã¥ãŒã·ã§ã³ã«ã€ããŠèª¬æããŸãã2ã€ã®ãã®ã1ã€ã«æ··åããŠããããã§ã¯ãããŸããã FormControlããããã£ã¯ç°ãªããã¯ã©ã¹ããããã£ã¯ããããã®ããŒã¿åãšã¯ç°ãªããŸãã FormControlããããã£åãDataããããã£ãšç°ãªããªã©ãããããã£åãå€æŽããå Žåã¯ãrxwebãªã¢ã¯ãã£ããã©ãŒã ããã±ãŒãžã®ããã¥ã¡ã³ããåç
§ããŠãã ããã ãããã£ãŠãææ¡ãããã¢ãããŒãã§ã¯ãæªãæãïŒããããã£åãšãã©ãŒã ã³ã³ãããŒã«åã®æ··åïŒã解決çã«ãªããããåé¡ã¯ãããŸããã
ç§ã¯ããªãã®æžå¿µã®ãã¹ãŠã«çããããšãé¡ã£ãŠããŸããããã«é¢ããä»ã®æžå¿µãããã°é æ ®ãªãå ±æããŠãã ãã:)ã
以åã®ã³ã¡ã³ãã§è¿°ã¹ãããã«ãReactive Formã®åºæ¬ã¯ã©ã¹ãå€æŽããå¿ èŠã¯ãããŸãããããã¯ãã€ã³ã¿ãŒãã§ã€ã¹åé¢ã®ååã®å®è·µã®åã䜿çšããŠåãããšãéæã§ããããã§ãã ããã¯ã @ rxweb / typesã®ããã±ãŒãžã䜿çšãããšã³ãããŒãšã³ãã®åŒ·ãåã®åå¿åãœãªã¥ãŒã·ã§ã³ã§ãã ããã¯ãã€ã³ã¿ãŒãã§ã€ã¹ããã³ã¯ã©ã¹ã¢ãããŒãã§ããŸãæ©èœããŸã:)ã
StackblitzïŒãªãŒãã³
Github ïŒã€ã³ã¿ãŒãã§ãŒã¹é§ååã®åŒ·ãåã®ãªã¢ã¯ãã£ããã©ãŒã ã®äŸ
誰ããåãããšãèªç±ã«å ±æããææ¡ããããŸãã
ãããã£ãŠã Angularã®ããŒãžã§ã³10ãå©çšå¯èœã«ãªããŸãããããã¯ã¡ãžã£ãŒãªãªãŒã¹ã§ãããæããã«ãªã¢ã¯ãã£ããªãã©ãŒã ã¯ãå°ãªããšãAngularã®ããŒãžã§ã³11ãŸã§åŒ·ãåä»ããããŸããã ãããã£ãŠããã®æ©èœãå®è£ ããã«ã¯ãå°ãªããšãç§ãŸã§åŸ ã€å¿ èŠããããŸãã
ããã§èŠãã»ãšãã©ã®ææ¡/ PRã§ãã©ãŒã ã¢ãã«ãæ§ç¯ããæ¹æ³ã«ã€ããŠè³ªåïŒãŸãã¯ææ¡ïŒïŒããããŸãã
Reactive Formsã¿ã€ããå®å šã«ããããšããŠããã»ãšãã©ã®ã©ã€ãã©ãªãšPRãèŠããšã次ã®ãããªã¢ãã«ãäœæãããŠããããšãããããŸãã
interface Address {
name: Name;
}
interface Name {
firstName: string;
lastName: string;
}
次ã«ãããã¯æ¬¡ã®ãããªãã®ã«ãå€æããããŸãã
const myForm = new FormGroup<Address>({
name: new FormGroup<Name>({
firstName: new FormControl('John'),
lastName: new FormControl('Doe'),
})
})
ã€ãŸããç°¡åã«èšããšãããªããžã§ã¯ãã®å Žåã¯ããã®ããã®FormGroupãäœæããŸããé åã®å Žåã¯ãFormArrayãäœæããŸããããªããã£ãå€ã®å Žåã¯ãFormControlãäœæããŸããã
ãã ãã1ã€ã®åé¡ããããŸããFormControlsã§ãªããžã§ã¯ãã䜿çšã§ããªããªããŸããã
ç§ããããŸã§ã«èŠã解決çïŒäžéšã®ã©ã€ãã©ãªã¯åã«ããããµããŒãããŠããŸããã ãŸããäžéšã®ã©ã€ãã©ãªã¯ãããçš®ã®ãããã¯ãã䜿çšããŠãFormGroupã®ä»£ããã«FormControlãå®éã«äœ¿çšããããšãããã³ããäœæããŸãã
ç§ã®è³ªå/ææ¡ïŒãã©ãŒã ã¢ãã«ã次ã®ããã«æ瀺çã«å®çŸ©ããããšã«å察ãããã®ã¯äœã§ããïŒ
interface Address {
name: FormGroup<Name>;
}
interface Name {
firstName: FormControl<string>;
lastName: FormControl<string>;
}
const myForm = new FormGroup<Address>({
name: new FormGroup<Name>({
firstName: new FormControl('John'),
lastName: new FormControl('Doe'),
})
})
ããã«ã¯ããªããžã§ã¯ããFormControlsã«é 眮ã§ãããšãã倧ããªå©ç¹ããããŸãã ãããŠãããããããã«ã©ããªçš®é¡ã®ãããã¯ããå¿ èŠãšããŸãã:)
ãã®ããã®Codesandboxãäœæããã®ã§ãèªåã§è©ŠããŠã¿ãããšãã§ããŸãïŒ https ïŒ//codesandbox.io/s/falling-grass-k4u50ïŒfile = / src / app / app.component.ts
@MBuchalik ãã¯ããããã¯ã匷ãåã®ãã©ãŒã ãã§äœæ¥ãéå§ãããšãã«é ã«æµ®ãã¶æåã®æçœãªæ±ºå®ã§ãã ç§ãããããå§ããŸããããããã«ã¯é倧ãªæ¬ ç¹ããããŸãã1ã€ã¯ãã©ãŒã ã³ã³ãããŒã«çšããã1ã€ã¯ãã©ãŒã å€çšã®2ã€ã®ã¢ãã«ãäœæããå¿ èŠããããŸãã
äžæ¹ãç§ãç解ããŠããéãããã®ãœãªã¥ãŒã·ã§ã³ã§ã¯ãå€æŽãå£ãããšãªãã匷ãåã®ãã©ãŒã ããå®è£ ã§ããAngularã®æ¬¡ã®ã¡ãžã£ãŒããŒãžã§ã³ã®ãªãªãŒã¹ãåŸ ã€å¿ èŠã¯ãããŸããã ããã§ã¯ããã®ãããªãœãªã¥ãŒã·ã§ã³ãå®éã«äœ¿çšããŠã2ã€ã®ã¢ãã«ãäœæããå¿ èŠæ§ãããé倧ãªæ¬ ç¹ããããã©ãããè©äŸ¡ããå¿ èŠããããŸãã
@MBuchalikç§ã¯ããªããšåãæèŠãå ±æãã PRã«åã質åãæèµ·ããè§åºŠã®ããè²¢ç®è ã®1äººïŒ @KostyaTretyak ïŒãåçããŸããã
ããªãã¯PRã®è°è«ãèŠããããããŸããïŒ
https://github.com/angular/angular/pull/37389#discussion_r438543624
TLDR;
ããã«ããã€ãã®åé¡ããããŸãïŒ
ããªãã®ã¢ãããŒãã«åŸãå Žåããã©ãŒã ã³ã³ãããŒã«çšãšãã©ãŒã å€çšã®2ã€ã®ç°ãªãã¢ãã«ãäœæããå¿ èŠããããŸãã
ãã©ãŒã ã³ã³ãããŒã«ã®ã¢ãã«ã¯èªã¿ã«ããã§ãã
ãããŠãç§ã¯å幎åã«ãã§ã«æ¬çªç°å¢ã§äœ¿çšãããŠfullTemplateTypeCheck
æå¹ã«ãªã£ãŠããå ŽåïŒ
ç§ã¯ãã®ã¹ã¬ããã®ä»¥åã®ã³ã¡ã³ãã§ããªãç§ããã®ããã«è¡ãã®ãããå
±æããŸããïŒ
https://github.com/angular/angular/issues/13721#issuecomment -643214540
Codesanboxãã¢ïŒ https ïŒ//codesandbox.io/s/github/gaplo917/angular-typed-form-codesandbox/tree/master/ïŒfontsize = 14ïŒhidenavigation = 1ïŒtheme = dark
@KostyaTretyakãš@ gaplo917ã®æŽå¯ã«æè¬ããŸãïŒ ð
æ£ããç解ã§ããã°ã次ã®ããã«ãŸãšããããšãã§ããŸãã
åäžã®ã¢ãã«ã®ã¿ã䜿çšããå Žåã¯ã @ KostyaTretyakãæäŸãããããªãœãªã¥ãŒã·ã§ã³ã䜿çšã§ããŸãã ãã ããæ¬ ç¹ã¯ãFormControlsã§ãªããžã§ã¯ãã䜿çšã§ããªããªã£ãããšã§ãã ïŒãããå¯èœã«ãããããã¯ããããããšã¯ç¥ã£ãŠããŸããããããã¢ãã«ã¯åã³ãã¯ãªãŒã³ãã§ã¯ãªããããããäžåºŠ2ã€ã®ã¢ãã«ãå¿ èŠã«ãªããŸããïŒ
FormControlsã§ãªããžã§ã¯ãã䜿çšã§ããããã«ãããå Žåã¯ãããããïŒïŒïŒå³ã®ãããªã¢ãããŒãã䜿çšããæ¹æ³ã¯ãããŸããïŒãŸãã¯@ gaplo917ïŒã æ¬ ç¹ã¯ãåºæ¬çã«2ã€ã®ã¢ãã«ãå¿ èŠãªããšã§ãã ãŸãã¯ãå°ãªããšãããã€ãã®ãã«ããŒã¿ã€ãã䜿çšããŠããã©ãŒã å€ã¢ãã«ããæœåºãããŸãã
ãããã£ãŠãFormControlsã®ãªããžã§ã¯ããå¯èœãã©ãããèããå¿ èŠããããŸãã ããã¯ã2ã€ã®ã¢ãããŒãã®ã©ã¡ããéžæãããã«é¢ãã質åã«çããã ãã§ãã ãããšãç§ã¯äœãã足ããªãã®ã§ããïŒ
@KostyaTretyakãš@ gaplo917ã®æŽå¯ã«æè¬ããŸãïŒ ð
æ£ããç解ã§ããã°ã次ã®ããã«ãŸãšããããšãã§ããŸãã
åäžã®ã¢ãã«ã®ã¿ã䜿çšããå Žåã¯ã @ KostyaTretyakãæäŸãããããªãœãªã¥ãŒã·ã§ã³ã䜿çšã§ããŸãã ãã ããæ¬ ç¹ã¯ãFormControlsã§ãªããžã§ã¯ãã䜿çšã§ããªããªã£ãããšã§ãã ïŒãããå¯èœã«ãããããã¯ããããããšã¯ç¥ã£ãŠããŸããããããã¢ãã«ã¯åã³ãã¯ãªãŒã³ãã§ã¯ãªããããããäžåºŠ2ã€ã®ã¢ãã«ãå¿ èŠã«ãªããŸããïŒ
FormControlsã§ãªããžã§ã¯ãã䜿çšã§ããããã«ãããå Žåã¯ãããããïŒïŒïŒå³ã®ãããªã¢ãããŒãã䜿çšããæ¹æ³ã¯ãããŸããïŒãŸãã¯@ gaplo917ïŒã æ¬ ç¹ã¯ãåºæ¬çã«2ã€ã®ã¢ãã«ãå¿ èŠãªããšã§ãã ãŸãã¯ãå°ãªããšãããã€ãã®ãã«ããŒã¿ã€ãã䜿çšããŠããã©ãŒã å€ã¢ãã«ããæœåºãããŸãã
ãããã£ãŠãFormControlsã®ãªããžã§ã¯ããå¯èœãã©ãããèããå¿ èŠããããŸãã ããã¯ã2ã€ã®ã¢ãããŒãã®ã©ã¡ããéžæãããã«é¢ãã質åã«çããã ãã§ãã ãããšãç§ã¯äœãã足ããªãã®ã§ããïŒ
@MBuchalikç§ã®æèŠã§ã¯ã çšæããå¿
èŠã¯ãããŸããã å
éšã·ã¹ãã ã«ã¯60以äžã®ãã©ãŒã ãããããã®ãã¡ã®ããã€ãã¯3ã€ã®æ·±ãã¬ãã«FormArray-FormGroup-FormArray
ãã¹ããããéåžžã«è€éã§ãããå€åã®æ瀺çãªã¢ãã«ãå¿
èŠãããŸããã
䜿çšã§ããããŒã¿ã¢ãã«ã¯2çš®é¡ã®ã¿ã§ãã
99.9ïŒ ã®æéãç§ãã¡ã¯
次ã®ã³ãŒãã¹ããããã¯å³ã§ãã
interface FooApiData {
id: string
age: number
dob: string | null
createdAt: string
}
interface FooFormControlType {
id: TypedFormControl<string>
age: TypedFormControl<number>
// calendar view required JS date form control binding
dob: TypedFormControl<Date | null>
}
interface FooApiUpdateRequest {
id: string
dob: string | null
age: number
}
class FooForm extends TypedFormGroup<FooFormControlType> {
constructor(private fb: TypedFormBuilder, private initialValue: FooApiData) {
super({
id: fb.control(initialValue.id, Validators.required),
dob: fb.control(initialValue.dob === null ? new Date(initialValue.dob) : null),
age: fb.number(initialValue.age, Validators.required)
})
}
toRequestBody(): FooApiUpdateRequest {
const typedValue = this.value
return {
id: typedValue.id,
dob: typedValue.dob !== null ? moment(typedValue.dob).format('YYYYMMDD') : null,
age: typedValue.age
}
}
}
const apiData = apiService.getFoo()
const form = new FooForm(new TypedFormBuilder(), apiData)
// assume some UI changes the form value
function submit() {
if(form.dirty && form.valid){
const payload = form.toRequestBody()
apiService.updateFoo(payload)
}
}
PSããã¯ãTypescriptã§ã¿ã€ãã»ãŒãã«ããã°ã©ãã³ã°ã楜ããããšãã§ããæèŠã®ããããŒã¿ãããŒã¢ãŒããã¯ãã£ã§ãã
åäžã®ã¢ãã«ã®ã¿ã䜿çšããå Žåã¯ã @ KostyaTretyakãæäŸãããããªãœãªã¥ãŒã·ã§ã³ã䜿çšã§ããŸãã ãã ããæ¬ ç¹ã¯ãFormControlsã§ãªããžã§ã¯ãã䜿çšã§ããªããªã£ãããšã§ãã ïŒãããå¯èœã«ãããããã¯ããããããšã¯ç¥ã£ãŠããŸããããããã¢ãã«ã¯åã³ãã¯ãªãŒã³ãã§ã¯ãªããããããäžåºŠ2ã€ã®ã¢ãã«ãå¿ èŠã«ãªããŸããïŒ
ããã§ãã FormControl
ãªããžã§ã¯ãã䜿çšããå¿
èŠãããé »åºŠãèŠç©ããå¿
èŠããããŸãã ã©ããã§5ã30ïŒ
ãšèŠç©ããããšãã§ãããšæããŸãã ã€ãŸãã1ã€ã®ã¢ãã«ã§ãœãªã¥ãŒã·ã§ã³ã䜿çšããå Žåã FormControl
ã䜿çšããã±ãŒã¹ã®70ã95ïŒ
ãã«ããŒã§ããŸãã æ®ãã®éšåã«ã€ããŠã¯ãTypeScriptã®ãã³ããè¿œå ã®ã¿ã€ããšããŠæäŸããã ãã§ãïŒ Control<T>
ããããã2çªç®ã®ã¢ãã«ããšåŒã¶ã®ã¯æ£ãããããŸããïŒã
interface FormModel {
date: Control<Date>;
}
Control<T>
ã¿ã€ãã¯ããã¯ãšåŒã¶ããšãã§ããŸããïŒ -ã¯ããããã¯ããããããã¯ã§ããã倧ãŸããªããã¯ã§ã¯ãããŸããã ãã®ã¿ã€ããæå³ãããšããã«æ©èœããªãããŸãã¯å¯äœçšãããå Žåã¯ããããŸããã
ããããã©ãŒã å€ã¢ãã«ã«å€éšã©ã€ãã©ãªã䜿çšããå¿
èŠãããå Žåã®Control<T>
å¯äœçšãæãåºããŸããã ãã®ãããªå Žåã2ã€ã®ã¢ãã«ãå®éã«å¿
èŠã§ãã
import { FormBuilder, Control } from '@ng-stack/forms';
// External Form Model
interface ExternalPerson {
id: number;
name: string;
birthDate: Date;
}
const formConfig: ExternalPerson = {
id: 123,
name: 'John Smith',
birthDate: new Date(1977, 6, 30),
};
interface Person extends ExternalPerson {
birthDate: Control<Date>;
}
const fb = new FormBuilder();
const form = fb.group<Person>(formConfig); // `Control<Date>` type is compatible with `Date` type.
const birthDate: Date = form.value.birthDate; // `Control<Date>` type is compatible with `Date` type.
ãããããã®ã³ãŒãã§ã¯ããªãŒããŒãããã¯ããã«ã®ã¿ãããŸãã
interface Person extends ExternalPerson {
birthDate: Control<Date>;
}
@ArielGuetaã®ãããã§ã Control<T>
ã¿ã€ãã®é倧ãªåé¡ãå€æããŸããã ã€ãŸãã以åã«èšç»ããããã«ãAngularã®å°æ¥ã®ãã«ãªã¯ãšã¹ãã§Control<T>
ãå®è£
ããããšããããŸããã
@ArielGuetaã®ãããã§ã
Control<T>
ã¿ã€ãã®é倧ãªåé¡ãå€æããŸããã ã€ãŸãã以åã«èšç»ããããã«ãAngularã®å°æ¥ã®ãã«ãªã¯ãšã¹ãã§Control<T>
ãå®è£ ããããšããããŸããã
@KostyaTretyakããã¯çå®ã§ã¯ãããŸããã éèŠãªåé¡ã¯ããControlTypeãã®å®è£ ãæ£ãããªãããšã瀺ããŠããã ãã§ãã
å®å šãªãå¶åŸ¡ã¿ã€ããã®å®è£ ã«ã¯åé¡ã¯ãããŸããã
ã©ã€ããã¢ïŒ https ïŒ//codesandbox.io/s/lucid-bassi-ceo6t = / src / app / demo / forms / type -test.ts
ã€ãŸããç§ã¯ã³ã³ãããŒã«ãå®è£ ããããšããããŸãã
以åã«èšç»ããããã«ãå°æ¥ã®Angularã®ãã«ãªã¯ãšã¹ãã
OKãã€ãŸããPRïŒããã³é£ç¶ããPRïŒã¯FormControlsã®ãªããžã§ã¯ãããµããŒãããªãå¯èœæ§ãé«ããšããããšã§ããïŒ
@MBuchalik ãçŸæç¹ïŒAngular v10ïŒã次ã®ãã©ãŒã ã¢ãã«ãããå ŽåïŒ
interface FormModel {
date: Date;
}
ãŸããã³ã³ããŒãã³ãã§date
ããããã£ã®å€ã«ã¢ã¯ã»ã¹ããå Žåã¯ã次ã®æé ãå®è¡ããå¿
èŠããããŸãã
get date() {
return this.formGroup.get('date') as FormControl;
}
// ...
this.date.value as Date;
ç§ã®çŸåšã®ãã«ãªã¯ãšã¹ãã¯ããã©ãŒã å€ã®ãžã§ããªãã¯ãæäŸããŸããããã©ãŒã ã³ã³ãããŒã«ã®ã¿ã€ããæäŸããŸããã
get date() {
return this.formGroup.get('date') as FormControl<Date>;
}
// ...
this.date.value; // Here Date type
@ gaplo917ã@MBuchalikãç§ã¯ããªãã®ãœãªã¥ãŒã·ã§ã³ãè©Šã¿ãããç§èªèº«ã®åæ§ã®ãœãªã¥ãŒã·ã§ã³ãå®è£ ããããšããŸãããããããã¯ãã¹ãŠå®ç§ã«åäœããŸããããŸããã ãã®ãœãªã¥ãŒã·ã§ã³ã¯ããã©ãŒã ã¢ãã«å€ãååž°çã«æœåºããããã®äžé£ã®ã¿ã€ããæäŸããŸãã ãªãŒããŒããããšé倧ãªå€æŽã¯éåžžã«éèŠã§ããPRãã©ãããåç §ããŠãã ããã
çŸæç¹ã§ã¯ããããã®ãœãªã¥ãŒã·ã§ã³ãAngularã§å®è£ ããããã«ææ¡ããå¿ èŠããããã©ããã¯éåžžã«çãããã§ãã ã€ãŸããä»ã®ãšããããžã§ããªãã¯ã¹ã¯ãã©ãŒã ã³ã³ãããŒã«ã¿ã€ãã§ã¯ãªãããã©ãŒã å€ã«ã®ã¿äœ¿çšããå¿ èŠããããŸãã
ãããããããã¯ãã¹ãŠå®å šã«ã¯æ©èœããŸãã
ã€ã©ã¹ãã«æ°æéããè²»ãããŠããªãã®ã§ãå®ç§ã ãšã¯æã£ãŠããŸããã§ãã;ïŒããŸããããªãããšã®äŸãæããŠãã ããã ïŒç¹ã«ãããªãã®èŠ³ç¹ãããç°¡åã«ä¿®æ£ã§ããªããã®ã«ã€ããŠã¯ïŒïŒ
ãšããã§ãäžäœäºææ§ã«é¢ãã1ã€ã®ææ¡ïŒç§ã®èŠ³ç¹ããã¯ãå®è£
ãå®å
šã«äžäœäºæã«ããããšã¯æ¯èŒçå°é£ã§ãã ãã®ããã次ã®ããšãã§ããå¯èœæ§ããããŸããFormControlãFormGroupãããã³FormArrayã¯ã©ã¹ã¯ãŸã£ããå€æŽããŸããã 代ããã«ãããããç¶æ¿ããæ°ãããã®ãäœæããŸãïŒãããããããããStrictFormControl<T>
ããã³StrictFormGroup<T>
ãªã©ãšåŒã³ãŸãïŒã ãããã¯ãã¿ã€ãã»ãŒãã«ãããã®ã§ãã å©ç¹ïŒé倧ãªå€æŽãè¡ãããªãããšã100ïŒ
確信ããŠããŸãã :)
ç§ã®ã€ã©ã¹ãã¯æ°æéãªã®ã§ãå®ç§ã ãšã¯æã£ãŠããŸããã§ãã;ïŒ
ç§ã¯ãã®ãœãªã¥ãŒã·ã§ã³ãæ°æ¥é䜿çšããŸãããããã©ãŒã ã䜿çšããã®ãã©ãã»ã©é£ããããããããŸãã
Control<T>
ã¿ã€ãã®ãœãªã¥ãŒã·ã§ã³ãããåªããŠããŸãããããã¯ãåãæ¹æ³ã§ãã©ãŒã ã¢ãã«ã®å€ãååž°çã«æœåºããå¿
èŠãããããã§ããinterface FormModel {
one: FormGroup<{two: FormControl<string>}>;
}
ãããŠã formGroup.controls.one.value
ãååŸããå ŽåãTypeScriptã¯ã {two: string}
ã¿ã€ãã§ã¯ãªããæ¡ä»¶ä»ãã¿ã€ãã§ãã³ããæäŸããŸãïŒæ¬æ¥ããã¹ã姿ã§ãïŒã ãããã£ãŠãIDEããèªã¿åãã®ã¯é£ãã䟡å€ããããŸãã
ãããŠãformGroup.controls.one.valueãååŸãããšãTypeScriptã¯ã{twoïŒstring}åã§ã¯ãªããæ¡ä»¶ä»ãåã®ãã³ããæäŸããŸãïŒæ¬æ¥ããã¹ã姿ïŒã ãããã£ãŠãIDEããèªã¿åãã®ã¯é£ãã䟡å€ããããŸãã
OKãããã§ç§ããã¹ãŠãæ£ããç解ããããšã確èªããããã ãã«ã ç§ã®å®è£ ã䜿çšããŠã次ã®ããã«èšè¿°ããå ŽåïŒ
interface FormModel {
one: FormGroup<Two>;
}
interface Two {
two: FormControl<string>;
}
const myForm = new FormGroup<FormModel>({
one: new FormGroup<Two>({
two: new FormControl('')
})
});
ïŒããå°ãåé·ã«ããŸãã;ïŒïŒ
myForm.controls.one.value
ãæ¢ããšã次ã®ããã«ãªããŸãã
ã€ãŸãããã®äŸã§ã¯ãã2ã€ãã¯ãªãã·ã§ã³ã§ã¯ãªããšããããšã§ããïŒ ããã¯ãã©ãŒã ã®å€ãå ¥åããæ£ããæ¹æ³ã§ã¯ãªããšæããŸãã ãã©ãŒã ã®å€ã«ã¯ãç¡å¹ã«ãªã£ãŠããªããã£ãŒã«ãã®ã¿ãå«ãŸããŸãã ãããã£ãŠãç§ã®èŠ³ç¹ããã¯ãååž°çãªããŒã·ã£ã«ã§ããå¿ èŠããããŸãã ã³ã³ãã€ã«æã«ãã©ã®ãã£ãŒã«ããç¡å¹ã«ãªããã©ã®ãã£ãŒã«ããç¡å¹ã«ãªãããç¥ãããšã¯ã§ããŸããã
ã€ãŸãããã®äŸã§ã¯ãã2ã€ãã¯ãªãã·ã§ã³ã§ã¯ãªããšããããšã§ããïŒ
äœïŒ ãããã
ããªãã®ãœãªã¥ãŒã·ã§ã³ã®ç§ã®ãã¹ãïŒ
interface FormModel {
one: FormGroup<{two: FormControl<string>}>;
}
let formGroup: FormGroup<FormModel>;
const some = formGroup.controls.one.value;
value
ããŠã¹ã眮ããåŸã«
(property) FormGroup<FormGroupControls<{ two: FormControl<string>; }>>.value: PartialFormGroupValue<FormGroupControls<{
two: FormControl<string>;
}>>
ããã§ã PartialFormGroupValue
ã¯ãæ¡ä»¶ä»ãã¿ã€ãPartialFormValue
æããŸãã
ãããããããŸãããç§ã¯ãããæã«å ¥ãããšæããŸãã ã€ãŸããã¿ã€ããèªã¿ã«ãããšããããšã§ããïŒ ç§ã¯ããšããšããªãããã°ããã®ãããªäœãã«ã€ããŠè©±ããŠãããšæã£ãŠããŸããã
ããŠãã»ãšãã©ã®IDEã¯ãå
¥åãç¶ãããšãå©çšå¯èœãªããããã£ã®ææ¡ã衚瀺ããã ãã§ãã ã§ããããããã§ã¯å€§ããªåé¡ã¯èŠãããŸããã ïŒãã¡ããã {two?: string}
ãšã ãæžãããŠããå Žåã¯ãèªãã ã»ããããã§ããããããããããã¯ããã»ã©éèŠã§ã¯ãªããšæããŸããå°ãªããšãç§ã®æèŠã§ããïŒ
Control<T>
ãå®è£
ããå Žåãç§ãè¡ã£ãããã«sthãå®è¡ããã«ããã©ãŒã å€ã®å
¥åãããããã©ã®ããã«åé€ããŸããïŒ ãŸãããã«ããŒã¿ã€ãã䜿çšããã«ããã©ãŒã å€ãååž°çããŒã·ã£ã«ã«ããã«ã¯ã©ãããã°ããã§ããããã
ã³ã³ãããŒã«ãå®è£ ããå Žå
ãããã§ã¯ãç§ãè¡ã£ãããã«sthãå®è¡ããã«ããã©ãŒã å€ã®å ¥åãããããã©ã®ããã«åé€ããŸããïŒ ãŸãããã«ããŒã¿ã€ãã䜿çšããã«ããã©ãŒã å€ãååž°çããŒã·ã£ã«ã«ããã«ã¯ã©ãããã°ããã§ããããã
ãã®å Žåãç§ã®è§£æ±ºçã¯è¯ããããŸããïŒ
(property) FormGroup<FormGroup<{ two: FormControl<string>; }>>.value: ExtractGroupValue<FormGroup<{
two: FormControl<string>;
}>>
ããªãããããæ±ããã®ã§ãç§ã¯ãã®äŸãäžããŸããïŒ
ããŸããããªãããšã®äŸãæããŠããã ããŸããïŒ ïŒç¹ã«ãããªãã®èŠ³ç¹ãããç°¡åã«ä¿®æ£ã§ããªããã®ã«ã€ããŠã¯ïŒïŒ
ã¡ãªã¿ã«ã Control<T>
é倧ãªåé¡ãä¿®æ£ããŸããã
Angular 10ãš[formControl]
ã§ã®HTMLãã€ã³ãã£ã³ã°ã®åé¡ã解決ããããã«ããããç§ãè¡ã£ãã«ãŒãã§ãã
å¥ã®åé¡ïŒhttps://github.com/angular/angular/issues/36405#issuecomment-655110082ïŒã«èšèŒãããŠããããã«ãç§ã®ãã©ãŒã ã§ã¯éåžžãåå©çšæ§ãšãã¹ãã容æã«ããããã«FormGroup
ãæ¡åŒµããã¯ã©ã¹ãäœæããŸãã ãã®æ§é ã§ã次ã®ãããªã³ãŒããæŽæ°ããããšã§ãä»ã®ãšããåé¡ã解決ããããšãã§ããŸããã
class UserFormGroup extends FormGroup {
constructor() {
super({
id: new FormControl(null, Validators.required),
name: new FormControl(null, Validators.required),
});
}
ããã«ïŒ
// everything will extend these two
export class EnhancedFormGroup<T extends { [key: string]: AbstractControl }> extends FormGroup
{
controls!: T;
}
export class EnhancedFormArray<T extends AbstractControl> extends FormArray
{
controls!: T[];
}
// reworked form from above
function formDefinition() {
return {
id: new FormControl(null, Validators.required),
name: new FormControl(null, Validators.required),
};
}
class UserFormGroup extends EnhancedFormGroup<ReturnType<typeof formDefinition>> {
constructor() {
super(formDefinition());
}
ãã®æç¹ã§ã form.controls
ã¯ãã®ã¿ã€ãã{ id: FormControl, name: FormControl }
ãšããŠæ£ãã衚瀺ããHTMLã§æ£ãããã€ã³ããããã©ãŒã ããã¹ãããããã©ãŒã ã°ã«ãŒããŸãã¯é
åã§ããè€éãªå Žåã¯æ£ããéçŽãããŸãã
formDefinition
é¢æ°ã䜿çšããã®ã¯èŠæ ãããããããŸãããããã©ãŒã å®çŸ©ãšã³ã³ã¹ãã©ã¯ã¿ãŒã®éã®éè€ãé²ãããã«ç§ãæãã€ããæãã¯ãªãŒã³ãªãœãªã¥ãŒã·ã§ã³ã§ããã
FormGroup
ãæŽæ°ããŠãé倧ãªå€æŽãå°å
¥ããã«äžèšã®ãžã§ããªãã¯åã®å®çŸ©ãèšå®ã§ãããšæããŸãïŒãŸããããã¯ãã³ã³ãããŒã«ãåçã«è¿œå /åé€ãããã©ãŒã ã«ã¯åœãŠã¯ãŸããªãå¯èœæ§ããããŸãã controls
ã¯è¡šç€ºãããŸããã
ç·šé
FormGroupãæ¡åŒµããã¯ã©ã¹ãäœæããå¿
èŠããªãå Žåã¯ãããã«ç°¡åã«èŠããŸãã äžè¬çãªåé¡ã解決ãããã«ããŒé¢æ°ãäœæã§ããŸãã
function createEnhancedFormGroup<T extends { [key: string]: AbstractControl }>(controls: T) {
return new EnhancedFormGroup<T>(controls);
}
const form = createEnhancedFormGroup({
id: new FormControl(null, Validators.required),
name: new FormControl(null, Validators.required),
});
ç·šé2
...ãŸãã¯ã FormGroup
ã¯ã©ã¹èªäœã«ãã€ã¯ããããšãã§ããŸãïŒ FormBuilder
ãããããŸãããïŒïŒ
export class EnhancedFormGroup<T extends { [key: string]: AbstractControl }> extends FormGroup
{
controls!: T;
static create<T extends { [key: string]: AbstractControl }>(controls: T) {
return new EnhancedFormGroup<T>(controls);
}
}
const form = EnhancedFormGroup.create({
id: new FormControl(null, Validators.required),
name: new FormControl(null, Validators.required),
});
ç·šé3
äžèšã®äŸãæ¡åŒµããŠã value
ã®å
¥åãå«ãããã¹ãŠãèŠçŽããèšäºãäœæããŸããã
https://medium.com/youngers-consulting/angular-typed-reactive-forms-22842eb8a181
ããã¯çŸåšãå°æ¥ã®éçºã®ããŒããããã«ããŒã¯ãããŠããŸãïŒ
@pauldraperçŽ2ãæåã®ããŒãããããšæ¯èŒããŠäœãå€ãã£ãã説æããŠ
@MBuchalikããããããã¯2ã¶æéããã«ãããŸããã
æãåèã«ãªãã³ã¡ã³ã
ãããAngularããŒã ããã®ææ°æ å ±ãå ±æããããšæããŸããããã¯å€§ããªåé¡ç¹ã ãšèããŠããŸãã éããªãããã匷ãåä»ãããããã©ãŒã ã®äœæ¥ãéå§ããŸããããã«ã¯ãæ¢åã®PRã確èªãããã¹ãŠã®ã³ã¡ã³ããå床確èªããããšãå«ãŸããŸãã æéãå²ããŠèããæ®ããŠãããçããã«æè¬ããŸãïŒ