angulartypescriptenumscomponents

Angular Component Template does not compile


Using Angular 17, I work through Matt Thornfield's video series of real site with Angular. An enum shall render its value on template, but typescript does not compile it. I read https://stackblogger.com/no-index-signature-found/. But how is this applied on component template? I tried that for 3 hours, but I failed miserably.

compiler error messager:

X [ERROR] NG3: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof Layout'. No index signature with a parameter of type 'string' was found on type 'typeof Layout'. [plugin angular-compiler]

src/app/admin/rooms/room-edit/room-edit.component.html:19:36:
  19 │     <label for="layout{{layout}}">{{layoutEnum[layout]}}</label>
     ╵                                     ~~~~~~~~~~~~~~~~~~

Error occurs in the template of component RoomEditComponent.

src/app/admin/rooms/room-edit/room-edit.component.ts:7:15:
  7 │   templateUrl: './room-edit.component.html',

Layout.ts

export enum Layout {
    THEATER = "Theater",
    USHAPE = "U-Shape",
    BOARD = "Board Meeting"
}

room-edit.component.ts:

import { Component, Input, OnInit } from '@angular/core';
import { Layout, Room } from '../../../model/room';
import { FormControl, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-room-edit',
  templateUrl: './room-edit.component.html',
  styleUrl: './room-edit.component.css'
})
export class RoomEditComponent implements OnInit{

  @Input() room: Room;

  layouts = Object.keys(Layout);
  layoutEnum = Layout;

  roomForm = new FormGroup(
    {
      roomName : new FormControl('roomName'),
      location: new FormControl('location')
    }
  );
  
  constructor() {
    this.room = new Room();
  }

  ngOnInit(): void {
    this.roomForm.patchValue({
      roomName:  this.room.name,
      location: this.room.location
    });
  }

  onSubmit() {
    this.room.name = this.roomForm.controls['roomName'].value ?? '';
    this.room.location = this.roomForm.value['location'] ?? '';
    console.log(this.room);
  }
}

room-edit.component.html:

<h1> {{room.id == null ? 'Add' : 'Edit'}} Room</h1>

<form [formGroup]="roomForm">
  <div class="form-group">
    <label for="name">Name</label>
    <input type="text" class="form-control" id="name" placeholder="room name" formControlName="roomName" >
    <div class="alert alert-danger"></div>

  </div>
  <div class="form-group">
    <label for="location">Location</label>
    <input type="text" class="form-control" id="location" placeholder="location" formControlName="location" >
    <div class="alert alert-danger"></div>
  </div>

  <h2>This room can accomodate:</h2>

  <div class="form-group" *ngFor="let layout of layouts">
    <label for="layout{{layout}}">{{layoutEnum[layout]}}</label>
    <input type="number" class="form-control" id="layout{{layout}}" formControlName="layout{{layout}}">
  </div>

  <!-- list the layout types here -->

  <button type="button" class="btn btn-primary" (click)="onSubmit()" >Save</button>
</form>

Solution

  • Let's try to move the layout fetch based on the key to the RoomEditComponent.

    RoomEditComponent - add new method:

    getLayoutByKey(layoutKey: string): Layout {
        return this.layoutEnum[layoutKey as keyof typeof Layout]
    }
    

    room-edit.component.html - change line:

    <label for="layout{{layout}}">{{layoutEnum[layout]}}</label>
    

    to:

    <label for="layout{{layout}}">{{ getLayoutByKey(layout) }}</label>