Default selected value upon init, with remote data

Dear, I am trying to show a default value in the dropdown tree. I am using OData4 adaptor to fetch the items.


What I am trying to accomplish is: the default value is filled in the dropdown field when the page is loaded, and when the user opens the dropdown, the tree is expanded from root until the value.

I have both the path to the value, and the parentId's avail


13 Replies

SR Subalakshmi Ramachandran Syncfusion Team November 6, 2024 02:16 PM UTC

Hi Neils,

Greetings from Syncfusion support.

Based on your shared details, we understood that you need to show the default value in the DropdownTree and need to expand the tree node. We kindly suggest you that use selected field property for the default selection in Dropdown Tree and use ensureVisible method of treeview in beforeOpen event of DropdownTree component.

Refer to the below code:
[app.component.html]

<ejs-dropdowntree id='dropdownTree' #ddtObj [fields]='fields' (beforeOpen)="beforeOpen()"></ejs-dropdowntree>


[app.component.ts]

public beforeOpen() {
    (this.ddtObj as any).treeObj.ensureVisible('15');
  }



Regards,
Suba R.



NV Niels Van Goethem November 6, 2024 02:47 PM UTC

Hi, I have tried your solution, but it does not seem to work. 
I have set the value in the "selected" field property, but I suspect it does not show as selected, because the tree value is not fetched yet.

<ejs-dropdowntree
  #oneHrDropdownTree
  [fields]="oneHrDataFields"
  [treeSettings]="oneHrTreeSettings"
  [placeholder]="label"
  floatLabelType="Never"
  [itemTemplate]="itemTmpl"
  (beforeOpen)="beforeOpen()"
  (valueChange)="nodeSelected($event)"
>
</ejs-dropdowntree>

<ng-template #itemTmpl id="itemTmpl" let-data>
  <div [class.is-linked]="isLinked(data.Id)">{{ data.DescriptionEN }}</div>
</ng-template>
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { ODataService, TreeStructureService } from '@shared/services';
import {
  DropDownTreeComponent,
  FieldsModel,
  TreeSettingsModel,
} from '@syncfusion/ej2-angular-dropdowns';
import { Subject } from 'rxjs';
import { takeUntil, tap } from 'rxjs/operators';

@Component({
  selector: 'am-one-hr-dropdown-tree',
  templateUrl: './one-hr-dropdown-tree.component.html',
  styleUrls: ['./one-hr-dropdown-tree.component.scss'],
})
export class OneHrDropdownTreeComponent implements OnInit {
  @Input() oneHrLinkFc: UntypedFormControl;
  @Input() path: number[];
  @Input() label: string;
  @ViewChild('oneHrDropdownTree') dropdownTree: DropDownTreeComponent;

  public oneHrTreeSettings: TreeSettingsModel;
  public oneHrDataFields: FieldsModel;

  private linkedItems: number[] = [];

  private destroy$ = new Subject<void>();

  constructor(
    private readonly oDataService: ODataService,
    private readonly treeStructureService: TreeStructureService
  ) {}

  ngOnInit(): void {
    this.treeStructureService
      .getFlatTree$()
      .pipe(
        tap((items) => {
          this.linkedItems = items.filter((x) => !!x.oneHrLink).map((x) => x.oneHrLink.id);
        }),
        takeUntil(this.destroy$)
      )
      .subscribe();
    this.oneHrTreeSettings = { loadOnDemand: true };
    this.oneHrDataFields = this.oDataService.getOneHrDataFields(this.oneHrLinkFc.value?.toString());
  }

  public beforeOpen() {
    if (this.oneHrLinkFc.value) {
      (this.dropdownTree as any).treeObj.ensureVisible(this.oneHrLinkFc.value.toString());
    }
  }

  public nodeSelected(e: string[]) {
    if (e && e.length > 0) {
      this.oneHrLinkFc.setValue(Number(e[0]));
    }
  }

  public isLinked(id: number): boolean {
    return this.linkedItems.includes(id);
  }
}



SR Subalakshmi Ramachandran Syncfusion Team November 8, 2024 03:13 PM UTC

Hi Neils,

Greetings from Syncfusion support.

Based on your shared details, we understood that you need to show the default value in the DropdownTree and need to expand the tree node. We kindly suggest you that use value property for the default selection in DropdownTree component.

Refer to the below code:
[app.component.html]

