Added Dropdown and Hidden Input
This commit is contained in:
@@ -1,22 +1 @@
|
||||
<form #formCounter="ngForm">
|
||||
<counter-input [(ngModel)]="resultCounter" name="res"></counter-input>
|
||||
</form>
|
||||
|
||||
<p>Value:</p>
|
||||
<pre>{{ resultCounter }}</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<form #formTag="ngForm">
|
||||
<tag-input [(ngModel)]="resultTag" name="res" [id]="'a'" [items]="{'alpha': 'A', 'beta': 'B', 'gamma': 'G'}"></tag-input>
|
||||
<tag-input [(ngModel)]="resultTag2" name="res2" [id]="'b'" [items]="{'alpha': 'A', 'beta': 'B', 'gamma': 'G'}" [nullable]="true"></tag-input>
|
||||
</form>
|
||||
|
||||
<p>Value:</p>
|
||||
<pre>{{ resultTag | json }}</pre>
|
||||
<pre>{{ resultTag2 | json }}</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<dyn-form [questions]="formQuestions" (onSubmit)="submit($event)"></dyn-form>
|
||||
<dyn-form [questions]="formQuestions" (onSubmit)="submit($event)" [value]="formValue" [type]="'insert'"></dyn-form>
|
||||
@@ -1,34 +1,57 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {Component} from '@angular/core';
|
||||
import {QuestionInterface} from './modules/dyn-form/types/question.interface';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
|
||||
export class AppComponent {
|
||||
public resultCounter = 10;
|
||||
public resultTag = {"alpha": true, "beta": false};
|
||||
public resultTag2 = {"alpha": true, "beta": false};
|
||||
|
||||
export class AppComponent {
|
||||
public formQuestions: QuestionInterface[] = [
|
||||
{
|
||||
type: "flag",
|
||||
description: "This is a help tooltip",
|
||||
type: 'flag',
|
||||
description: 'This is a help tooltip',
|
||||
properties: {
|
||||
key: "flags",
|
||||
label: "Form Type Flags",
|
||||
key: 'flags',
|
||||
label: 'Form Type Flags',
|
||||
order: 1,
|
||||
|
||||
// dropdown && flags
|
||||
options: [{key: "alpha", value: "A"}, {key: "beta", value: "B"}]
|
||||
options: [{key: 'alpha', value: 'A'}, {key: 'beta', value: 'B'}, {key: 'gamma', value: 'C'}, {key: 'delta', value: 'D'}]
|
||||
}, constraints: {
|
||||
optional: true
|
||||
optional: true
|
||||
}
|
||||
}, {
|
||||
type: 'dropdown',
|
||||
description: 'Cool dropdown',
|
||||
properties: {
|
||||
key: 'cooldrop',
|
||||
label: 'Dropdown',
|
||||
order: 2,
|
||||
methods: ['insert'],
|
||||
|
||||
// dropdown
|
||||
options: [{key: 'hello', value: 'Hallo'}, {key: 'world', value: 'World'}, {key: 'and', value: 'And'}, {key: 'u', value: 'You'}]
|
||||
}, constraints: {
|
||||
optional: false
|
||||
}
|
||||
}, {
|
||||
type: 'hidden',
|
||||
description: 'ID',
|
||||
properties: {
|
||||
key: 'ID',
|
||||
order: 3
|
||||
}, constraints: {
|
||||
optional: false
|
||||
}
|
||||
}
|
||||
];
|
||||
public formValue = {
|
||||
flags: {gamma: true},
|
||||
ID: 5,
|
||||
cooldrop: 'u'
|
||||
};
|
||||
|
||||
submit(value: any) {
|
||||
console.log("send", value);
|
||||
console.log('send', value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import {CustomInputModule} from "./custom-input.module";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { DynFormModule } from './modules/dyn-form/dyn-form.module';
|
||||
import {AppComponent} from './app.component';
|
||||
import {CustomInputModule} from './custom-input.module';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {DynFormModule} from './modules/dyn-form/dyn-form.module';
|
||||
import {HelloService} from './services/hello.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -14,7 +15,11 @@ import { DynFormModule } from './modules/dyn-form/dyn-form.module';
|
||||
CustomInputModule,
|
||||
DynFormModule
|
||||
],
|
||||
declarations: [ AppComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
declarations: [AppComponent],
|
||||
providers: [
|
||||
HelloService
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
export class AppModule {
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@ import {FormControl, FormGroup} from '@angular/forms';
|
||||
selector: 'dyn-form',
|
||||
template: `
|
||||
<form (ngSubmit)="submit()" [formGroup]="form">
|
||||
<dyn-question *ngFor="let question of questions" [question]="question" [form]="form"></dyn-question>
|
||||
<dyn-question *ngFor="let question of questions" [hidden]="question.properties.methods && question.properties.methods.indexOf(type)==-1" [question]="question" [form]="form" [type]="type"></dyn-question>
|
||||
<div class="form-row">
|
||||
<button type="submit">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
`
|
||||
})
|
||||
export class DynFormComponent {
|
||||
export class DynFormComponent implements OnInit {
|
||||
@Input() questions: QuestionInterface[];
|
||||
@Input() value: any;
|
||||
@Input() type: "'insert'|'update'|'delete'|'view'";
|
||||
@@ -22,13 +22,17 @@ export class DynFormComponent {
|
||||
|
||||
private form: FormGroup;
|
||||
|
||||
constructor() {
|
||||
this.form = new FormGroup({
|
||||
'flags': new FormControl({'alpha': true})
|
||||
});
|
||||
public ngOnInit () {
|
||||
let controls = {};
|
||||
for(let i = 0; i < this.questions.length; i++) {
|
||||
let key = this.questions[i].properties.key;
|
||||
controls[key] = new FormControl(this.value[key]);
|
||||
}
|
||||
this.form = new FormGroup(controls);
|
||||
}
|
||||
|
||||
submit() {
|
||||
private submit() {
|
||||
console.log("isValid", this.form.valid);
|
||||
this.onSubmit.emit(this.form.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { DynFormComponent } from './dyn-form.component';
|
||||
import {DynQuestionComponent} from './dyn-question.component';
|
||||
import {CounterInputComponent} from './inputs/counter-input.component';
|
||||
import {KeysPipe, TagInputComponent} from './inputs/tag-input.component';
|
||||
import {DynQuestionComponent} from './dyn-question.component';
|
||||
import {HiddenInputComponent} from './inputs/hidden-input.component';
|
||||
import {DropdownInputComponent} from './inputs/dropdown-input.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@@ -20,6 +22,8 @@ import {DynQuestionComponent} from './dyn-question.component';
|
||||
DynQuestionComponent,
|
||||
CounterInputComponent,
|
||||
TagInputComponent,
|
||||
HiddenInputComponent,
|
||||
DropdownInputComponent,
|
||||
KeysPipe
|
||||
],
|
||||
providers: [],
|
||||
|
||||
@@ -6,11 +6,21 @@ import {FormGroup} from '@angular/forms';
|
||||
selector: 'dyn-question',
|
||||
template: `
|
||||
<div [ngSwitch]="question.type" [formGroup]="form">
|
||||
<label [for]="question.properties.key">{{question.properties.label}}</label>
|
||||
<tag-input *ngSwitchCase="'flag'"
|
||||
[formControlName]="question.properties.key" [id]="question.properties.key"
|
||||
[items]="question.properties.options" [nullable]="question.constraints.optional"
|
||||
(ngModelChange)="change()"></tag-input>
|
||||
<label [for]="question.properties.key">{{question.properties.label}}</label>
|
||||
<tag-input *ngSwitchCase="'flag'"
|
||||
[formControlName]="question.properties.key" [id]="question.properties.key"
|
||||
[nullable]="question.constraints.optional" [readonly]="type=='view'"
|
||||
[items]="question.properties.options"
|
||||
(ngModelChange)="change()"></tag-input>
|
||||
<hidden-input *ngSwitchCase="'hidden'"
|
||||
[formControlName]="question.properties.key" [id]="question.properties.key"
|
||||
[nullable]="question.constraints.optional" [readonly]="type=='view'"
|
||||
(ngModelChange)="change()"></hidden-input>
|
||||
<dropdown-input *ngSwitchCase="'dropdown'"
|
||||
[formControlName]="question.properties.key" [id]="question.properties.key"
|
||||
[nullable]="question.constraints.optional" [readonly]="type=='view'"
|
||||
[items]="question.properties.options"
|
||||
(ngModelChange)="change()"></dropdown-input>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
|
||||
98
src/app/modules/dyn-form/inputs/dropdown-input.component.ts
Normal file
98
src/app/modules/dyn-form/inputs/dropdown-input.component.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import {Component, forwardRef, Inject, Input, OnChanges, Pipe, PipeTransform, SimpleChanges} from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl, ValidationErrors } from '@angular/forms';
|
||||
import {CustomInputComponent} from "./custom-input.component";
|
||||
import {HelloService} from '../../../services/hello.service';
|
||||
|
||||
@Pipe({name: 'keys'})
|
||||
export class KeysPipe implements PipeTransform {
|
||||
transform(value: Object, args:string[]) : any {
|
||||
let keys = [];
|
||||
for (let key in value) {
|
||||
keys.push({key: key, value: value[key]});
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'dropdown-input',
|
||||
template:
|
||||
`
|
||||
<select *ngIf="!readonly" [value]="value" (change)="onChange($event.target.value)">
|
||||
<option *ngFor="let entry of listedItems" [value]="entry.key">{{entry.value}}</option>
|
||||
</select>
|
||||
<div *ngIf="readonly">{{constVal}}</div>
|
||||
`,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => DropdownInputComponent),
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: NG_VALIDATORS,
|
||||
useExisting: forwardRef(() => DropdownInputComponent),
|
||||
multi: true,
|
||||
}]
|
||||
})
|
||||
export class DropdownInputComponent extends CustomInputComponent implements OnChanges {
|
||||
@Input() readonly: boolean = false;
|
||||
@Input() nullable: boolean = false;
|
||||
@Input() items: Array<{key: string, value: string}> = [];
|
||||
private listedItems: Array<{key: string, value: string}> = [];
|
||||
private constVal: string;
|
||||
|
||||
constructor(private helloService: HelloService) {
|
||||
super();
|
||||
helloService.sayHello();
|
||||
}
|
||||
|
||||
// set initial value
|
||||
public writeValue(obj: any): void {
|
||||
console.log("init: ", obj);
|
||||
this.value = obj;
|
||||
this.updateConst();
|
||||
}
|
||||
|
||||
public ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['items'] || changes['nullable']) {
|
||||
if (this.nullable)
|
||||
this.listedItems = [{key: "", value: "N/A"}, {key: null, value: "N/A"}].concat(this.items);
|
||||
else
|
||||
this.listedItems = [].concat(this.items);
|
||||
}
|
||||
this.updateConst();
|
||||
}
|
||||
|
||||
private updateConst() {
|
||||
if (this.readonly) {
|
||||
for (let i=0; i<this.listedItems.length; i++) {
|
||||
if (this.listedItems[i].key==this.value) {
|
||||
this.constVal = this.listedItems[i].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(this.readonly, this.listedItems, this.value, this.constVal);
|
||||
}
|
||||
|
||||
// validates the form, returns null when valid else the validation object
|
||||
public validate(c: FormControl): ValidationErrors {
|
||||
if (this.value===null) {
|
||||
return this.nullable ? null : {notNullable: {valid: false}};
|
||||
}
|
||||
for (let i=0; i<this.items.length; i++) {
|
||||
if (this.items[i].key==this.value)
|
||||
return null;
|
||||
}
|
||||
return {invalidValue: {valid: false}};
|
||||
}
|
||||
|
||||
// on button click
|
||||
protected onChange(value: any): boolean {
|
||||
this.value = value;
|
||||
|
||||
super.change();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
33
src/app/modules/dyn-form/inputs/hidden-input.component.ts
Normal file
33
src/app/modules/dyn-form/inputs/hidden-input.component.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import {Component, forwardRef, Input} from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl, ValidationErrors } from '@angular/forms';
|
||||
import {CustomInputComponent} from "./custom-input.component";
|
||||
|
||||
@Component({
|
||||
selector: 'hidden-input',
|
||||
template: ``,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => HiddenInputComponent),
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: NG_VALIDATORS,
|
||||
useExisting: forwardRef(() => HiddenInputComponent),
|
||||
multi: true,
|
||||
}]
|
||||
})
|
||||
export class HiddenInputComponent extends CustomInputComponent {
|
||||
@Input() readonly: boolean = false;
|
||||
@Input() nullable: boolean = false;
|
||||
|
||||
// set initial value
|
||||
public writeValue(obj: any): void {
|
||||
this.value = obj;
|
||||
}
|
||||
|
||||
// validates the form, returns null when valid else the validation object
|
||||
public validate(c: FormControl): ValidationErrors {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -34,8 +34,9 @@ export class KeysPipe implements PipeTransform {
|
||||
}]
|
||||
})
|
||||
export class TagInputComponent extends CustomInputComponent {
|
||||
@Input() items: Array<{key: string, value: string}> = [];
|
||||
@Input() readonly: boolean = false;
|
||||
@Input() nullable: boolean = false;
|
||||
@Input() items: Array<{key: string, value: string}> = [];
|
||||
|
||||
private lookup: {[_:string]: string} = {};
|
||||
|
||||
@@ -57,9 +58,10 @@ export class TagInputComponent extends CustomInputComponent {
|
||||
this.value[key] = (this.nullable ? null : false);
|
||||
}
|
||||
}
|
||||
console.log("writeValue", isUpdated, this.value);
|
||||
|
||||
if (isUpdated) {
|
||||
super.change();
|
||||
setTimeout(() => super.change(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +72,7 @@ export class TagInputComponent extends CustomInputComponent {
|
||||
|
||||
// on button click
|
||||
protected onChange(key: string, forward: boolean): boolean {
|
||||
if (this.readonly) return false;
|
||||
let value = this.value[key];
|
||||
if (!this.nullable)
|
||||
value = !value;
|
||||
|
||||
8
src/app/services/hello.service.ts
Normal file
8
src/app/services/hello.service.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class HelloService {
|
||||
sayHello(): void {
|
||||
console.log("Hello world from my Service!");
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"mapRoot":"/src/",
|
||||
"sourceRoot":"/src/",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [ "es2015", "dom" ],
|
||||
|
||||
Reference in New Issue
Block a user