ui-components icon indicating copy to clipboard operation
ui-components copied to clipboard

fix(#2114): dropdown dynamic items not updating

Open syedszeeshan opened this issue 1 year ago • 1 comments

Before (the change)

Unexpected behavior when parents have one or more child items with same value(s). Use the code and instructions in the story to reproduce.

After (the change)

When dropdown items are same across different parent, they get displayed as expected.

Issue (use case)

Parent Dropdown

-One -Two -Three

Child Dropdown

-Alpha, Beta (when One selected) -Alpha, Beta, Gamma (when Two selected) -Alpha, Gamma (when Three selected)

Alpha is present in all 3 parent Beta and Gamma in 2 of the parent

Make sure that you've checked the boxes below before you submit the PR

  • [x] I have read and followed the setup steps
  • [ ] I have created necessary unit tests
  • [x] I have tested the functionality in both React and Angular.

Steps needed to test

Angular Code

<h1>Dropdown</h1>
<hr />
<div [formGroup]="changeForm">
  <goa-form-item label="Parent" requirement="optional">
    <goa-dropdown goaValue formControlName="parentDropdown" placeholder="Select a value" name="parent">
      <goa-dropdown-item *ngFor="let parent of parents" [value]="parent" [label]="parent" />
    </goa-dropdown>
  </goa-form-item>
  <goa-form-item label="Children" requirement="optional">
    <goa-dropdown formControlName="childDropdown" placeholder="Select a value" goaValue name="children">
      <ng-container *ngIf="children.length > 0">
      <goa-dropdown-item
        *ngFor="let child of children; index as i;"
        [value]="child"
        [parentValue]="selectedParent + '-' + child"
        [label]="child"
        [mount]="i === 0 ? 'reset' : 'append'"
      />
    </ng-container>
    </goa-dropdown>
  </goa-form-item>
</div>
import { Component, OnInit} from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms";

@Component({
  selector: "abgov-dropdown",
  templateUrl: "./dropdown.component.html",
})
export class DropdownComponent implements OnInit {
  changeForm: FormGroup;
  parents = ["One", "Two", "Three"];
  children: string[] = [];
  selectedParent = "";

  private childrenOne = ["Alpha", "Beta"];
  private childrenTwo = ["Alpha", "Beta", "Gamma"];
  private childrenThree = ["Alpha", "Gamma"];

  constructor(private fb: FormBuilder) {
    this.changeForm = this.fb.group({
      parentDropdown: [""],
      childDropdown: [""],
    });
  }

  ngOnInit() {
    this.changeForm.get("parentDropdown")?.valueChanges.subscribe((value) => {
      this.selectedParent = value;
      this.loadChildren(value);
      this.changeForm.get("childDropdown")?.reset("");
    });
  }

  loadChildren(parentValue: string) {
    switch (parentValue) {
      case "One":
        this.children = this.childrenOne;
        break;
      case "Two":
        this.children = this.childrenTwo;
        break;
      case "Three":
        this.children = this.childrenThree;
        break;
      default:
        this.children = [];
    }
  }
}

React Code

import { GoADropdown, GoADropdownItem, GoAFormItem } from "@abgov/react-components";
import { useState } from "react";

export default function Dropdown() {
  const parents = ["One", "Two", "Three"];
  const childrenOne = ["Alpha", "Beta"];
  const childrenTwo = ["Alpha", "Beta", "Gamma"];
  const childrenThree = ["Alpha", "Gamma"];
  const [children, setChildren] = useState<string[]>([]);
  const [parentValue, setParentValue] = useState<string>("");

  const loadSchemas = (name: string, values: string[] | string) => {
    if (typeof values === "string") {
      setParentValue(values);

      if (values === "One") setChildren(childrenOne);
      else if (values === "Two") setChildren(childrenTwo);
      else setChildren(childrenThree);
    }
  };

  const log = () => {
    console.log("Children Changed");
  };

  return (
    <main>
      <GoAFormItem label="Parent" requirement="optional">
        <GoADropdown name="parent" placeholder="Select a value" onChange={loadSchemas}>
          {parents.map((parent) => (
            <GoADropdownItem key={parent} value={parent} label={parent} />
          ))}
        </GoADropdown>
      </GoAFormItem>
      <GoAFormItem label="Children" requirement="optional">
        <GoADropdown name="children" placeholder="Select a value" onChange={log}>
          {" "}
          {children.map((child, index) => (
            <GoADropdownItem
              key={child}
              value={child}
              label={child}
              mountType={index === 0 ? "reset" : "append"}
              parentValue={`${parentValue}-${child}`} // Unique key combining parent and child
            />
          ))}
        </GoADropdown>
      </GoAFormItem>
    </main>
  );
}

syedszeeshan avatar Sep 25 '24 22:09 syedszeeshan

This issue is verified and fixed, cypress test is also created

lizhuomeng71 avatar Oct 02 '24 20:10 lizhuomeng71

https://github.com/user-attachments/assets/ddb82499-9126-4fe9-a4c1-1405f4677f6c

Video explanation of the issue

syedszeeshan avatar Oct 07 '24 19:10 syedszeeshan

No fix is needed for this. Instead some documentation updates need to be added on how to deal with this edge case.

chrisolsen avatar Oct 09 '24 15:10 chrisolsen