Issues with communicating between parent and child components within Angular 9 using mat-tab

As a newcomer to Angular, I've been experimenting with passing data from a parent component to a child component using @Input(), but I'm facing issues with the changes not being reflected. In my parent component, there's a select element and I intend to pass the selected item's value to the children components. The parent component consists of a mat-tab-group containing multiple mat-tabs.

Parent HTML

<mat-form-field>
    <mat-select placeholder="Class" [formControl]="selectedClassControl" (selectionChange)="changeClassId()">
        <mat-option *ngFor="let class of classes" value="{{class.id}}">{{class.classNumber}}-{{class.section}}</mat-option>
    </mat-select>
</mat-form-field>
<mat-tab-group color="primary" (selectedIndexChange)="selectTab($event)">
    <mat-tab label="Units">
        <app-units [classId]="classId" *ngIf="selectedTab === 0"></app-units>
    </mat-tab>
    <!-- other tabs with similar structure --> 
</mat-tab-group>

Parent TS

  classId : number = 0;
  classes: Class[];
  selectedClass: any;
  selectedClassControl = new FormControl(this.selectedClass);
  constructor(private classService: ClassService, private stateMgmtService: 
StateManagementService) { 
    var schoolId = this.stateMgmtService.getSchoolId();
    this.classService.getClasses(schoolId).subscribe(data =>{
      this.classes = data;
    })
  }
  selectedTab = 0;
  ngOnInit(): void {
  }

  selectTab(event) {
    this.selectedTab = event;
  }

  changeClassId(){
    this.classId = this.selectedClassControl.value;
    console.log("ClassId changed to "+this.classId);
  }

Child HTML

<mat-form-field>
    <mat-select placeholder="Subject" [formControl]="selectedSubjectControl" >
        <mat-option *ngFor="let subject of subjects" value="{{subject.id}}">{{subject.code}}-{{subject.name}}</mat-option>
    </mat-select>
</mat-form-field>

Child TS


  @Input() classId : number = 0;
  subjects: Subject[];
  selectedSubject: any;
  selectedSubjectControl = new FormControl(this.selectedSubject);
  constructor(private classService: ClassService) { 
    console.log("classId"+this.classId);
    if(this.classId != 0)
    classService.getSubjects(this.classId).subscribe( data => {
      this.subjects = data;
    })
  }

I've noticed that when I make a selection in the parent component, the classId isn't passed to the child component. Is it necessary for me to manually refresh the component for the changes to take effect?
Any assistance would be greatly appreciated...
Thanks in advance!

Answer №1

When working on this code, it's important to take note of a few things. Firstly, be cautious when naming your classes, as using "Subject" may conflict with the rxjs object of the same name that you could unintentionally import. It would be advisable to choose a more unique and specific class name.

Regarding the selectionChange event logic, you can simplify it by subscribing to the valueChanged property of the form control instead. You can update the classId variable whenever there is a change by implementing it like this:

this.selectedClassControl.valueChanges.subscribe(e => this.classId = e),

In the child component, while the classId updates correctly, the Subject array does not. To address this issue, consider using a setter for your input, as demonstrated below:

@Input() set classId(val: number) {
   this._classId = val;
 if(val != 0) {
  classService.getSubjects(val).subscribe( data => {
   this.subjects = data;
  }); //assuming this is an http service so no unsubscribe is required
}
}
private _classId: number = 0;

Answer №2

To ensure the constructor is not fired too soon for the input variable, it is recommended to manually listen to changes in the input variable through the use of the OnChanges hook. You can implement this by following the code snippet below:

import { Component, Input, OnChanges } from "@angular/core";

export class ChildComponent implements OnChanges {
  @Input() classId: number = 0;
  subjects: Subject[];
  selectedSubject: any;
  selectedSubjectControl = new FormControl(this.selectedSubject);

  constructor(private classService: ClassService) { }

  ngOnChanges() {
    console.log("classId" + this.classId);
    if(this.classId != 0) {
      this.classService.getSubjects(this.classId).subscribe( data => {
        this.subjects = data;
      });
    }
  }

