Home > Enterprise >  Dependent DropDown Angular
Dependent DropDown Angular

Time:09-30

i`m creating dynamic dropdown box i have 2 dropdown each of my dropdown have a different data once i selected it it will channge the other data depending on what you select in the first dropdown how to achieve that?

i tried this code but it gaves me a undentified

.TS 

this is what iwanted to put in my dropdown box once i click the SERVICEABLE it will populate all the maintenance,upgrage,repairable and once i click the UNSERVICEABLE it will change it to another data and list all unserviceable

[
  {
    "id": 1,
    "assetID": 9,
    "tranType": "MAINTENANCE",
    "assetConditionType": {
      "id": 9,
      "assetConditionType": "SERVICEABLE"
    }
  },
  {
    "id": 2,
    "assetID": 9,
    "tranType": "UPGRADE",
    "assetConditionType": {
      "id": 9,
      "assetConditionType": "SERVICEABLE"
    }
  },
  {
    "id": 3,
    "assetID": 9,
    "tranType": "REPAIRABLE",
    "assetConditionType": {
      "id": 9,
      "assetConditionType": "SERVICEABLE"
    }
  },
  {
    "id": 4,
    "assetID": 10,
    "tranType": "DISPOSAL",
    "assetConditionType": {
      "id": 10,
      "assetConditionType": "UNSERVICEABLE"
    }
  },
  {
    "id": 5,
    "assetID": 10,
    "tranType": "WRITTEN-OFF",
    "assetConditionType": {
      "id": 10,
      "assetConditionType": "UNSERVICEABLE"
    }
  },
  {
    "id": 6,
    "assetID": 10,
    "tranType": "RETIRED",
    "assetConditionType": {
      "id": 10,
      "assetConditionType": "UNSERVICEABLE"
    }
  }
]


assetDS: AssetCondtionDTO[];
  assetObj: any;


'selectedType(trigger: MatSelectChange) {
  this.assetObj = trigger.value;

  const selectedItem = this.assetDS.find((x) => x.tranType.assetID == trigger.value);
  if (selectedItem) this.serviceLogArray.get('tranType').patchValue(selectedItem.id);
  console.log(this.assetObj)
}
assetCondition(){
  this.serviceSVC.getAssetCondition(5,10).subscribe((res: AssetCondtionDTO) => {
    this.assetObj = res;
  })
}'



HTML

 <td>
  <mat-select formControlName="assetCondition" style="width:200px;padding:10px"
           (selectionChange)="selectedType($event)">
      <mat-option ngFor="let items of assetObj" [value]="items.id">
          {{items.id}}
      </mat-option>
  </mat-select>
</td>
 <td>
<mat-select formControlName="tranType" style="width:200px;padding:10px">
     <mat-option ngFor="let items of assetObj" [value]="items.tranType.assetID">
       {{items.tranType.tranType}}</mat-option></mat-select> </td> ```

CodePudding user response:

Code portion of your question is unclear and we can't understand written logic but from your description, I provide you an example to filter a fake list base on another select form control:

Template:

<form [formGroup]="formGroup">
  <div>
    <mat-select formControlName="assetCondition" style="width:200px;padding:10px"
             (selectionChange)="selectedType($event)">
        <mat-option *ngFor="let items of assetConditionTypes" [value]="items.id">
            {{items.assetConditionType}}
        </mat-option>
    </mat-select>
  </div>
  <div>
    <mat-select formControlName="tranType" style="width:200px;padding:10px">
         <mat-option *ngFor="let items of filteredAssets" [value]="items.assetID">
           {{items.tranType}}
          </mat-option>
         <mat-option *ngIf="filteredAssets.length===0">
           Pleas select type first!
          </mat-option>
    </mat-select>
  </div>
</form>

TS:

