Clone Group/Rule in Angular Query Builder UI

1 Sep 202610 minutes to read

Create exact duplicates of rules or entire groups with the cloning feature. When cloning is enabled, a new rule or group is created adjacent to the original, allowing users to reuse complex query structures. Cloning can be triggered either through the built-in clone buttons in the UI or programmatically through methods.

Enable clone buttons

The showButtons property controls the visibility of the built-in clone buttons alongside the other action buttons. Each key accepts a boolean value that toggles the corresponding button.

Key Purpose
cloneGroup Shows or hides the Clone Group button on each group header.
cloneRule Shows or hides the Clone Rule button on each rule.
ruleDelete Shows or hides the Delete Rule button on each rule.
groupInsert Shows or hides the Add Group button on each group header.
groupDelete Shows or hides the Delete Group button on each group header.

To expose the clone buttons in the UI, set cloneGroup and cloneRule to true:

public showButtons: Object = {
    ruleDelete: true,
    groupInsert: true,
    groupDelete: true,
    cloneGroup: true,
    cloneRule: true
};

Clone via methods

You can also clone groups and rules programmatically using the following methods:

cloneGroup parameters

Parameter Type Description
groupId string | number The id of the group to clone.
targetId string | number The id of the target group into which the cloned group is inserted.
index number The zero-based position within the target group where the cloned group is placed.

cloneRule parameters

Parameter Type Description
ruleId string | number The id of the rule to clone.
targetGroupId string | number The id of the target group into which the cloned rule is inserted.
index number The zero-based position within the target group where the cloned rule is placed.

The group and rule ids (querybuilder_group0, querybuilder_group0_rule0, etc.) are the element ids generated by the Query Builder for each group and rule. You can obtain them at runtime from the id attribute of the corresponding group or rule element in the DOM, or by inspecting the getRules result and mapping the rules to their rendered element ids.

When cloning is performed through the built-in UI buttons, the new group or rule is inserted adjacent to the original and the Query Builder fires the ruleChange or groupChange events accordingly. When cloning is performed through the cloneGroup or cloneRule methods, the same events are triggered after the new group or rule is added.

The following sample demonstrates programmatic cloning. The built-in clone buttons are hidden (cloneGroup: false, cloneRule: false) and two external buttons invoke the cloneGroup and cloneRule methods with the ids of the first group and the first rule.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { QueryBuilderModule } from '@syncfusion/ej2-angular-querybuilder'
import { enableRipple } from '@syncfusion/ej2-base'



import { Component, ViewChild, OnInit } from '@angular/core';
import { RuleModel, QueryBuilderComponent } from '@syncfusion/ej2-angular-querybuilder';
import { QueryLibrary } from '@syncfusion/ej2-querybuilder';
import { hardwareData } from './datasource';

QueryBuilderComponent.Inject(QueryLibrary);

@Component({
imports: [
        
        QueryBuilderModule,
    ],


standalone: true,
    selector: 'app-root',
    template: `<!-- To render Query Builder. -->
               <ejs-querybuilder id="querybuilder" #querybuilder class="row" width="70%" [dataSource]="data" [rule]="importRules" [showButtons]="showButtons">
                <e-columns>
                  <e-column field="TaskID" label="Task ID" type="number"></e-column>
                  <e-column field="Name" label="Name" type="string"></e-column>
                  <e-column field="Category" label="Category" type="string"></e-column>
                  <e-column field="SerialNo" label="SerialNo" type="string"></e-column>
                  <e-column field="InvoiceNo" label="InvoiceNo" type="string"></e-column>
                  <e-column field="Status" label="Status" type="string"></e-column>
                </e-columns>
              </ejs-querybuilder>
               <button class="e-btn e-primary e-qb-button" (click)="cloneGroup()" >Clone Group</button>
               <button class="e-btn e-primary e-qb-button" (click)="cloneRule()" >Clone Rule</button>`
})

export class AppComponent implements OnInit {
    public data?: Object[];
    public importRules?: RuleModel;
    public showButtons: Object = {ruleDelete: true, groupInsert: true, groupDelete: true, cloneGroup: false, cloneRule: false};
     @ViewChild('querybuilder')
    public qryBldrObj?: QueryBuilderComponent;
    ngOnInit(): void {
        this.data = hardwareData;
        this.importRules = {
            'condition': 'and',
            'rules': [{
                    'label': 'Task ID',
                    'field': 'TaskID',
                    'type': 'number',
                    'operator': 'equal',
                    'value': 1
                },
                {
                    'label': 'Name',
                    'field': 'Name',
                    'type': 'string',
                    'operator': 'equal',
                    'value': 'Sales Manager'
                },
                {
                    condition: "or", rules: [
                        { 'label': 'Name',
                        'field': 'Name',
                        'type': 'string',
                        'operator': 'equal',
                        'value': 'Engineer' }
                    ]
                }
            ]
            };
    }
    cloneGroup(): void {
        this.qryBldrObj!.cloneGroup("querybuilder_group0", "querybuilder_group1", 1);
    }
    cloneRule(): void {
        this.qryBldrObj!.cloneRule("querybuilder_group0_rule0", "querybuilder_group0", 1);
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

See also