Mr. Learner
Mr. Learner

Reputation: 1038

Angular 11 - Reusable component not working

I'm trying to understand and implement REUSEABLE in concept in Angular. so trying to create reusable component <mat-card> which I want to use it in different module's component.

so for I've created like below skeleton for reusability. But after the compilation I'm getting 'empTotalCount' undefined error.

Could someone tell me, the way i tried is wrong or the understanding about reusability with help of @Input() is wrong.?

Kindly someone suggest me proper implementation or any other approach for code reusability.

EDITED

  1. create generic-MAT-CARD
  2. use generic-MAT-CARD in my target-component-1 with different data
  3. use same generic-MAT-CARD in my target-component-2 with different data

MY Faulty Stackblitz

(Note: same code working in my local but which is shows compilation err in stackblitz )

Infocard.ts

export interface Infocard {
    empCardHeader: string;  
    empTotalCount: string;
    
    empDirLbl: string;
    empDirectCount:string;
    
    empTempLbl: string;
    empTemprory:string;
    
    empDirStatus:string;
    empTempStatus:string;
}

generic-card-component.html

<mat-card class="example-card mat-elevation-z8">
    <mat-card-header>
        <div mat-card-avatar class="example-header-image"></div>
        <mat-card-title><span class="device-count">{{empInfo.empTotalCount}} </span>
            {{empInfo.empCardHeader}}</mat-card-title>
    </mat-card-header>

    <mat-card-content>
        <div class="connected-device-info">
            <label class="device-status">{{empInfo.empDirLbl}} </label>
            <span class="device-count">{{empInfo.empDirectCount}}</span>
        </div>
        <div class="offline-device-info">
            <label class="device-off-status">{{empInfo.empTempLbl}} </label>
            <span class="device-count">{{empInfo.empTemprory}}</span>
        </div>
    </mat-card-content>
    <mat-card-actions class="card-action">
        <button mat-button>SHARE</button>
    </mat-card-actions>
</mat-card>

generic-card-component.ts

import { Component, Input, OnInit } from '@angular/core';
import { Infocard } from './infocard';

@Component({
  selector: 'app-generic-card-layout',
  templateUrl: './generic-card-layout.component.html',
  styleUrls: ['./generic-card-layout.component.scss']
})
export class GenericCardLayoutComponent implements OnInit {

  @Input() empInfo: Infocard;

  constructor() { }

  ngOnInit(): void {
  }

}


 module-1/myTarget1-component.html

 <app-generic-card-layout [empTotalCount] = "2" ></app-generic-card-layout>
  
 
 module-2/myTarget2-component.html

 <app-generic-card-layout [empTotalCount] = "2" ></app-generic-card-layout>

Thanks all

Upvotes: 0

Views: 954

Answers (1)

Alexander Staroselsky
Alexander Staroselsky

Reputation: 38767

You are getting an error because you are not providing the component the expected input with the expected name and expected structure. In your generic card component you specified an @Input() of:

@Input() empInfo: Infocard;

This means the component will expect to receive/bind a property with the name empInfo and a value of an object that has the structure you specified in the interface Infocard. In the current state of the component, if you try to pass any other custom property or if you pass empInfo that does not match the interface Infocard, it will give you an error.

Your example MyTarget2Component/MyTarget2Component would look something like instead:

Component:

// specify an object that matches structure of interface Infocard
empInfo: Infocard = {
  empTotalCount: '2',
  empCardHeader: 'ADC Employees',
  empDirectLbl: 'foo',
  empContractLbl: 'bar',
  empDirectCount: 'fizz',
  empContractCount: 'buzz'
};

Template:

// bind to property `empInfo` that matches the @Input() and matches interface `Infocard`
<app-generic-card [empInfo]="empInfo"></app-generic-card>

What you seem to be trying to do in your example is trying to pass individual properties of interface Infocard. If you want to do that, instead of passing an object with those properties, you need to update your @Input() statements, angular will not destructure/unwrap those properties for you:

  @Input() empCardHeader: string;
  @Input() empTotalCount: string;

  @Input() empDirectLbl: string;
  @Input() empContractLbl: string;

  @Input() empDirectCount: string;
  @Input() empContractCount: string;

Here is a working example using the original @Input().

Upvotes: 2

Related Questions