Hello,
I am using a DropdownTree in a template for a QueryBuilder control where there could be a need to add items to the data source while going through the filtering event. What is the best way to update the datasource and use the query after the additional items are added?
The original way I attempted this was to do the following, but e.updateData call at the bottom does not exist:
filtering: (e: any) => {
// e.text = filter value
let existingData: any[] = dropDownTree.fields.dataSource as any[];
....
// Add some items to the existingData collection
....
dropDownTree.fields.dataSource = existingData;
let query = new Query();
query = query.where("text", "startswith", e.text, true);
e.updateData(existingData, query);
}
Is there a way to update the datasource and display the filtered data properly?
Thank you,
KS
Hi KS,
Greetings from Syncfusion support.
Based on the shared details, we understand that your requirement is to add some additional data to the existing data source in the Angular Dropdown Tree component filtering event and perform filtering operations at your end. To achieve this scenario, inside the filtering event, we have added some items to the existing data source based on the 'addNewItems' boolean value. After that, we performed a custom filtering operation by preventing the default operation using the 'preventDefaultAction' argument.
We then filtered the nodes with the matched search string, retrieved the corresponding parent node for the filtered child node, and all child nodes for the filtered parent node. Finally, we updated the Dropdown Tree data source with the filtered nodes.
Refer to the below code snippets.
[app.component.html]
|
… <ejs-dropdowntree id="filter" #dropdown [fields]="fields" [filterBarPlaceholder]="filterPlaceholder" [popupHeight]="height" [allowFiltering]="true" [placeholder]="watermark" (filtering)="filtering($event)" ></ejs-dropdowntree> … |
[app.component.ts]
|
import { Query,Predicate,DataManager} from '@syncfusion/ej2-data'; …
export class AppComponent { … public addNewItems:boolean =true; filtering(args) { if(this.addNewItems){ this.filterData.push({ id: 30, name: 'New Book',hasChild: true }); this.filterData.push({ id: 31, pid:30, name: 'Game of Thrones' }); this.filterData.push({ id: 32, pid:30, name: 'Spider-Man' }); this.addNewItems=false; } let _text = args.text; args.preventDefaultAction = true; let predicats = [], _array = [], _filter = []; if (_text == '') { args.fields.dataSource = this.filterData; } else { let predicate = new Predicate('name', 'startswith', _text, true); let filteredList = new DataManager(this.filterData).executeLocal( new Query().where(predicate) ); for (let j = 0; j < filteredList.length; j++) { _filter.push(filteredList[j]['id']); let filters = this.getFilterItems(filteredList[j], this.filterData); for (let i = 0; i < filters.length; i++) { if (_array.indexOf(filters[i]) == -1 && filters[i] != null) { _array.push(filters[i]); if (filteredList[j]['pid'] == undefined) { predicats.push(new Predicate('pid', 'equal', filters[i], false)); } predicats.push(new Predicate('id', 'equal', filters[i], false)); } } } if (predicats.length == 0) { args.fields.dataSource = []; } else { let query = new Query().where(Predicate.or(predicats)); let newList = new DataManager(this.filterData).executeLocal(query); args.fields.dataSource = newList; } } }
//Find the Parent Nodes for corresponding childs and all childs for searched parent. public getFilterItems(fList, list) { let nodes = []; nodes.push(fList['id']); let query2 = new Query().where('id', 'equal', fList['pid'], false); let fList1 = new DataManager(list).executeLocal(query2); if (fList1.length != 0) { let pNode = this.getFilterItems(fList1[0], list); for (let i = 0; i < pNode.length; i++) { if (nodes.indexOf(pNode[i]) == -1 && pNode[i] != null) nodes.push(pNode[i]); } return nodes; } else { let predicate = new Predicate('pid', 'equal', fList.id, false); let filteredList = new DataManager(this.filterData).executeLocal( new Query().where(predicate) ); for (let i = 0; i < filteredList.length; i++) { nodes.push(filteredList[i]); } } return nodes; } }
|
For your reference, we have attached the sample.
Sample: https://stackblitz.com/edit/angular-wzrevk-fswegk?file=src%2Fapp.component.html
Check out the attached sample and let us know if you need any further assistance.
Regards,
Prasanth Madhaiyan.
Hello,
Does it have to be a whole custom predicate/query setup in the filtering method? All I want is to add a few additional items to the existing data source and let the dropdown tree filter using those new items. I don't need to do the whole filtering part myself.
Is that not possible in this method, to add the items to the full datasource and then allow the default filtering to take place?
Thank you,
KS
Hi KS,
Based on the shared details, we would like to inform you that your mentioned requirement is to add some additional data to the existing data source in the Angular Dropdown Tree component filtering event and perform filtering operations. However, to achieve this exact requirement, we have provided a solution in our previous update. Your mentioned requirement involves sample-level customization, and our previous solution will be the proper way to fulfill the mentioned requirement without any issues.
Therefore, we recommend you check our solution sample, and based on your needs, you can customize it at your end. Please let us know if you need any further assistance.
Regards,
Prasanth Madhaiyan.
Hello,
Does this work within a subscribe? We have to do an API call within the filtering event to get the additional items and setting the datasource within the subscribe does not seem to update the dropdown contents properly.
Thank you,
KS
Hi KS,
Based on the shared details, we prepared the sample by making an API call within the filtering event to obtain additional items using the subscribe method, as mentioned in the Angular Dropdown Tree component. However, upon checking, we found that the subscribe method doesn't wait for the response from the backend. As a result, it adds the additional data after all the code is executed in the filtering event. This causes the first-time filtering not to function properly. To overcome this scenario, we recommend adding the additional data in the beforeOpen event. This ensures the proper functioning of the filtering without any issues.
[app.component.html]
|
<div class="control-section"> <div class="content" style="width: 280px;margin: 0 auto; padding-top:15px"> <ejs-dropdowntree id="filter" #dropdown [fields]="fields" [filterBarPlaceholder]="filterPlaceholder" [popupHeight]="height" [allowFiltering]="true" [placeholder]="watermark" (filtering)="filtering($event)" (beforeOpen)="beforeOpen($event)" ></ejs-dropdowntree> </div> </div>
|
[app.component.ts]
|
import { HttpClient } from '@angular/common/http'; … export class AppComponent {
@ViewChild ("dropdown") dropDownTree: DropDownTreeComponent; … public addNewItems:boolean =true; // Declare httpClient as a property private httpClient: HttpClient;
constructor(httpClient: HttpClient) { // Assign the injected httpClient to the class property this.httpClient = httpClient; } beforeOpen(args){ if(this.addNewItems){ // Make API call to fetch additional items this.httpClient.get('http://localhost:52799/Home/Get').subscribe((data: any[]) => { // Add new items to the filterData array data.forEach(item => { this.filterData.push(item); }); this.addNewItems = false; }); } } … }
|
For your reference, we have attached the sample and service.
Sample: https://stackblitz.com/edit/angular-wzrevk-bthxxf?file=src%2Fapp.component.html
Service: https://www.syncfusion.com/downloads/support/directtrac/general/ze/WebApplication_1691367757.zip
Check out the attached sample and let us know if you need any further assistance.
Regards,
Prasanth Madhaiyan.
Hello,
This does not quite cover the use case I am working with.
We need to do an API call based on the string that the user uses in the Search bar during the filtering event. We wouldn't know what other items to get if we do it in beforeOpen. Unless this event occurs when filtering as well?
We would only do the additional API call when the data is being filtered, so that is when this needs to occur. Assigning to the args.fields.dataSource within a subscribe in the filtering event does not seem to work.
Thank you,
KS
Hi KS,
To meet your specific requirement of making an API call within the filtering event to obtain additional items using the subscribe method, and then adding that data to the existing data while performing filtering for the newly added items in the Dropdown Tree component, please refer to the attached sample. You can also review the changes outlined below in the Dropdown Tree component filtering event.
[app.component.html]
|
… <div class="control-section"> <div class="content" style="width: 280px;margin: 0 auto; padding-top:15px"> <ejs-dropdowntree id="filter" #dropdown [fields]="fields" [filterBarPlaceholder]="filterPlaceholder" [popupHeight]="height" [allowFiltering]="true" [placeholder]="watermark" (filtering)="filtering($event)" ></ejs-dropdowntree> </div> </div> |
[app.component.ts]
|
… export class AppComponent { @ViewChild('dropdown') dropDownTree: DropDownTreeComponent; … public addNewItems: boolean = true; // Declare httpClient as a property private httpClient: HttpClient;
constructor(httpClient: HttpClient) { // Assign the injected httpClient to the class property this.httpClient = httpClient; } public subscribeFlag: boolean;
filtering(args) { if (this.addNewItems) { // Make API call to fetch additional items this.httpClient.get('http://localhost:52799/Home/Get').subscribe((data: any[]) => { data.forEach(item=> { this.filterData.push(item); }); this.subscribeFlag=true; this.customFiltering(args, args.text); this.addNewItems = false; });
} else { args.preventDefaultAction = true; this.customFiltering(args, args.text); } } public customFiltering(args, _text: string) { … if (predicats.length == 0) { args.fields.dataSource = []; } else { let query = new Query().where(Predicate.or(predicats)); let newList = new DataManager(this.filterData).executeLocal(query); if(this.subscribeFlag){ (this.dropDownTree as any).treeObj.fields.dataSource = newList; this.subscribeFlag=false; } else{ args.fields.dataSource = newList; } } } } //Find the Parent Nodes for corresponding childs and all childs for searched parent. public getFilterItems(fList, list) { … } }
|
For your reference, we have attached the sample and service.
Sample: https://stackblitz.com/edit/angular-wzrevk-unoxfs?file=src%2Fapp.component.html
Service: https://www.syncfusion.com/downloads/support/directtrac/general/ze/WebApplication_1691367757.zip
Regards,
Prasanth Madhaiyan.