Angular dynamic form with groups of elements getting from JSON - javascript

I am making angular application and building of angular dynamic form.
Here i am trying to split of form in two parts such as Person Name and Personal details..
For Person Name its working for grouping but for Personal details its not working.
The Html:
<div *ngIf="form">
<div *ngFor="let question of questions" class="form-row" [formGroup]="form">
<ng-container *ngIf="!question.children">
<app-question [question]="question" [form]="form"></app-question>
</ng-container>
<ng-container *ngIf="question.controlType === 'group' && question.children && question.children.length > 0">
<app-dynamic-group [questions]="question.children" [form]="form.controls[question.key]" [key]="question.key" [formControlName]="question.key"></app-dynamic-group>
</ng-container>
</div>
</div>
JSON:
jsonData: any = [
{
"elementType": "group",
"key": "person_name",
"children": [
{
"elementType": "textbox",
"class": "col-12 col-md-4 col-sm-12",
"key": "first_name",
"label": "First Name",
"type": "text",
"value": "",
"required": true,
"minlength": 3,
"maxlength": 20,
"order": 1
},
{
"elementType": "textbox",
"class": "col-12 col-md-4 col-sm-12",
"key": "last_name",
"label": "Last Name",
"type": "text",
"value": "",
"required": true,
"order": 2
}
],
},
{
"elementType": "group",
"key": "personal_details",
"children": [
{
"elementType": "textbox",
"class": "col-12 col-md-4 col-sm-12",
"key": "email",
"label": "Email",
"type": "text",
"value": "",
"required": true,
"minlength": 3,
"maxlength": 20,
"order": 1
},
{
"elementType": "textbox",
"class": "col-12 col-md-4 col-sm-12",
"key": "mobile",
"label": "Mobile",
"type": "text",
"value": "",
"required": true,
"order": 2
}
],
},
];
The working Stckblitz: https://stackblitz.com/edit/angular-x4a5b6-5uj52y
As of working everything works fine.. Already a group was made for Person name and its working fine but for Personal details i am unable to find the input boxes..
A single form needs to get split up with titles above each part thats the requirement of this form.
Here the {{question.key}} displays the name on each input boxes but i need to display only Person Name at top.. Because it is the parent title and the remaining such as First Name, Last Name are input box labels.. How to show the parent title alone in before of each part (Person Name (Has First and Last Name) , Personal Details (Has Email and Mobile))...
I would like to have order split up exactly like the below with title for each respectively.
Person Name
-> First Name
-> Last Name
Personal Details
-> Email
-> Mobile Number
If i am wrong with the above approach then kindly help me to split this https://stackblitz.com/edit/angular-x4a5b6-geesde dynamic form like the below given approach..
My form needs to look like this https://stackblitz.com/edit/angular-zc34qr but it needs to be in pure angular dynamic form and JSON loading..
Kindly help me to create a group Personal Details like the Person Name which was already created and working..
Stuck for a long duration in this kindly help me please...

I don't understand why you creates additional formGroup here:
this.form = new FormGroup({main: innerForm});
Just use formGroup you're getting from your service:
dynamic-form.component.ts
this.form = this.qcs.toFormGroup(this.questions);
dynamic-form.component.html
<app-dynamic-group [questions]="questions" [form]="form"></app-dynamic-group>
Now, you do not need to implement ControlValueAccessor on your DynamicGroupComponent. You're passing FormGroup to it and it should be enough to generate form dynamically.
dynamic-group.component.ts
#Component({
selector: 'app-dynamic-group',
templateUrl: './dynamic-group.component.html'
})
export class DynamicGroupComponent {
#Input() form: FormGroup;
#Input() questions: QuestionBase<any>[] = [];
}
dynamic-group.component.html
<div *ngFor="let question of questions" class="form-row">
<app-question *ngIf="!question.children" [question]="question" [form]="form"></app-question>
<app-dynamic-group
*ngIf="question.controlType === 'group' && question.children && question.children.length"
[form]="form.get(question.key)"
[questions]="question.children">
</app-dynamic-group>
</div>
Forked Stackblitz

Related

How to use v-for 2 times to get specific values in check-box action form?

