added validation, error messages, help tooptips, async question loading and textarea input
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {Component} from '@angular/core';
|
||||
import {QuestionInterface} from './modules/dyn-form/types/question.interface';
|
||||
import {QuestionService} from './modules/dyn-form/services/question.service';
|
||||
import {ValueService} from './modules/dyn-form/services/value.service';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
@@ -8,16 +9,21 @@ import {QuestionService} from './modules/dyn-form/services/question.service';
|
||||
})
|
||||
|
||||
export class AppComponent {
|
||||
public formQuestions: QuestionInterface[] = [];
|
||||
public formQuestions: QuestionInterface[] = null;
|
||||
public formValue: Object = null;
|
||||
|
||||
constructor(private questionService: QuestionService) {
|
||||
constructor(private questionService: QuestionService, private valueService: ValueService) {
|
||||
this.questionService.getQuestions((res, err) => {
|
||||
this.formQuestions = res;
|
||||
if (!err)
|
||||
this.formQuestions = res;
|
||||
});
|
||||
this.valueService.getValues((res, err) => {
|
||||
if (!err)
|
||||
this.formValue = res;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
submit(value: any) {
|
||||
static submit(value: any) {
|
||||
console.log('send', value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||
import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core';
|
||||
import {QuestionInterface} from './types/question.interface';
|
||||
import {FormControl, FormGroup} from '@angular/forms';
|
||||
|
||||
@@ -6,33 +6,39 @@ import {FormControl, FormGroup} from '@angular/forms';
|
||||
selector: 'dyn-form',
|
||||
template: `
|
||||
<form (ngSubmit)="submit()" [formGroup]="form">
|
||||
<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>
|
||||
<dyn-question *ngFor="let question of questions" [hidden]="question.properties.methods && question.properties.methods.indexOf(type)==-1" [question]="question" [form]="form" [type]="type" (onChange)="valueChange.emit(this.form.value)"></dyn-question>
|
||||
<div class="form-row">
|
||||
<button type="submit">Save</button>
|
||||
<button [disabled]="form.invalid" type="submit">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
`
|
||||
})
|
||||
export class DynFormComponent implements OnInit {
|
||||
export class DynFormComponent implements OnChanges {
|
||||
@Input() questions: QuestionInterface[];
|
||||
@Input() value: any;
|
||||
@Input() value: {[_:string]: any};
|
||||
@Input() type: "'insert'|'update'|'delete'|'view'";
|
||||
@Output() valueChange: EventEmitter<any> = new EventEmitter<any>();
|
||||
@Output() onSubmit: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
private form: FormGroup;
|
||||
|
||||
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]);
|
||||
public ngOnChanges(changes: SimpleChanges) {
|
||||
console.log("changes form", changes);
|
||||
if (changes['questions']) {
|
||||
let controls = {};
|
||||
for(let i = 0; this.questions && i < this.questions.length; i++) {
|
||||
let key = this.questions[i].properties.key;
|
||||
controls[key] = new FormControl();
|
||||
}
|
||||
this.form = new FormGroup(controls);
|
||||
}
|
||||
if ((changes['questions'] || changes['value']) && this.form && this.value) {
|
||||
this.form.patchValue(this.value);
|
||||
}
|
||||
this.form = new FormGroup(controls);
|
||||
}
|
||||
|
||||
private submit() {
|
||||
console.log("isValid", this.form.valid);
|
||||
this.onSubmit.emit(this.form.value);
|
||||
if (this.form.valid)
|
||||
this.onSubmit.emit(this.form.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,13 @@ 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 {TagInputComponent} from './inputs/tag-input.component';
|
||||
import {HiddenInputComponent} from './inputs/hidden-input.component';
|
||||
import {DropdownInputComponent} from './inputs/dropdown-input.component';
|
||||
import {QuestionService} from './services/question.service';
|
||||
import {TextareaInputComponent} from './inputs/textarea-input.component';
|
||||
import {ValueService} from './services/value.service';
|
||||
import {KeysPipe} from './types/keys.pipe';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@@ -25,10 +28,12 @@ import {QuestionService} from './services/question.service';
|
||||
TagInputComponent,
|
||||
HiddenInputComponent,
|
||||
DropdownInputComponent,
|
||||
TextareaInputComponent,
|
||||
KeysPipe
|
||||
],
|
||||
providers: [
|
||||
QuestionService
|
||||
QuestionService,
|
||||
ValueService
|
||||
],
|
||||
})
|
||||
export class DynFormModule { }
|
||||
|
||||
@@ -1,27 +1,38 @@
|
||||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||
import {QuestionInterface} from './types/question.interface';
|
||||
import {FormGroup} from '@angular/forms';
|
||||
import {FormGroup, ValidationErrors} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
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"
|
||||
[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>
|
||||
<div [ngSwitch]="question.type" [formGroup]="form">
|
||||
<label [for]="question.properties.key">{{question.properties.label ? question.properties.label + (question.constraints.optional ? '' : ' *') : ''}}</label>
|
||||
<i [hidden]="question.description" class="help circle icon" (mouseover)="onHover(true)" (mouseout)="onHover(false)">Help</i>
|
||||
<a [hidden]="!hoverState" class="ui pointing red basic label">{{question.description}}</a><br>
|
||||
|
||||
<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>
|
||||
<textarea-input *ngSwitchCase="'textbox'"
|
||||
[formControlName]="question.properties.key" [id]="question.properties.key"
|
||||
[nullable]="question.constraints.optional" [readonly]="type=='view'"
|
||||
(ngModelChange)="change()"></textarea-input>
|
||||
|
||||
<ul [hidden]="!errorList.length">
|
||||
<li *ngFor="let error of errorList">{{error}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class DynQuestionComponent {
|
||||
@@ -29,8 +40,26 @@ export class DynQuestionComponent {
|
||||
@Input() type: "'insert'|'update'|'delete'|'view'";
|
||||
@Input() form: FormGroup;
|
||||
@Output() onChange: EventEmitter<any> = new EventEmitter<any>();
|
||||
public hoverState: any = false;
|
||||
private errorList: Array<string> = [];
|
||||
|
||||
onHover(state: boolean) {
|
||||
this.hoverState = state;
|
||||
}
|
||||
|
||||
change() {
|
||||
this.onChange.emit();
|
||||
setTimeout(() => {
|
||||
this.errorList = [];
|
||||
let control = this.form.controls[this.question.properties.key];
|
||||
if (control.untouched || control.valid)
|
||||
return null;
|
||||
let errors: ValidationErrors = control.errors;
|
||||
for (let key in errors) {
|
||||
if (errors.hasOwnProperty(key)) {
|
||||
this.errorList.push(errors[key].message);
|
||||
}
|
||||
}
|
||||
this.onChange.emit();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, forwardRef } from '@angular/core';
|
||||
import {Component, forwardRef} from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl, ValidationErrors } from '@angular/forms';
|
||||
import {CustomInputComponent} from "./custom-input.component";
|
||||
|
||||
@@ -6,9 +6,9 @@ import {CustomInputComponent} from "./custom-input.component";
|
||||
selector: 'counter-input',
|
||||
template:
|
||||
`
|
||||
<button (click)="onChange(-1)" (blur)="onBlur()">-</button>
|
||||
<button (click)="onChange(-1)">-</button>
|
||||
{{value}}
|
||||
<button (click)="onChange(1)" (blur)="onBlur()">+</button>
|
||||
<button (click)="onChange(1)">+</button>
|
||||
`,
|
||||
providers: [
|
||||
{
|
||||
@@ -23,6 +23,7 @@ import {CustomInputComponent} from "./custom-input.component";
|
||||
}]
|
||||
})
|
||||
export class CounterInputComponent extends CustomInputComponent {
|
||||
|
||||
// set initial value
|
||||
public writeValue(obj: any): void {
|
||||
if (obj) {
|
||||
@@ -33,9 +34,12 @@ export class CounterInputComponent extends CustomInputComponent {
|
||||
|
||||
// validates the form, returns null when valid else the validation object
|
||||
public validate(c: FormControl): ValidationErrors {
|
||||
if (!this.initComplete)
|
||||
return null;
|
||||
return (!this.parseError) ? null : {
|
||||
numberParseError: {
|
||||
valid: false,
|
||||
message: "Not a valid number!"
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -47,9 +51,4 @@ export class CounterInputComponent extends CustomInputComponent {
|
||||
|
||||
super.change();
|
||||
}
|
||||
|
||||
// on touched
|
||||
protected onBlur(): void {
|
||||
super.blur();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,20 @@
|
||||
import {ControlValueAccessor, FormControl, ValidationErrors, Validator} from '@angular/forms';
|
||||
import {AfterViewInit} from '@angular/core';
|
||||
|
||||
export abstract class CustomInputComponent implements ControlValueAccessor, Validator {
|
||||
export abstract class CustomInputComponent implements ControlValueAccessor, Validator, AfterViewInit {
|
||||
protected value: any;
|
||||
protected parseError: boolean;
|
||||
private propagateChange: (_: any) => void = () => {};
|
||||
private propagateTouch: () => void = () => {};
|
||||
protected initComplete: boolean = false;
|
||||
private isTouched: boolean = false;
|
||||
|
||||
public ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
this.initComplete = true;
|
||||
this.change();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// set initial value
|
||||
public abstract writeValue(obj: any): void;
|
||||
@@ -23,12 +33,17 @@ export abstract class CustomInputComponent implements ControlValueAccessor, Vali
|
||||
public abstract validate(c: FormControl): ValidationErrors;
|
||||
|
||||
// on change
|
||||
protected change(): void {
|
||||
protected change(noTouch?: boolean): void {
|
||||
if (!noTouch)
|
||||
this.touch();
|
||||
this.propagateChange(this.value);
|
||||
}
|
||||
|
||||
// on touch
|
||||
protected blur(): void {
|
||||
this.propagateTouch();
|
||||
// on change
|
||||
protected touch(): void {
|
||||
if (!this.isTouched) {
|
||||
this.propagateTouch();
|
||||
this.isTouched = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,6 @@
|
||||
import {Component, forwardRef, Inject, Input, OnChanges, Pipe, PipeTransform, SimpleChanges} from '@angular/core';
|
||||
import {Component, forwardRef, Input, OnChanges, SimpleChanges} from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl, ValidationErrors } from '@angular/forms';
|
||||
import {CustomInputComponent} from "./custom-input.component";
|
||||
import {HttpCachedService} from '../../../services/http-cached.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',
|
||||
@@ -42,10 +30,6 @@ export class DropdownInputComponent extends CustomInputComponent implements OnCh
|
||||
private listedItems: Array<{key: string, value: string}> = [];
|
||||
private constVal: string;
|
||||
|
||||
constructor(private httpCachedService: HttpCachedService) {
|
||||
super();
|
||||
}
|
||||
|
||||
// set initial value
|
||||
public writeValue(obj: any): void {
|
||||
console.log("init: ", obj);
|
||||
@@ -54,15 +38,18 @@ export class DropdownInputComponent extends CustomInputComponent implements OnCh
|
||||
}
|
||||
|
||||
public ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['items'] || changes['nullable']) {
|
||||
console.log("onchnage: ", this.value);
|
||||
if (changes['items'] || changes['nullable'] || changes['readonly']) {
|
||||
if (this.nullable)
|
||||
this.listedItems = [{key: "", value: "N/A"}, {key: null, value: "N/A"}].concat(this.items);
|
||||
else
|
||||
this.listedItems = [].concat(this.items);
|
||||
this.listedItems = this.items;
|
||||
this.updateConst();
|
||||
}
|
||||
this.updateConst();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private updateConst() {
|
||||
if (this.readonly) {
|
||||
for (let i=0; i<this.listedItems.length; i++) {
|
||||
@@ -72,19 +59,29 @@ export class DropdownInputComponent extends CustomInputComponent implements OnCh
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
console.log("validate", this.value, this.initComplete, this.nullable, this.items);
|
||||
if (!this.initComplete)
|
||||
return null;
|
||||
if (this.value===null) {
|
||||
return this.nullable ? null : {notNullable: {valid: false}};
|
||||
return this.nullable ? null : {notNullable: {
|
||||
valid: false,
|
||||
message: "This field is required!"
|
||||
}};
|
||||
}
|
||||
for (let i=0; i<this.items.length; i++) {
|
||||
console.log(this.items[i].key, this.value);
|
||||
if (this.items[i].key==this.value)
|
||||
return null;
|
||||
}
|
||||
return {invalidValue: {valid: false}};
|
||||
console.log("ret invalid");
|
||||
return {invalidValue: {
|
||||
valid: false,
|
||||
message: "This value is invalid. Please select another value!"
|
||||
}};
|
||||
}
|
||||
|
||||
// on button click
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
import {Component, forwardRef, Input, Pipe, PipeTransform} from '@angular/core';
|
||||
import {Component, forwardRef, Input} from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl, ValidationErrors } from '@angular/forms';
|
||||
import {CustomInputComponent} from "./custom-input.component";
|
||||
|
||||
@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: 'tag-input',
|
||||
template:
|
||||
@@ -61,7 +50,7 @@ export class TagInputComponent extends CustomInputComponent {
|
||||
console.log("writeValue", isUpdated, this.value);
|
||||
|
||||
if (isUpdated) {
|
||||
setTimeout(() => super.change(), 0);
|
||||
setTimeout(() => super.change(true), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
54
src/app/modules/dyn-form/inputs/textarea-input.component.ts
Normal file
54
src/app/modules/dyn-form/inputs/textarea-input.component.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
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: 'textarea-input',
|
||||
template:
|
||||
`
|
||||
<textarea *ngIf="!readonly" (keyup)="onChange($event)">{{value}}</textarea>
|
||||
<span *ngIf="readonly">{{value}}</span>
|
||||
`,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => TextareaInputComponent),
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: NG_VALIDATORS,
|
||||
useExisting: forwardRef(() => TextareaInputComponent),
|
||||
multi: true,
|
||||
}]
|
||||
})
|
||||
export class TextareaInputComponent extends CustomInputComponent {
|
||||
@Input() readonly: boolean = false;
|
||||
@Input() nullable: boolean = false;
|
||||
|
||||
|
||||
// set initial value
|
||||
public writeValue(obj: any): void {
|
||||
if (obj) {
|
||||
this.value = obj + '';
|
||||
}
|
||||
}
|
||||
|
||||
// validates the form, returns null when valid else the validation object
|
||||
public validate(c: FormControl): ValidationErrors {
|
||||
if (!this.initComplete)
|
||||
return null;
|
||||
console.log("no error?", !!(this.nullable || this.value));
|
||||
return this.nullable || (this.value) ? null : {notNullable: {
|
||||
valid: false,
|
||||
message: "This field is required!"
|
||||
}};
|
||||
}
|
||||
|
||||
// on button click
|
||||
protected onChange($event: KeyboardEvent): void {
|
||||
this.value = $event.target['value'];
|
||||
console.log("NEW:", this.value, $event.target, $event.target['value']);
|
||||
|
||||
super.change();
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,14 @@ export class QuestionService {
|
||||
|
||||
}
|
||||
public getQuestions(cb: (res: QuestionInterface[], err: any) => void) {
|
||||
setTimeout(() => cb([
|
||||
setTimeout(() => cb(QuestionService.orderItems([
|
||||
{
|
||||
type: 'flag',
|
||||
description: 'This is a help tooltip',
|
||||
properties: {
|
||||
key: 'flags',
|
||||
label: 'Form Type Flags',
|
||||
order: 1,
|
||||
order: 3,
|
||||
|
||||
// dropdown && flags
|
||||
options: [{key: 'alpha', value: 'A'}, {key: 'beta', value: 'B'}, {key: 'gamma', value: 'C'}, {key: 'delta', value: 'D'}]
|
||||
@@ -41,11 +41,34 @@ export class QuestionService {
|
||||
description: 'ID',
|
||||
properties: {
|
||||
key: 'ID',
|
||||
order: 3
|
||||
order: 1
|
||||
}, constraints: {
|
||||
optional: false
|
||||
}
|
||||
}, {
|
||||
type: 'textbox',
|
||||
description: 'This is a very long box. Fill it!',
|
||||
properties: {
|
||||
key: 'textarea',
|
||||
label: 'Textareaaaa',
|
||||
order: 4
|
||||
}, constraints: {
|
||||
optional: false
|
||||
}
|
||||
}
|
||||
], null), 4000);
|
||||
]), null), 10);
|
||||
}
|
||||
|
||||
private static orderItems(list: Array <any>) {
|
||||
function compare(a: any, b: any) {
|
||||
if (a.properties.order < b.properties.order)
|
||||
return -1;
|
||||
if (a.properties.order > b.properties.order)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list.sort(compare);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
12
src/app/modules/dyn-form/services/value.service.ts
Normal file
12
src/app/modules/dyn-form/services/value.service.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {HttpCachedService} from '../../../services/http-cached.service';
|
||||
|
||||
@Injectable()
|
||||
export class ValueService {
|
||||
constructor(private httpCachedService: HttpCachedService) {
|
||||
|
||||
}
|
||||
public getValues(cb: (res: Object, err: any) => void) {
|
||||
setTimeout(() => cb({flags:{alpha:true}, ID: 50, textarea: "a long text", cooldrop: "u"}, null), 15);
|
||||
}
|
||||
}
|
||||
12
src/app/modules/dyn-form/types/keys.pipe.ts
Normal file
12
src/app/modules/dyn-form/types/keys.pipe.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { ResponseInterface } from './response.interface';
|
||||
export class HttpCachedService extends HttpService {
|
||||
private _stored: any = {}; // {data: ResponseInterface, e: Response}
|
||||
|
||||
get refreshTime() {
|
||||
static get refreshTime() {
|
||||
return 3*1000;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export class HttpCachedService extends HttpService {
|
||||
}
|
||||
|
||||
getJSON(uri: string, query: {[propName: string]: any}, dataFunc: (data: ResponseInterface, e: Response | any) => void) {
|
||||
var hash: string = this._hashRequest("GET", uri, query);
|
||||
const hash: string = this._hashRequest('GET', uri, query);
|
||||
if (this._stored.hasOwnProperty(hash)) {
|
||||
if (this._stored[hash] instanceof Array) {
|
||||
// pending request, add to event emitter
|
||||
@@ -31,30 +31,29 @@ export class HttpCachedService extends HttpService {
|
||||
super.getJSON(uri, query, (data, e) => {
|
||||
// request recieved, emit to caller and event subscriber
|
||||
dataFunc(data, e);
|
||||
for (var i = this._stored[hash].length - 1; i >= 0; i--) {
|
||||
for (let i = this._stored[hash].length - 1; i >= 0; i--) {
|
||||
this._stored[hash][i](data, e);
|
||||
}
|
||||
this._stored[hash] = {
|
||||
data: data,
|
||||
e: e
|
||||
};
|
||||
var that = this;
|
||||
setTimeout(function() {
|
||||
delete that._stored[hash];
|
||||
}, this.refreshTime);
|
||||
setTimeout(() => {
|
||||
delete this._stored[hash];
|
||||
}, HttpCachedService.refreshTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _hashRequest(method: string, uri: string, query?: Object): string {
|
||||
function objectToString(obj: Object = {}) {
|
||||
var keys: string[] = [];
|
||||
var result: string = '{';
|
||||
for (var key in obj)
|
||||
const keys: string[] = [];
|
||||
let result: string = '{';
|
||||
for (let key in obj)
|
||||
if (obj.hasOwnProperty(key))
|
||||
keys.push(key);
|
||||
keys.sort();
|
||||
for (var i = keys.length - 1; i >= 0; i--) {
|
||||
for (let i = keys.length - 1; i >= 0; i--) {
|
||||
result += keys[i]+':"'+obj[keys[i]]+'",'
|
||||
}
|
||||
result += '}';
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"mapRoot":"/src/",
|
||||
"sourceRoot":"/src/",
|
||||
"mapRoot":"/",
|
||||
"sourceRoot":"/src/app",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [ "es2015", "dom" ],
|
||||
|
||||
Reference in New Issue
Block a user