Reputation: 725
I'm facing an issue with an existing application, below is my scenario I'm having the below JSON format
.html code
<div class="panel-group" id="accordion">
<div *ngFor="let property of Tree.properties">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a class="link" data-toggle="collapse" data-parent="#accordion" href="#dataCatg-{{property.name}}">
<div *ngIf="property.required">
<span class="glyphicon glyphicon-chevron-right"></span>{{property.name}}
</div>
<div *ngIf="!property.required">
<span class="glyphicon glyphicon-chevron-right"></span>{{property.name}}
</div>
</a>
</h4>
</div>
<div id="dataCatg-{{property.name}}" class="panel-collapse collapse">
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item" *ngFor="let prop of property.details">
<div *ngIf="prop.details.visible">
<div class="row">
<div class="col-md-4">
<div *ngIf="data.includes(prop.name)">
<label class="inline-label" for="{{prop.name}}">{{prop.name}}</label>
</div>
<div *ngIf="!data.includes(prop.name) ">
<label class="inline-label " for="{{prop.name}} ">{{prop.name}}</label>
</div>
</div>
<div class="col-md-8 ">
<div *ngIf="!Edit">
<span *ngIf="formVisible && metaDataTemplateMap[selectedFile]!==undefined ">
<input id="{{prop.name}}" type="{{prop.details.type}} " [(ngModel)]="Data[prop.name]" class="form-control ">
</span>
</div>
<div *ngIf="Edit">
<div *ngIf="prop.details.group ">
<span *ngIf="formView">
<!--need-->
<input id="{{prop.name}}" type="{{prop.details.type}}" [(ngModel)]="Edit[prop.name]" (ngModelChange)="Edit($event)" style=" border-radius:0;"
class="form-control">
</span>
</div>
<div *ngIf="!prop.details.group ">
<input id="{{prop.name}}" type="text " style=" border-radius:0" class="form-control " readonly>
</div>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
.ts Code
Data(res) {
this.Tree['Properties'] = [];
for (let property in res.properties) {
var prop = res.properties[property];
if (prop['properties'] !== undefined) {
let temp= {};
if (res['required'].indexOf(property) !== -1) {
temp['required'] = true;
}
else {
temp['required'] = false;
}
temp['name'] = property;
let template = {};
temp['details'] = [];
for (let nestedProps in prop.properties) {
let nestedProp = {};
nestedProp['name'] = nestedProps;
if (prop.properties[nestedProps]['type'] == 'string' || prop.properties[nestedProps]['type'] == 'date-time') {
prop.properties[nestedProps]['type'] = 'text';
template[nestedProps] = '';
}
if (prop.properties[nestedProps]['type'] == 'integer') {
prop.properties[nestedProps]['type'] = 'number';
template[nestedProps] = 0;
}
if (prop.properties[nestedProps]['type'] == 'array') {
prop.properties[nestedProps]['type'] = 'array';
template[nestedProps] = '';
}
if (prop.properties[nestedProps]['group'] == true) {
if (this.Edit[property] == undefined)
this.Edit[property] = {};
this.Edit[property][nestedProps] = '';
}
nestedProp['details'] = prop.properties[nestedProps];
temp['details'].push(nestedProp);
}
this.Data[property] = template;
this.Tree['Properties'].push(temp);
}
if (prop['properties'] == undefined) {
let temp = {};
if (res['required'].indexOf(property) !== -1) {
temp['required'] = true;
}
else {
temp['required'] = false;
}
temp['name'] = property;
if (prop['type'] == 'string' || prop['type'] == 'date-time') {
prop['type'] = 'text';
this.Data[property] = '';
}
if (prop['type'] == 'number') {
prop['type'] = 'integer';
this.Data[property] = 0;
}
if (prop['group'] == true) {
this.Edit[property] = '';
}
temp['details'] = prop;
this.Tree['Others'].push(temp);
}
}
}
here what I'm want is 1. if You see in the JSON I have
"required": [
"host",
"quantity",
"id"
],
while generating the fields it has to check the above mentioned fields are empty or not with out template or reactive form approach how can it be possible if the fields are empty then we have let user know that fields are empty how can I accomplish this ?
Upvotes: 8
Views: 1255
Reputation: 11243
Aim
Validation of dynamic generated form input without Reactive
or Template
Approach.
Solution
Directive
will be best use for such kind of requirement. Directive
helps to break the complicated job into small independent task. Lets see how it can be implemented.
Implementation provided below doesn't require any change in your existing code.
import { Injectable } from '@angular/core';
@Injectable()
export class ValidateService {
errors = {};
validate(key: string, value: object) {
this.errors[key] = value;
}
getErrors() {
let errorList = [];
Object.keys(this.errors).forEach(key => {
let value = this.errors[key];
if ((value == undefined || value == '') && this.required.find(item=>item == key)) {
errorList.push({ name: key, error: key + " Field is required" })
}
});
return errorList;
}
//All required fields can be maintained here
required = [
"host",
"quantity",
"id"
]
}
ValidateDirective
is responsible to collect the current value of input
control if any change happens. This information will be passed to the service class ValidationService
.
import { Directive, Host, Input, OnChanges, SimpleChanges, ViewContainerRef, AfterViewInit } from '@angular/core';
import { ValidateService } from './validate.service';
@Directive({
selector: '[validate]'
})
export class ValidateDirective implements OnChanges {
constructor(private service: ValidateService, private containerRef: ViewContainerRef) {
}
@Input("ngModel") model;
@Input("validate") element;
ngOnChanges(changes: SimpleChanges) {
setTimeout(() => {
this.service.validate(this.containerRef.element.nativeElement.id, changes.model.currentValue);
})
}
}
ValidateDirective
can be used with any input controls which has id
and ngModel
.
ex:
<input [validate] id="{{prop.name}}" type="{{prop.details.type}}" [(ngModel)]="Edit[prop.name]" (ngModelChange)="Edit($event)" style=" border-radius:0;" class="form-control">
ValidateService
will be Injected into component to get the list of errors.
constructor(private service:ValidateService) {}
public get errors(){
return this.service.getErrors();
}
Since all errors are available in Component, it can be displayed in the html.
ex :
<li *ngFor="let error of errors">
{{error.error}}
</li>
Note - There are many thing which can be enhanced further like
- Passing custom message to
Directive
.Required field list
can be passed to Directive as @Input
Working sample demo is here - https://stackblitz.com/edit/angular-xnbzqd
Upvotes: 5