<ejs-dropdowntree #ddtObj id='dropdownTree' [value]='value' [fields]='fields'></ejs-dropdowntree>


[app.component.ts]

  public valuestring[] = ['1'];


Sample: Syncfusion-content - Ej2 Angular Docs - StackBlitz

Documenatation: Angular Dropdown Tree API component - Syncfusion

Regards,
Suba R.



NV Niels Van Goethem November 12, 2024 08:46 AM UTC

Hii, I have tried your approach, however it is still not working as expected.

The root entry is selected, not the entry that matches the value. I suspect this is because that entry is not fetched yet.
When I open de dropdown, the message "The request failed" is shown, but when I inspect the network, the call succeeded



NV Niels Van Goethem November 18, 2024 06:43 AM UTC

Can I still expect an answer, or should I look into a different approach?




NV Niels Van Goethem November 18, 2024 09:09 AM UTC

I have tried this approach. Fetching only the node that equals the value of the fromcontrol, and passing that to the fields. And also setting the id as the value; I expected the value to show up in the input field, but the input field remains empty

import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { TranslationService } from '@arcelormittal-platform/core';
import { ODataService, TreeStructureService } from '@shared/services';
import {
  DropDownTreeComponent,
  FieldsModel,
  TreeSettingsModel,
} from '@syncfusion/ej2-angular-dropdowns';
import { Query } from '@syncfusion/ej2-data';
import { Subject } from 'rxjs';
import { takeUntil, tap } from 'rxjs/operators';

@Component({
  selector: 'am-one-hr-dropdown-tree',
  templateUrl: './one-hr-dropdown-tree.component.html',
  styleUrls: ['./one-hr-dropdown-tree.component.scss'],
})
export class OneHrDropdownTreeComponent implements OnInit {
  @Input() oneHrLinkFc: UntypedFormControl;
  @Input() path: number[];
  @Input() label: string;
  @ViewChild('oneHrDropdownTree') dropdownTree: DropDownTreeComponent;

  public oneHrTreeSettings: TreeSettingsModel;
  public oneHrDataFields: FieldsModel;

  public value: string[];

  public currentLanguage: string;

  private linkedItems: number[] = [];

  private destroy$ = new Subject<void>();

  constructor(
    private readonly oDataService: ODataService,
    private readonly treeStructureService: TreeStructureService,
    private readonly translationService: TranslationService
  ) {}

  public get descriptionProperty() {
    return `Description${this.currentLanguage.toUpperCase()}`;
  }

  ngOnInit(): void {
    this.currentLanguage = this.translationService.getCurrentLanguage();

    if (this.oneHrLinkFc.value) {
      this.oDataService.getOneHrNodeById(this.oneHrLinkFc.value).then((response: any) => {
        this.setDropdownTree(response.result[0]);
        this.value = [this.oneHrLinkFc.value];
      });
    }

    this.treeStructureService
      .getFlatTree$()
      .pipe(
        tap((items) => {
          this.linkedItems = items.filter((x) => !!x.oneHrLink).map((x) => x.oneHrLink.id);
        }),
        takeUntil(this.destroy$)
      )
      .subscribe();

    this.oneHrTreeSettings = { loadOnDemand: true };
  }

  public nodeSelected(e: string[]) {
    if (e && e.length > 0) {
      this.oneHrLinkFc.setValue(Number(e[0]));
    }
  }

  public isLinked(id: number): boolean {
    return this.linkedItems.includes(id);
  }

  private setDropdownTree(node: any) {
    const datamanager = this.oDataService.getOneHrDataManager();

    this.oneHrDataFields = {
      dataSource: [node],
      value: 'Id',
      text: this.descriptionProperty,
      hasChildren: 'Id',
      child: {
        dataSource: datamanager,
        query: new Query().from('OneHrOrganisationNodes'),
        value: 'Id',
        parentValue: 'ParentId',
        text: this.descriptionProperty,
        hasChildren: 'Id',
      },
    };
  }
}



SR Subalakshmi Ramachandran Syncfusion Team November 18, 2024 04:14 PM UTC

Hi Neils,


Based on your shared details, we have confirmed that the pre-select child value is not rendered on input of DropdownTree component and consider this as a bug from our end. We will share the feedback and the timeline for the fix tomorrow.


Regards,
Suba R.



SR Subalakshmi Ramachandran Syncfusion Team November 19, 2024 07:00 AM UTC

Hi Neils,


