0

I'm working on an ionic 7 project where I have a page containing three instances of a custom component, and each of these instances passes a different array dataset to the child component. The component is meant to display the received array data in a list and this works perfectly. But when I click on each of the component instances, the data displayed in the child component is always the data passed by the first instance.

I tried passing the data to the child component through the individual instances on the same page. Below is the html page for the parent component (home.page.html).

<ion-content> <app-select title="Select District" [data]="districts" itemTextField="text" [multiple]=false (click)="select.open()" (selectedChanged)="districtChanged($event)" #select></app-select> <app-select title="Select Parish" [data]="parishes" itemTextField="text" [multiple]=false (click)="select.open()" (selectedChanged)="parishChanged($event)" #select></app-select> <app-select title="Select Village" [data]="villages" itemTextField="text" [multiple]=false (click)="select.open()" (selectedChanged)="villageChanged($event)" #select></app-select> </ion-content> 

This is the home.page.ts file

import { Component, OnInit, ViewChild } from '@angular/core'; import { IonDatetime, IonModal } from '@ionic/angular'; export interface Item { text: string; value: string; } @Component({ selector: 'app-add-exporter', templateUrl: './add-exporter.page.html', styleUrls: ['./add-exporter.page.scss'], }) export class AddExporterPage implements OnInit { @ViewChild('modal', { static: true }) modal!: IonModal; public selectedDistrict: String = ''; public selectedParish: String = ''; public selectedVillage: String = ''; public district: any; public districts: Item[] = [ { text: 'District 1', value: 'District 1' }, { text: 'District 2', value: 'District 2' }, { text: 'District 3', value: 'District 3' }, { text: 'District 4', value: 'District 4' }, { text: 'District 5', value: 'District 5' }, { text: 'District 6', value: 'District 6' }, { text: 'District 7', value: 'District 7' }, { text: 'District 8', value: 'District 8' }, { text: 'District 9', value: 'District 9' } ]; public parish: any; public parishes: Item[] = [ { text: 'Parish 1', value: 'Parish 1' }, { text: 'Parish 2', value: 'Parish 2' }, { text: 'Parish 3', value: 'Parish 3' }, { text: 'Parish 4', value: 'Parish 4' }, { text: 'Parish 5', value: 'Parish 5' }, { text: 'Parish 6', value: 'Parish 6' }, { text: 'Parish 7', value: 'Parish 7' }, { text: 'Parish 8', value: 'Parish 8' }, { text: 'Parish 9', value: 'Parish 9' } ]; public village: any; public villages: Item[] = [ { text: 'Village 1', value: 'Village 1' }, { text: 'Village 2', value: 'Village 2' }, { text: 'Village 3', value: 'Village 3' }, { text: 'Village 4', value: 'Village 4' }, { text: 'Village 5', value: 'Village 5' }, { text: 'Village 6', value: 'Village 6' }, { text: 'Village 7', value: 'Village 7' }, { text: 'Village 8', value: 'Village 8' }, { text: 'Village 9', value: 'Village 9' } ]; constructor() { } ngOnInit() { } districtChanged(event: any){ this.selectedDistrict = event[0].text; } parishChanged(event: any){ this.selectedParish = event[0].text; } villageChanged(event: any){ this.selectedVillage = event[0].text; } } 

Select.component.html

<div *ngIf="selected.length; else placeholder"> <span *ngFor="let item of selected; let last = last"> {{ leaf(item) }}{{ last ? '' : ', '}} </span> </div> <ng-template #placeholder>Select</ng-template> <ion-modal [isOpen]="isOpen" (willDismiss)="cancel()"> <ng-template> <ion-header class="ion-no-border"> <ion-toolbar color="primary"> <ion-title>{{ title }}</ion-title> </ion-toolbar> </ion-header> <ion-content class="ion-padding-horizontal"> <ion-item lines="full" *ngFor="let item of filtered"> <ion-checkbox slot="start" labelPlacement="end" justify="start" [(ngModel)]="item.selected" (ionChange)="itemSelected()" > {{ leaf(item) }} </ion-checkbox> </ion-item> </ion-content> </ng-template> </ion-modal> 

And this is the code in the custom component file (select.component.ts).

import { CommonModule } from '@angular/common'; import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges} from '@angular/core'; import { IonicModule, SearchbarCustomEvent } from '@ionic/angular'; @Component({ standalone: true, imports: [IonicModule, CommonModule, FormsModule], selector: 'app-select', templateUrl: './select.component.html', styleUrls: ['./select.component.scss'], }) export class SelectComponent implements OnChanges { @Input() title = 'Search'; @Input() data: any = []; @Input() multiple: boolean = false; @Input() itemTextField = 'name'; @Output() selectedChanged: EventEmitter<any> = new EventEmitter(); isOpen: boolean = false; selected: any[] = []; filtered: any[] = []; constructor() { } ngOnChanges(changes: SimpleChanges): void { this.filtered = this.data; } open(){ this.isOpen = true; this.filtered = this.data; } cancel(){ this.isOpen = false; } select(){ this.isOpen = false; } leaf(obj: any){ return this.itemTextField.split('.').reduce((val, el) => val[el], obj); } itemSelected(){ if(!this.multiple){ if(this.selected.length){ this.selected[0].selected = false; } this.selected = this.data.filter((item: any) => item.selected); this.selectedChanged.emit(this.selected); this.isOpen = false; } } } 

I expected each select component instance to pass it's data to the custom component so that it's displayed within the component. But what actually happened is, when I click on each of the component instances, the data displayed in the child component is always the data passed by the first instance (list of districts), and definitely the value emitted on select is displayed on the first instance, regardless of which instance was clicked. Even when I click the parishes or villages component, I still get districts displayed.

So, I tried a different approach by passing the array data through the select.open() function in home.page.ts

<ion-content> <app-select title="Select District" [data]="districts" itemTextField="text" [multiple]=false (click)="select.open(districts)" (selectedChanged)="districtChanged($event)" #select></app-select> <app-select title="Select Parish" [data]="parishes" itemTextField="text" [multiple]=false (click)="select.open(parishes)" (selectedChanged)="parishChanged($event)" #select></app-select> <app-select title="Select Village" [data]="villages" itemTextField="text" [multiple]=false (click)="select.open(villages)" (selectedChanged)="villageChanged($event)" #select></app-select> </ion-content> 

and edited the open() function in select.component.ts as shown below

 open(data: any[]){ this.data = data; this.isOpen = true; this.filtered = this.data; } 

The data was passed and displayed well for the individual instances, but the problem was that the result is always emitted to the first instance and the value was assigned to the first instance.

I also tried this answer, but still emits the value to the first select input for districts.

1 Answer 1

1

This might be caused by the duplicate #select template variables declared in home.page.html, template variables should only be declared once according to the Angular documentation.

Sign up to request clarification or add additional context in comments.

1 Comment

True, the duplicate template variables were the problem, I renamed them differently and it worked perfectly. Thank you so much.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.