Generate form automatically with config file - javascript

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.

Related

Adaptive Cards Input Values in Submit

Hi I'm using the Adaptive card SDK in a web page, using a Sample Card like this:
var card = {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "Present a form and submit it back to the originator"
},
{
"type": "Input.Text",
"id": "firstName",
"placeholder": "What is your first name?"
},
{
"type": "Input.Text",
"id": "lastName",
"placeholder": "What is your last name?"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Action.Submit"
}
]};
and rendering using the usual rubric. I'd like to get the inputs back with the submit so I tried this
// Set the adaptive card's event handlers. onExecuteAction is invoked
// whenever an action is clicked in the card
adaptiveCard.onExecuteAction = function (action) { console.log(action.toJSON()) }
which just gives me:
Object title: "Action.Submit" type: "Action.Submit" __proto__: Object
How do I get the values of the input fields on the submit action?
TIA for any comments, advice and answers
You can use the data property of the action object just like this:
adaptiveCard.onExecuteAction = function (action) {
alert(`Hello ${action.data.firstName} ${action.data.lastName}`);
}
Here's a full jsfiddle.
There are many other interesting properties on the action object, but I haven't found good documentation.
However, the source code of the adaptive card visualizer contains some usage examples.

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

Angular dynamic form with groups of elements getting from JSON

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

Is there a way to use a property in JSON in another value of a property?

Not sure if the question makes sense so better to provide a code example.
{
"data": {
"whatever": [{
"id": "abcd12312",
"title": null,
"value": null,
"options": [
{
"text": "My text {{value}} one",
"value": "email#address.com"
},
{
"text": "My text [value] one",
"value": "email#address.com"
}
]
}]
}
}
So I was thinking can you do anything with Mustache or is there another way without having to write JavaScript to insert the value inside the text?
What I am trying to do is to allow the user to change the text to what ever they want but have a pointer to the value which will be dynamic based on what email address the entered on a previous page.

Parse dynamic nested JSON into HTML table

My experience with parsing JSON is fairly minimal but the document im working with is pretty big. JSON Objects are nested within one another and the keys are fairly consistent with "title","description","properties","default", and "type". Property/Object names will vary and new values may be added overtime so I want this to be as flexible as possible.
Here is a sample of the JSON I am working with, The real document is much larger:
{
"title": "settings schema",
"description": "Settings schema ",
"type": "object",
"properties": {
"alerts": {
"description": "Settings for alerts ",
"type": "object",
"properties": {
"pageSize": {
"description": "The number of alerts .",
"type": "number",
"default": 15
},
"paramKeys": {
"description": "parameter keys",
"type": "string",
"default": "fromKey,toKey,inKey,outKey"
},
"alertsEnabled": {
"description": "Enable/disable alerts",
"type": "boolean",
"default": true
},
"actionablesEnabled": {
"description": "Enable/disable actionable alerts",
"type": "boolean",
"default": true
},
"HistoryEnabled": {
"description": "Enable/disable alert history",
"type": "boolean",
"default": true
},
"generalAlertsEnabled": {
"description": "Enable/disable general alerts",
"type": "boolean",
"default": true
},
"accountsEnabled": {
"description": "Enable/disable account alerts",
"type": "boolean",
"default": true
},
"alertPrefsEnabled": {
"description": "Enable/disable alert preferences",
"type": "boolean",
"default": true
},
"datePicker": {
"description": "Search date picker settings",
"type": "object",
"properties": {
"maxSearchDays": {
"description": "The maximum days to search before today's date. Used on search page",
"type": "integer",
"default": 365
},
"minDays": {
"description": "The number of days before a user is able to select a date. Should be less than the maxDays",
"type": "integer",
"default": 0
},
"maxDays": {
"description": "The total number of days that user is able to select a date until. Should be greater than minDays",
"type": "integer",
"default": 30
},
"blackOutDays": {
"description": "Days of the week indicated by 0 (Sunday) though 6 (Saturday) that will be blacked out",
"type": "array",
"default": []
},
"blackOutDates": {
"description": "Date Ranges or individual dates in the following format: ['20 Mar 2014 - 1 May 2014', '28 Apr 2014'] that are blacked out or unselectable on the calendar. Typically holidays. ",
"type": "array",
"default": []
},
"isAlertCalendar": {
"description": "Configures datepicker to work for alerts dnd ",
"type": "boolean",
"default": true
}
},
"required": [
"maxSearchDays",
"minDays",
"maxDays",
"blackOutDays",
"blackOutDates",
"isAlertCalendar"
]
}
},
"required": [
"pageSize",
"paramKeys"
]
}
}
Ive seen a lot of places online say to iterate over arrays but it seems like im dealing with more nested Objects than arrays. Value/Property names may change so I cant really hardcode any property names. I am trying to pull this data and parse it back into an HTML table ideally leaving empty cells where data doesn't apply. For example the first column would have the "alerts" title and every cell underneath it would be empty until all of its properties had been parsed into the next column with property description/type/sub properties/ and defaults in the following columns again leaving blank values when there is no data to include.
Here is a hardcoded example of what I am trying to achieve
Ive never had to work with such complex dynamic json data before so usually its as easy as chaining together keys to get to values but this i really throwing me through a loop and the output i am producing looks like 200 empty cells with the word "id" repeated 10 times in the middle of it.
Any advice helps!
You need to know how deep your structure is in order to render x amount
of sub property columns ( where x is the number of levels )
When parsing an object you need to know the level where that object is so that you may add columns to that row corresponding to that object.
use recursion. Since you know what type you're dealing with you only have to recurse down the properties with the type object.
I honestly tried solving your problem but I keep bumping to the problem that this table is going to look horrific after 3+ levels. I would perhaps rethink how you want the data to be displayed.
If this is some sort of exercise ( i.e. you have to use a table ) I would look into a js template rendering engine that would help you render the x columns. i.e. something like underscore would let you do:
<tr>
<% for(var i = 0; i < totalNumberOfLevels; i --) { %>
<td></td>
<% }; %>
<td><%- default %></td>
</tr>
Maybe this helps you out?
Convert JSON array to an HTML table in jQuery
(at the download page is also a module listed which supports sub grid creation)
http://www.trirand.com/blog/?page_id=6

Categories

Resources