We were able to replicate the “Issue with pre-selecting child nodes in the Dropdown Tree component for Remote data” and considered this as a bug on our end. The fix for this issue will be included in the weekly patch release scheduled on Dec 3, 2024.


You can track the status of the fix through the following link.


FeedbackFacing issue with pre-selecting child nodes in the Dropdown Tree component for Remote data in Angular | Feedback Portal


Disclaimer: Inclusion of this solution in the weekly release may change due to other factors including but not limited to QA checks and works reprioritization.


Regards,

Suba R



SR Subalakshmi Ramachandran Syncfusion Team December 4, 2024 07:54 AM UTC

Hi Neils,

Thanks for your patience. 


The issue with “pre-selecting child nodes in the Dropdown Tree component for Remote data” has been resolved in this release. To access this fix, we suggest you update the package to 27.2.5 and we include the sample in the latest version for your reference.

Sample: ddt-remotedata-child - StackBlitz

Feedback: Facing issue with pre-selecting child nodes in the Dropdown Tree component for Remote data in Angular | Feedback Portal

Release Notes: Essential Studio for Angular Weekly Release Release Notes

Root cause: The issue occurs because the setValidValue method doesn't correctly update the text property for remote data. In the setTreeValue method, the else block tries to set the text property using a firstName property from the parent node. However, the child node doesn’t have a firstName property, so text gets assigned null. This causes the input field to appear empty or undefined.


We thank you for your support and appreciate your patience in waiting for this release. Please get in touch with us if you would require any further assistance.


Regards,
Suba R.




NV Niels Van Goethem December 6, 2024 11:48 AM UTC

Hi! The issue is still not solved on my side. I have recreated the issue here:  ddt-remotedata-child (forked) - StackBlitz

What I did, was add a item template, with a function in it that checks wether or not to use a css class



SR Subalakshmi Ramachandran Syncfusion Team December 9, 2024 06:36 AM UTC

Hi Neils,


 Upon reviewing your code, we noticed an issue with the itemTemplate. Specifically:

  1. The data.Id argument passed to the function was incorrect.
  2. The type of the ID being passed to the function did not align with its expected type, causing the issue.

To resolve this:

  • Use OrderID for the child or EmployeeID for the parent, depending on your requirement.
  • Ensure the ID type passed to the function matches the expected type (number in this case).

Here’s the updated code for your reference:
[app.component.html]

<ng-template #itemTmpl id="itemTmpl" let-data>
  <div [class.is-linked]="isLinked(data.OrderID)">
    {{ data.FirstName ?? data.ShipName }}
  </div>
</ng-template>

 

[app.component.ts]

public isLinked(id: number): boolean {
    return id != null && this.linkedItems.includes(id.toString());
  }

Sample: ddt-remotedata-child-style - StackBlitz

Regards,
Suba R.




NV Niels Van Goethem December 9, 2024 07:12 AM UTC

Hello, the data in the example is not the data structure we use. We are using self referential data. Can you prodvide an example please, because I cannot get it to work



SR Subalakshmi Ramachandran Syncfusion Team December 13, 2024 07:58 PM UTC

Hi Neils,

Based on your previous code snippet regarding the Dropdown Tree's data source, we reviewed your implementation and we suspect that the issue with the field mapping, particularly for parent and child relationships.

If you are working with self-referential data, there is no need to map the child property. Instead, you can use the parentValue field to establish parent-child relationships, as shown in the example below:


id: 1, name: 'Discover Music', hasChild: true, expanded: true },

{ id: 2, pid: 1, name: 'Hot Singles', selected: true },

{ id: 3, pid: 1, name: 'Rising Artists' },


Field mapping for the Dropdown Tree:

public listfields: Object = {

    dataSource: this.localData,

    value: 'id',

    parentValue: 'pid',

    text: 'name',

    hasChildren: 'hasChild',

    selected: 'selected',

  };


In this structure, the id represents each node, and the pid specifies the parent node's id. Nodes are linked by matching the id of the parent with the pid of the child. The parentValue property handles this mapping which eliminating the need for a child property.

Refer to the below sample: Vh6btsxk (forked) - StackBlitz
Documentation: Data binding in Angular Drop down tree component | Syncfusion
If we misunderstood the issue, please replicate the problem in the provided sample or share a screenshot or video to help us understand it better.

Regards,
Suba R


Loader.
Up arrow icon