  private doSomething(input: string) {}
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble connecting 'chartData' to a 'div' in Angular 2 because it is not recognized as a valid property?

While working on my Angular project, I encountered the following error that I have been unable to resolve: EXCEPTION: Uncaught (in promise): Error: Template parse errors: Can't bind to 'chartData' since it isn't a known property of ...

Using React to make an API request depending on the selected option

In my code, I have a function that receives the value of a selected option. There are three different select options (level, facility, host), and when an option is selected, its value is sent to this function. private optionFilterHandler = (option: string ...

Error message: 'DialogContent' component is dependent on 'DialogTitle' component and needs to be implemented in NextJs and ReactJs with ShadCN

I've encountered the same error multiple times in my project, even after double-checking that each DialogContent component contains a DialogTitle within it. After thoroughly inspecting all my imports to ensure they are from ShadCN and not mistakenly ...

Avoiding the use of reserved keywords as variable names in a model

I have been searching everywhere and can't find a solution to my unique issue. I am hoping someone can help me out as it would save me a lot of time and effort. The problem is that I need to use the variable name "new" in my Typescript class construct ...

Mastering the art of utilizing generic types efficiently within Higher Order Component structures

My parent component (Grid) passes props to a higher-order component (hoc), let me show you: <QuickBooksTable itemList={quickBooksList} /> Here is the QuickBooksTable component: export const QuickBooksTable = withIntegrationTable(props: : WithIntegra ...

What steps should I take to plan a collaborative code-sharing project?

As I develop various applications utilizing a core framework of my own creation, I am looking for a way to easily manage updates across all these applications. I have structured the code by creating a GitHub project where the main branch consists of the co ...

What is the best way to generate a displayName with a bindable property in C#

I have a requirement to create a custom textbox that can handle different display names for two separate textboxes - one for firstName and the other for LastName. Is there a way to achieve this by adding a displayName property in the UI side? For example, ...

NestJs encountering issues with reading environment variables

I used the instructions from the Nest documentation to set up the configuration, however, it's not functioning correctly. app.module.ts @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), TypeOrmModule.forRoot(config), AuthMo ...

I'm having trouble establishing a connection with the Appwrite platform

Encountered an issue while trying to connect to appwrite. The specific error message is: Uncaught (in promise) TypeError: Failed to construct 'URL': Invalid URL at Account.<anonymous> (appwrite.js?v=d683b3eb:932:19) at Generator.nex ...

Discover the perfect way to implement true lazyloading using NativeScript Angular tabs and BottomNavigation

Currently working on an app using nativescipt, I've successfully added BottomNavigation with lazy loading and Tab components in child pages. The code structure resembles the following: export const routes: Routes = [ { path: '', red ...

I encountered an issue trying to run my Angular project on multiple computers

We are currently transitioning to a team-based approach for our Angular project, as a new developer has recently joined. However, we are facing some challenges in getting the project up and running on the new computer. We need assistance troubleshooting th ...

Angular components are persisting instead of being destroyed

When navigating to a new page in my Angular application, I've noticed that the component from the previous page remains in memory instead of being destroyed. This results in a new instance being created when I navigate back to that page. The applicat ...

Modifying the Design of Angular Material Dialog

I am currently working on creating a modal using Angular Material Dialog, but I want to customize the style of Angular Material with Bootstrap modal style. I have tried using 'panelClass' but the style is not being applied. Has anyone else faced ...

The Angular ngFor loop seems to be stuck in an endless cycle while trying to display

I'm currently in the process of creating a Logbox for my web application. It is designed to receive an Array of logs and display them row by row within a div. I am utilizing ngFor to iterate through my Array of logs and then present them. However, I& ...

How can we efficiently determine if a background image is broken in Angular 5 and substitute it with a default image?

When working with Angular 2+, we often use the <img> tag to display images using a syntax like <img [src]="myDp" (error)="myDp='assets/media/user/default_dp.jpg'">, where myDp contains the relative path to the image on the server. Is ...

Encountering an issue with Auth0 and Angular2: "The supplied parameters do not match any signature of call target."

I'm currently in the process of integrating Auth0 with my Angular2 application using angular2-cli. I've added a new service called auth, but when I try running npm start, I encounter an error stating: src/app/auth.service.ts (21,5): Supplied para ...

Using style binding and ngStyle doesn't appear to be effective for setting a background image within a DIV element in Angular5

After facing difficulties in customizing the spacing of Angular material cards, I decided to create my own cards. However, during this process, I encountered an issue where I needed to set an image as a background inside a div. Despite trying various CSS ...

Tips for arranging various information into a unified column within an Antd Table

Is there a way to display multiple data elements in a single cell of an Ant Design table, as it currently only allows insertion of one data element? I am attempting to combine both the 'transactionType' and 'sourceNo' into a single cell ...

Terminal displaying a running error for a NestJS CLI project

Encountered an error while running the command yarn start:dev in my WebStorm integrated terminal. Error Snapshot https://i.sstatic.net/Oug8y.png Sharing my package.json file below { "name": "test-project", "version": "0.0.1", "description": "", ...

Encountering an error while trying to run ng serve following ng build

Currently working on my initial Angular application, I am in the process of setting up an existing Angular app on my local machine. Encountered the following error message when running ng serve ERROR in src/app/common-componets/directives/dropFile/d ...