formGroup: FormGroup = new FormGroup({
    assetCondition: new FormControl(''),
    tranType: new FormControl('')
  });

  selectedType(trigger: MatSelectChange) {
    this.filteredAssets = this.myAssets.filter((asset) => asset.assetConditionType.id ==  trigger.value);
    console.log(this.filteredAssets);
  }

  assetConditionTypes = [
    {
    "id": 9,
    "assetConditionType": "SERVICEABLE"
    },
    {
      "id": 10,
      "assetConditionType": "UNSERVICEABLE"
    }
  ];

  filteredAssets: any[] = [];

  myAssets = [
    {
      "id": 1,
      "assetID": 9,
      "tranType": "MAINTENANCE",
      "assetConditionType": {
        "id": 9,
        "assetConditionType": "SERVICEABLE"
      }
    },
    {
      "id": 2,
      "assetID": 9,
      "tranType": "UPGRADE",
      "assetConditionType": {
        "id": 9,
        "assetConditionType": "SERVICEABLE"
      }
    },
    {
      "id": 3,
      "assetID": 9,
      "tranType": "REPAIRABLE",
      "assetConditionType": {
        "id": 9,
        "assetConditionType": "SERVICEABLE"
      }
    },
    {
      "id": 4,
      "assetID": 10,
      "tranType": "DISPOSAL",
      "assetConditionType": {
        "id": 10,
        "assetConditionType": "UNSERVICEABLE"
      }
    },
    {
      "id": 5,
      "assetID": 10,
      "tranType": "WRITTEN-OFF",
      "assetConditionType": {
        "id": 10,
        "assetConditionType": "UNSERVICEABLE"
      }
    },
    {
      "id": 6,
      "assetID": 10,
      "tranType": "RETIRED",
      "assetConditionType": {
        "id": 10,
        "assetConditionType": "UNSERVICEABLE"
      }
    }
  ];

CodePudding user response:

First you need transform your data "grouping" in an object like

  [
    {
      "id": 9,
      "assetConditionType": "SERVICEABLE",
      "items": [
        {
          "id": 1,
          "assetID": 9,
          "tranType": "MAINTENANCE"
          "assetConditionType": {
            "id": 9,
            "assetConditionType": "SERVICEABLE"
          }
        },
        ...
      ]
    }
    ...
  ]

For this we use reduce. Reduce it's no so complex looks like. Imagine you has an array data

const dataTransformed=data.reduce((a,b)=>{
   return function(a,b)
},initial)

If like a loop

   let a=initial
   for (let i=0;i<data.length;i  )
   {
     b=data[i];
     a=function(a,b)
   }
   const dataTransformed=a

So you can use reduce and rxjs map operator in the way

getData(){
   return this.httpClient.get(..your url...).pipe(
      map((data: any[]) => {
        const groupData=data.reduce((a: any, b: any) => {
          const id = b.assetConditionType.id;
          const element = a.find((x: any) => x.id == id);
          
          if (element) element.items.push(b);
          else
          {
          a.push({
              id: id,
              assetConditionType: b.assetConditionType.assetConditionType,
              items: [b],
            });
          }
          return a;
        }, []);
        return groupData
      })
    );
  }

One time you has your data grouped, as you has a few data you can use some like

<mat-form-field appearance="fill">
  <mat-label>Asset</mat-label>
  <mat-select [(ngModel)]="value" (selectionChange)="value2=null">
    <mat-option *ngFor="let item of obs|async" [value]="item">
      {{item.assetConditionType}}
    </mat-option>
  </mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
  <mat-label>Transation</mat-label>
  <mat-select [(ngModel)]="value2">
    <mat-option *ngFor="let item of value?.items" [value]="item">
      {{item.tranType}}
    </mat-option>
  </mat-select>
</mat-form-field>

See that "value" has the whole object grouped, so we can use value.items to give value to the options of the second dropdown

I use [(ngModel)] you can use ReactiveForms. If only are interesting in the "items" only use a FormControl to get the item.

Some like

form=new FormGroup({
   asset:new FormControl()
})

<form [formGroup]="form">
    <mat-form-field appearance="fill">
      ...
      <mat-select [(ngModel)]="value" (selectionChange)="value2=null">
                   [ngModelOptions]="{standalone:true}"
        <mat-option *ngFor="let item of obs|async" [value]="item">
          {{item.assetConditionType}}
        </mat-option>
      </mat-select>
    </mat-form-field>
    <mat-form-field appearance="fill">
      ...
      <mat-select formControlName="asset">
        <mat-option *ngFor="let item of value?.items" [value]="item">
          {{item.tranType}}
        </mat-option>
      </mat-select>
    </mat-form-field>
</form>

See that the "value" is not belong to the form (it's only a auxiliar variable). As not belong to the form you use [(ngModel)] and [ngModelOptions]="{standalone:true}"

NOTE: If you only want the "id" use in the second dropdown [value]="item.id"

a stackblitz

  • Related