I am new to Vue js. I am trying to do an action form for the rest of API. I don't know how to get the data of name and location only. I was trying to use slice in Array, but it does not work.
My action form:
<div class="form-group">
<label class="required"> Social Media </label>
<b-form-checkbox v-for="event in events" :key="event._id" :value="event" v-model="selected">
{{event.name}}, {{event.location}}
</b-form-checkbox>
<span class="mt-3">Selected: <strong>{{ selected }}</strong></span>
</div>
My Vue instance
export default {
data() {
return {
events: [{
"_id": "d4d81da6-b453-4a31-999f-a2ea04848ee9",
"name": "A",
"location": "US",
"__v": 0
},
{
"_id": "91205d34-4480-4e4e-bdf7-fe66e46922b0",
"name": "B",
"location": "Korea",
"__v": 0
},
{
"_id": "0b168c44-4f38-4f86-8ee6-e077333aca95",
"name": "C",
"location": "Japan",
"__v": 0
}],
selected: ''
};
}
}
The Output when checking the first option of the checkbox:
Selected: ["_id": "d4d81da6-b453-4a31-999f-a2ea04848ee9", "name": "A", "location": "US", "__v": 0]
Expected output when checking the first option of the checkbox:
Selected: [ "name": "A", "location": "US" ]
You can create the necessary structure within the :value="" assignment.
<b-form-checkbox v-for="event in events" :key="event._id" :value="{ name: event.name, location: event.location }" v-model="selected">
{{event.name}}, {{event.location}}
</b-form-checkbox>
Firstly make Selected:false boolean ... then make a button and on click it'll get to a function which will accepts a parameter, iterate your array and select an object which is matching with the parameter
private selectFun(item){this.events.filter(val=>{val._id===item._id})//and then whatever}

AngularJS: Dynamically apply has-error to input fields

I have html that is dynamically generated from JSON and I would like to implement some validation logic.
To clarify, here is an example:
<div ng-switch on="field.type" ng-hide="{{ field.hide }}">
<div ng-switch-when="input" class= "col-md-6" ng-class="{'has-error': reqField(field.name, entity[field.name]) }">
<input
ng-model="entity[field.name]" id="{{field.name}}" class="form-control"
type="text" ng-style="setStyle(field.style)" ng-change="{{field.change}}" />
</div>
</div>
{
"title": "Json Title",
"id": "j_id",
"groupfields": [
{
"name": "jsonname",
"title": "JSON Title",
"type": "jsonselect",
"namevalue": "jsonvalue",
"combo": "jsondropdown",
"change" : "jsonChanged()"
},
{
"name": "jsonEmail",
"title": "JSON Email Address",
"type": "display"
},
{
"name": "jsonPhone",
"title": "JSON Phone Number",
"type": "display"
}
]
}, {
"title": "Json Title",
"id": "j_id",
"groupfields": [
{
"name": "jsonname",
"title": "JSON Title",
"type": "jsonselect",
"namevalue": "jsonvalue",
"combo": "jsondropdown",
"change" : "jsonChanged()"
},
{
"name": "jsonEmail",
"title": "JSON Email Address",
"type": "display"
},
{
"name": "jsonPhone",
"title": "JSON Phone Number",
"type": "display"
}
]
},
if (entityName) {
return false;
} else {
return true;
}
So for clarification, ex: 'field.type' in the ng-switch on is the "type" in the JSON - and we can determine which html div to display the content based on different JSON keys/values.
This implies that one html div could potentially be used to generate hundreds of input fields so this needs to be dynamic.
I would like to add validation for when a required field is empty. At the moment, I've tried adding the ng-class="{has-error': } which points to my function reqField. However, because this function is getting fired for EVERY field with "type": jsonselect, this function is checking whether or not the field is empty - which is really inefficient in terms of speed and usability (super laggy).
The javascript you see above is more or less the logic that the function reqField() does in order to check whether or not the field is empty (very inefficient since we're checking hundreds).
What I would like to use is something along the lines of ng-required={{field.required}} and make a new key/value in the JSON to determine whether or not I want this field to be a required field (sort like this):
{
"title": "Json Title",
"id": "j_id",
"groupfields": [
{
"name": "jsonname",
"title": "JSON Title",
"type": "jsonselect",
"namevalue": "jsonvalue",
"combo": "jsondropdown",
"change" : "jsonChanged()"
},
{
"name": "jsonEmail",
"title": "JSON Email Address",
"type": "display",
"required": true
},
{
"name": "jsonPhone",
"title": "JSON Phone Number",
"type": "display",
"required": true
}
]
},
~ and somehow pass that information to the ng-class="{has-error': } so that we can highlight - or do whatever we want once we know the field has been filled in/or is empty.
Form validation is built in to AngularJS. The ng-required directive will add error state to the form object, so that you can set up your ng-class like so:
<div ng-switch-when="input" class= "col-md-6" ng-class="{'has-error': myForm[field.name].$error.required }">
Your form and input must have name attributes for this to work:
<form name="myForm">
...
<input name="{{field.name}}" ng-required="field.required">

How to get selected item id,name or another json data?

I am new on JSON and I'm still trying to learn that's why I have couple of question/issue.
edit: I achieved to redirect selected item..
I have simple basic autocomplete plugin flexdatalist autocomplete and I want to get selected item properties.
Before you check the codes you can see my project online
footnote: I couldn't achievement add on codepen or stackoverflow snippet because on this platform json data wasn't loaded.
my json file
[
{
"id": "1",
"name": "Name 1",
"icon" : "https://cdn3.iconfinder.com/data/icons/finalflags/16/Germany-Flag.png",
"address":"http://www.google.com",
"category": "Premium",
"area": "United States",
"updated": null
},
{
"id": "2",
"name": "Name 2",
"icon":"https://cdn3.iconfinder.com/data/icons/finalflags/16/China-Flag.png",
"address":"http://www.youtube.com",
"category": "Free",
"area": "Spain",
"updated": null
}
]
as you see I have address and icon properties and I want to return this value I mean when I selected item from input than it must give me selected address and icon.
my js
$('.flexdatalist').flexdatalist({
cache:false,
searchContain: false,
textProperty: '{name},{continent}',
valueProperty: 'address',
minLength: 1,
focusFirstResult: true,
selectionRequired: true,
groupBy: 'continent',
visibleProperties: ["name", "continent", "capital_timezone"],
searchIn: ["address","name", "continent"],
url: 'hotels.json',
relatives: '#relative'
}).on("select:flexdatalist",function(){
window.location.href=this.value;
});
and my html
<input type='text' placeholder='Otel adını veya Bölgeyi yazmaya başla' class='flexdatalist'> <span></span>
and last question is how can I add icon/image left/right of item ? icons are in my json data
First of all
You have to change the fields to match what you want to get
And if you want to change json string to images you have to use js
Please check out is this javascript works for you.
$('.flexdatalist').flexdatalist({
cache:false,
searchContain: false,
textProperty: '{address},{icon}',
valueProperty: 'iso2',
minLength: 1,
focusFirstResult: true,
selectionRequired: true,
groupBy: 'address',
visibleProperties: ["address", "icon"],
searchIn: ["address", "icon"],
url: 'hotels.json',
relatives: '#relative'
}).on("show:flexdatalist.results",function(ev,result){
$.each(result,function(key,value){
result[key]['icon_highlight'] = '<img src="'+value.icon+'">';
})
});

Generate form automatically with config file

I am building a website to help operator of my team to generate a data source config.
Since there are many options need to be handled. I design an common solution to render the page: parse a config file(maybe, xml or json format) to html with some rules. Maybe something like below:
{
"data_type": {
"title": "Data type",
"description": "Select what type do you want.",
"fields": [{
"title": "promotion",
"description": "data from promotion center"
"type": "redio",
"default": true,
"value": "p",
"name": "dtype"
}, {
"title": "brands",
"description": "data from brands center"
"type": "redio",
"default": false,
"value": "b",
"name": "dtype"
}]
}
}
then it can be parsed as:
<div class="form-control-group">
<h3>Data type</h3>
<p>Select what type do you want.</p>
<div class="form-control-filed">
<input type="redio" name="dtype" value="p" show="dtype" checked />
<p>data from promotion center</p>
</div>
<div class="form-control-filed">
<input type="redio" name="dtype" value="b" />
<p>data from brands center</p>
</div>
</div>
This step is easily to implement. But since there are some cases like. When I click redio A, I wanna hide the checkbox B. After I unchecked Checkbox C, I wanna show up the input D. I have no idea about how to design the config file to describe the logic about different fields.
So, the key point is, I wanna parse the html by a json snippet. Then maybe there are some symbols to mark the behavior of each form field, I can use my common js to bind events to handle the show/hide, focus/blur or something else logic. Like the attribute show, I can use my common js function to detect it and bind click event to that radio button, and show up the element with name="dtype" after this radio is clicked.
I am not sure if it is a good solution and how to design an reasonable json structure.
Hope any one can provide some suggestions. Thanks in advance.
I've given up for this case. For my requirement, I use a json file to config the information of the form field with a behavior definition to describe show/hide functionality.
{
"xxx": {
"title": "Price mode",
"description": "group_description",
"fields": [{
"title": "",
"type": "select",
"name": "price_mode",
"value": [{
"text": "Store with product",
"value": 1,
"default": true,
"behaviors": {
"show": "name1|name2|name3",
"hide": ""
}
}, {
"text": "Product",
"value": 2,
"default": false,
"behaviors": {
"show": "",
"hide": "name1|name2|name3"
}
}],
"require": true,
"rule": ""
}]
}
}
Codes of server side will parse this config and render as html snippet with special attribute storing behavior definition, then use javascript functions handle these attributes and care about the behavior after doing something like click the radio button or change the value of select list.

How can I add separate width to each name and value that are getting iterated by ng-repeat

How can I add separate width to each name and value that are getting iterated by:
ng-repeat in angularJS
For e.g: This is my data:
[
{
"name": "First Name",
"value": "Harry"
},
{
"name": "Last Name",
"value": "Potter"
},
{
"name": "Gender",
"value": "Male"
},
{
"name": "DOB",
"value": "21/5/1988"
},
{
"name": "SSN",
"value": "298456147"
}]
HTML:
<div>
<div ng-repeat=\ "data in data\">
<div style=\ "float:left\">{{data.name}}</div>
<div style=\ "float:left\">{{data.value}}</div>
</div>
</div>
So, for each name and value I need separate width.
where can I add my width properties?
Add the "track by $index" clause as described in the docs for ng-repeat.
ng-repeat="opt in data track by $index"
Then you can use {{opt.name}} and {{opt.value}} and put them in different html elements with separate styles.
You can create an array of your possible widths like
$scope.widthArray = ['100px','300px','200px']
Then set width like below in ng-repeat on element
ng-style="{width: widthArray[$index]}"
You can arrange your widths as per your requirement in array.

Categories

Resources