nth-level Dynamic Query Builder Using Angular 7
Dynamic Query builder is a more innovative way to handle multiple conditions. We can say a set of rules using a simple but astonishing UI where the user can easily create dynamic rulesets (Combination of various conditions). Usually, it is used in backend portals where users can set dynamic rules and get an output in structured JSON format. Then you can parse the outcome in your desired form like SQL or No-SQL.
Let’s see the dynamic builder’s usage and how you can place fields, operators, and results dynamically. Follow the steps as shown below:
Step 1: Install Query Builder Package from the command prompt
npm install angular2-query-builder
Step 2: Import Query Builder module for use package in component
File Name: app.module.ts
Step 3: Create a query builder (Set rule and rule set with custom fields)
Here based on the field selection, the builder dynamically sets a query operator.
e.g. 1: if fields need to check multiple values then operator can be “IN or NOT IN”
e.g. 2: if fields need to check numeric value then operator can be “<, >, <=, >=, <>, =”
File Name: app.component.html
<query-builder [data]="uiExpression" [config]="config">
<ng-container
*queryButtonGroup="let ruleset; let addRule=addRule; let addRuleSet=addRuleSet; let removeRuleSet=removeRuleSet">
<button mat-button (click)="addRule()">+ Rule</button>
<button mat-button (click)="addRuleSet()">+ Ruleset</button>
<button mat-button (click)="removeRuleSet()">- Ruleset</button>
</ng-container>
<ng-container *queryRemoveButton="let rule; let removeRule=removeRule">
<button mat-icon-button color="accent" (click)="removeRule(rule)">
<mat-icon>remove</mat-icon>
</button>
</ng-container>
<ng-container *querySwitchGroup="let ruleset">
<mat-radio-group *ngIf="ruleset" [(ngModel)]="ruleset.condition">
<mat-radio-button value="and">And</mat-radio-button>
<mat-radio-button value="or">Or</mat-radio-button>
</mat-radio-group>
</ng-container>
<ng-container *queryInput="let rule; type: 'number'">
<mat-form-field>
<input matInput type="number" [(ngModel)]="rule.value">
</mat-form-field>
</ng-container>
<ng-container *queryField="let rule; let fields=fields; let onChange=onChange; let changeField=changeField">
<mat-form-field class="full-width-field">
<mat-select [(ngModel)]="rule.field" (ngModelChange)="onChange($event, rule)">
<mat-option *ngFor="let field of fields" [value]="field.value"> <b>{{field.sequence}}. </b> {{field.name}}
</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
<ng-container *queryOperator="let rule; let operators=operators; let onChange=onChange">
<mat-form-field class="text-center">
<mat-select [(ngModel)]="rule.operator" (ngModelChange)="onChange(rule)">
<mat-option *ngFor="let value of operators" [value]="value.value">{{value.name}}
</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
</query-builder>
File Name: app.component.ts
import { QueryBuilderConfig } from 'angular2-query-builder';
export class AppComponent {}
Step 4: Operator sets to display it in query builder
checboxRadioOperators = [
{ 'name': 'in', 'value': 'in' },
{ 'name': 'not in', 'value': 'not in' },
];
numberOperators = [
{ 'name': '=', 'value': '=' },
{ 'name': '!=', 'value': '!=' },
{ 'name': '>', 'value': '>' },
{ 'name': '>=', 'value': '>=' },
{ 'name': '<', 'value': '<' },
{ 'name': '<=', 'value': '<=' },
];
Step 5: Call the API and fetch dynamic fields to set it in query builder
getQuestionList(searchObj) {
searchObj.filter.status = 1;
searchObj.sortOrder = 'asc';
this.questionmappingService.getMapQuestionsList(this.analyzertagsId).subscribe(response => {
this.data = response;
this.id = this.data .items[0]._id;
this.analyzerTagsObj = this.data.items[0].analyzerTagsObj[0];
this.questionArray = this.data.items[0];
this.selectedQuestion = this.data.items[0].questionsObj[ this.sequence - 1];
if (!this.selectedQuestion) {
this.router.navigate(['master/analyzertags-list']);
} else {
this.data.items[0].questionsObj.forEach((element) => {
if (element.sequence < this.sequence) {
if (element.answer_input === 'radio' || element.answer_input === 'checkbox') {
this.operators = this.checboxRadioOperators;
}
if (element.answer_input === 'number') {
this.operators = this.numberOperators;
}
this.fieldsS[element._id] = {
name: element.question_text,
sequence: element.sequence,
type: element.answer_input.toLowerCase(),
operators: this.operators,
options: element.answer_options[0].answer
};
this.config.fields = this.fieldsS;
}
});
if (this.data.items[0].questionsObj.length > 0) {
if (!this.data.items[0].questionsObj[this.sequence - 1].conditionObj) {
if (this.data.items[0].answer_input === 'radio' || this.data.items[0].answer_input === 'checkbox') {
this.operators = this.checboxRadioOperators;
}
if (this.data.items[0].answer_input === 'number') {
this.operators = this.numberOperators;
}
/** Set default questions when query builder loads */
this.uiExpression = {
condition: 'and',
rules: [
{
field: this.data.items[0].questionsObj[0]._id,
type: this.data.items[0].questionsObj[0].answer_input.toLowerCase(),
operator: this.operators[0].value,
options: this.data.items[0].questionsObj[0].answer_options[0].answer[0],
}
]
};
} else {
this.uiExpression = this.data.items[0].questionsObj[this.sequence - 1].conditionObj;
}
}
}
});
}
The code snippets above have been implemented to create dynamic questions and their answers or any other dependency. Using this tool builds queries based on the input of questions.
Ex: If the answer to the age question is… > 50, then, If the answer to X question is IN (1, 2, 7), then. You can follow the steps above to integrate dynamic fields and operators in the query builder based on your requirements. To know more about Dynamic Query Builder, get in touch with a DEV IT expert here.