diff --git a/src/app/_components/common/dynamic-form-question/dynamic-form-question.component.html b/src/app/_components/common/dynamic-form-question/dynamic-form-question.component.html index 01e83c5..b443dbf 100644 --- a/src/app/_components/common/dynamic-form-question/dynamic-form-question.component.html +++ b/src/app/_components/common/dynamic-form-question/dynamic-form-question.component.html @@ -1,42 +1,60 @@
- - -
- - - - - - - - + + + + +
+ + + + + + +
+ +
{{ question.label }} is required
+ +
+ +
+
+ + + + + + +
-
{{ question.label }} is required
diff --git a/src/app/_components/common/dynamic-form-question/dynamic-form-question.component.ts b/src/app/_components/common/dynamic-form-question/dynamic-form-question.component.ts index 32673b6..676e97e 100644 --- a/src/app/_components/common/dynamic-form-question/dynamic-form-question.component.ts +++ b/src/app/_components/common/dynamic-form-question/dynamic-form-question.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, Input } from '@angular/core'; -import { FormGroup, FormArray, FormControl } from '@angular/forms'; +import { FormGroup, FormArray, FormBuilder, AbstractControl } from '@angular/forms'; -import { QuestionBase, QuestionConfig } from '@app/models'; +import { QuestionBase } from '@app/models'; @Component({ selector: 'app-question', @@ -12,22 +12,37 @@ export class DynamicFormQuestionComponent implements OnInit { @Input() question: QuestionBase; @Input() form: FormGroup; - @Input() config: QuestionConfig; get isValid() { return this.form.controls[this.question.key].valid; } - constructor() { + constructor(private fb: FormBuilder) { } + + ngOnInit() { } + + private asFormArray(ctrl: AbstractControl): FormArray { + return ctrl as FormArray; + } + + public addQuestion(): void { + this.questionArray.push(this.fb.control('')); } - ngOnInit() { + public removeQuestion(index: number): void { + this.questionArray.removeAt(index); + } + + public get questionArray(): FormArray { + return this.form.get(this.question.key) as FormArray; + } - if (this.question.iterable) { - console.log(this.question); - } + public questionControl(index?: number): AbstractControl { + return this.question.iterable ? this.asFormArray(this.form.get(this.question.key)).controls[index] : this.form.get(this.question.key); } - public addItem(question: QuestionBase): void { - ( this.form.get(question.key)).push(new FormControl('')); - console.log(question); + public questionId(index?: number): string { + return this.question.iterable ? `${this.question.key}-${index}` : this.question.key; } + public questionLabel(index?: number): string { + return this.question.iterable ? `${this.question.label} n°${index + 1}` : this.question.label; + } } diff --git a/src/app/_components/common/dynamic-form/dynamic-form.component.html b/src/app/_components/common/dynamic-form/dynamic-form.component.html index fd7c1c3..3f93374 100644 --- a/src/app/_components/common/dynamic-form/dynamic-form.component.html +++ b/src/app/_components/common/dynamic-form/dynamic-form.component.html @@ -5,7 +5,6 @@
diff --git a/src/app/_components/common/dynamic-form/dynamic-form.component.ts b/src/app/_components/common/dynamic-form/dynamic-form.component.ts index 4f3dfe8..a00f02b 100644 --- a/src/app/_components/common/dynamic-form/dynamic-form.component.ts +++ b/src/app/_components/common/dynamic-form/dynamic-form.component.ts @@ -1,7 +1,7 @@ -import { Component, OnInit, Input, Inject } from '@angular/core'; +import { Component, OnInit, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { QuestionBase, QuestionConfig } from '@app/models'; +import { QuestionBase } from '@app/models'; import { QuestionControlService } from '@app/services'; @Component({ @@ -15,10 +15,7 @@ export class DynamicFormComponent implements OnInit { form: FormGroup; payLoad = ''; - constructor( - @Inject('questionConfig') public config: QuestionConfig, - private qcs: QuestionControlService - ) { } + constructor(private qcs: QuestionControlService) { } ngOnInit() { this.form = this.qcs.toFormGroup(this.questions); diff --git a/src/app/_components/common/dynamic-form/dynamic-form.module.ts b/src/app/_components/common/dynamic-form/dynamic-form.module.ts index 5fdcbaf..efbb941 100644 --- a/src/app/_components/common/dynamic-form/dynamic-form.module.ts +++ b/src/app/_components/common/dynamic-form/dynamic-form.module.ts @@ -1,11 +1,10 @@ -import { NgModule, ModuleWithProviders } from '@angular/core'; +import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule, FormsModule } from '@angular/forms'; import { DynamicFormComponent } from './dynamic-form.component'; import { DynamicFormQuestionModule } from '../dynamic-form-question/dynamic-form-question.module'; -import { QuestionConfig } from '@app/models'; import { QuestionControlService } from '@app/services'; @NgModule({ @@ -20,29 +19,4 @@ import { QuestionControlService } from '@app/services'; exports: [DynamicFormComponent] }) export class DynamicFormModule { - - /** - * Use in AppModule: new instance of NgxSmartModal. - */ - public static forRoot(config?: QuestionConfig): ModuleWithProviders { - if (!config) { - config = { validClass: 'valid', invalidClass: 'invalid' }; - } - - return { - ngModule: DynamicFormModule, - providers: [QuestionControlService, { provide: 'questionConfig', useValue: config }] - }; - } - - /** - * Use in features modules with lazy loading: new instance of NgxSmartModal. - */ - public static forChild(): ModuleWithProviders { - return { - ngModule: DynamicFormModule, - providers: [QuestionControlService] - }; - } - } diff --git a/src/app/_models/index.ts b/src/app/_models/index.ts index d15cd44..7e208de 100644 --- a/src/app/_models/index.ts +++ b/src/app/_models/index.ts @@ -1,4 +1,3 @@ -export * from './question-config'; export * from './question-base'; export * from './question-dropdown'; export * from './question-textbox'; diff --git a/src/app/_models/question-config.ts b/src/app/_models/question-config.ts deleted file mode 100644 index deafe94..0000000 --- a/src/app/_models/question-config.ts +++ /dev/null @@ -1,4 +0,0 @@ -export class QuestionConfig { - validClass: string; - invalidClass: string; -} diff --git a/src/app/_models/question-textbox.ts b/src/app/_models/question-textbox.ts index 1956925..0c27058 100644 --- a/src/app/_models/question-textbox.ts +++ b/src/app/_models/question-textbox.ts @@ -3,9 +3,15 @@ import { QuestionBase } from './question-base'; export class TextboxQuestion extends QuestionBase { controlType = 'textbox'; type: string; + min: number | string; + max: number | string; + pattern: string; constructor(options: {} = {}) { super(options); this.type = options['type'] || 'text'; + this.min = options['min']; + this.max = options['max']; + this.pattern = options['pattern']; } } diff --git a/src/app/_services/question-control.service.ts b/src/app/_services/question-control.service.ts index efc7f0b..bb46069 100644 --- a/src/app/_services/question-control.service.ts +++ b/src/app/_services/question-control.service.ts @@ -3,9 +3,7 @@ import { FormGroup, FormControl, Validators, FormArray } from '@angular/forms'; import { QuestionBase } from '@app/models'; -@Injectable({ - providedIn: 'root' -}) +@Injectable() export class QuestionControlService { constructor() { } @@ -17,8 +15,21 @@ export class QuestionControlService { if (question.iterable) { - group[question.key] = question.required ? new FormArray([new FormControl(question.value || '') - ]) : new FormArray([new FormControl(question.value || '')], Validators.required); + if (!Array.isArray(question.value)) { + question.value = !!question.value ? [question.value] : ['']; + } + + const tmpArray: FormArray = question.required ? new FormArray([]) : new FormArray([], Validators.required); + + if (!question.value || !question.value.length) { + tmpArray.push(new FormControl('')); + } else { + question.value.forEach(val => { + tmpArray.push(new FormControl(val)); + }); + } + + group[question.key] = tmpArray; } else { diff --git a/src/app/_services/question.service.ts b/src/app/_services/question.service.ts index 3195f91..85dba94 100644 --- a/src/app/_services/question.service.ts +++ b/src/app/_services/question.service.ts @@ -7,9 +7,7 @@ import { TextareaQuestion } from '@app/models'; -@Injectable({ - providedIn: 'root' -}) +@Injectable() export class QuestionService { // TODO: get from a remote source of question metadata @@ -42,11 +40,21 @@ export class QuestionService { new TextboxQuestion({ key: 'jobs', label: 'Jobs', - value: '', + value: ['toto'], iterable: true, order: 5 }), + new TextboxQuestion({ + key: 'level', + label: 'Level', + type: 'range', + value: 70, + min: 20, + max: 200, + order: 6 + }), + new TextboxQuestion({ key: 'emailAddress', label: 'Email', diff --git a/src/app/app.component.html b/src/app/app.component.html index c47f1d1..6fe4805 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,10 +1,64 @@ + + + + + +
-

Job Application for Heroes

- +

Job Application for Heroes

+

Here is an example of how you can build on-the-fly forms with Angular. The form is the form as defined in The data object. You also can see the changes while you're modifying the form's values in The result section.

+
+
+ +
+
+

The form

+ +
+
+ +
+
+

The result

+
{{ dynamicForm.form.value | json }}
+
+
+ +
+
+

The data object

+
{{ questions | json }}
+
+
+
+ + +
diff --git a/src/app/app.component.scss b/src/app/app.component.scss index e69de29..d23247b 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -0,0 +1,32 @@ +:host { + .github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + + @keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + + 20%, + 60% { + transform: rotate(-25deg); + } + + 40%, + 80% { + transform: rotate(10deg); + } + } + + @media (max-width: 500px) { + .github-corner:hover .octo-arm { + animation: none; + } + + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + } +} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index ef2b82f..8299bdf 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, VERSION } from '@angular/core'; import { QuestionService } from '@app/services'; @@ -10,11 +10,10 @@ import { QuestionService } from '@app/services'; export class AppComponent { questions: any[]; + version = VERSION.full; constructor(service: QuestionService) { this.questions = service.getQuestions(); - - console.log(this.questions); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index dc38e4f..dcaeca3 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -14,10 +14,7 @@ import { QuestionService } from '@app/services'; imports: [ BrowserModule, AppRoutingModule, - DynamicFormModule.forRoot({ - validClass: 'good', - invalidClass: 'bad' - }) + DynamicFormModule ], providers: [QuestionService], bootstrap: [AppComponent] diff --git a/src/styles.scss b/src/styles.scss index f4e4274..d3b74bc 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -6,3 +6,16 @@ .bad { border-color: red !important; } + +textarea { + resize: vertical; +} + +pre { + max-height: 40vh; + overflow: scroll; +} + +button { + margin-right: 5px; +}