Added Dropdown and Hidden Input

This commit is contained in:
Caesar2011
2017-05-30 07:37:33 +02:00
parent a5fdfa32d2
commit 5f66284d02
12 changed files with 392 additions and 302 deletions

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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 {
}

View File

@@ -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);
}
}

View File

@@ -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: [],

View File

@@ -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>
`
})

View 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;
}
}

View 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;
}
}

View File

@@ -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;

View File

@@ -0,0 +1,8 @@
import { Injectable } from '@angular/core';
@Injectable()
export class HelloService {
sayHello(): void {
console.log("Hello world from my Service!");
}
}

View File

@@ -4,6 +4,8 @@
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"mapRoot":"/src/",
"sourceRoot":"/src/",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2015", "dom" ],