Search code examples
javascriptcsshtml-table

Angular JS: Child Components Rendered in First Column Instead of Corresponding Columns in Parent Component Table


I'm working on an Angular application where I have a parent component (HomeComponent) that renders a table with child components (TableEntriesComponent) in each row. However, I'm facing an issue where all child components are rendering in the first column instead of corresponding columns.

Here is a simplified version of the code:

HomeComponent:

HTML

<h1>
 Home Page
</h1>
<div id="HomeDiv">
    <form>
        <label for="name">Name:</label>
        <input type="text" id="name" [(ngModel)]="name" name="name" required >

        <br>

        <label for="email">Email:</label>
        <input type="email" id="email" name="email" [(ngModel)]="email" required>

        <br>

        <label for="message">Message:</label>
        <textarea id="message"  [(ngModel)]="message" name="message" rows="4" required></textarea>

        <br>

    <input type="submit" value="Submit" (click)="OnSubmit()">
    </form>
    </div>
      <table Id="HomeTable" *ngIf=Issubmitted>
         <tr>
            <th>#</th>
            <th>Name</th>
            <th>Email</th>
            <th>Message</th>
            <th>Remove</th>
       </tr>
<tr *ngFor="let Msg of Messages; let Index=index">
<app-table-entries
        [Index]="Index"
        [Name]="Msg.Name"
        [Email]="Msg.Email"
        [Message]="Msg.Message"
        (onDelete)="onDelete($event)"
      >
</app-table-entries>      
</tr>
</table>

TypeScript

import {Component, OnInit } from '@angular/core';
import { ConstantPool } from '@angular/compiler';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {


name:string='';
email:string='';
message:string='';
Issubmitted:boolean=false;
Messages:Array<any>=[];
 onDelete(index: number): void {
    // Handle the deletion logic for the specified index
    this.Messages.splice(index, 1);
  }
  OnSubmit():void
    {
    this.Issubmitted=true;
    this.Messages.push(
    {
      'Name':this.name,
      'Email':this.email,
      'Message':this.message
    });
    } 
   

constructor() {
  
  
 }

  ngOnInit() {
    
  }

}

CSS

   body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            margin: 0;
            padding: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
        }

        form {
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }

        label {
            display: block;
            margin-bottom: 8px;
        }

        input,
        textarea {
            width: 100%;
            padding: 8px;
            margin-bottom: 16px;
            box-sizing: border-box;
            border: 1px solid #ccc;
            border-radius: 4px;
        }

        input[type="submit"] {
            background-color: #4caf50;
            color: #fff;
            cursor: pointer;
        }

        input[type="submit"]:hover {
            background-color: #45a049;
        }
#SubmittedValue
{
  background-color: lightcoral;
  display: block;
  width: 50%;
  padding: 10pt;
  margin: 10pt;
  border-radius: 20pt;
  color: white;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
  font-weight: bold
}

 table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 20px;
        }

        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }

        th {
            background-color: #f2f2f2;
        }

ChildComponent:

HTML

<td>{{Index+1}}</td>
<td>{{Name}}</td>
<td>{{Email}}</td>
<td>{{Message}}</td>
<td><button (click)="handleDelete()">Del</button></td>

Typescript

import {Input, Output, Component, OnInit, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-table-entries',
  templateUrl: './table-entries.component.html',
  styleUrls: ['./table-entries.component.css']
})
export class TableEntriesComponent implements OnInit {
  @Input() Index: number;
  @Input() Name: string;
  @Input() Email: string;
  @Input() Message: string;
  @Output() onDelete: EventEmitter<number> = new EventEmitter<number>();
  
  handleDelete(): void {
    this.onDelete.emit(this.Index);
  }
  constructor() { }

  ngOnInit() {
  }

}

In the parent component's HTML, I have a table with child components in each row. However, all child components are rendering in the first column. I expected each child component to be in its corresponding column.

Could you please review my code and suggest what might be causing this issue? Am I missing something in the template or the component logic?

Any help or guidance would be greatly appreciated. Thank you!

OUTPUT CURRENTLY COMING

enter image description here

Expected OUTPUT are below

enter image description here


Solution

  • The component is not recognize as a tr. One option is to use the attribute selector [].

    Try it like:

    <table Id="HomeTable" *ngIf=Issubmitted>
            <thead>
             <tr>
                <th>#</th>
                <th>Name</th>
                <th>Email</th>
                <th>Message</th>
                <th>Remove</th>
           </tr>
           </thead>
           <tbody *ngFor="let Msg of Messages; let Index=index">
               
                <tr app-table-entries
            [Index]="Index"
            [Name]="Msg.Name"
            [Email]="Msg.Email"
            [Message]="Msg.Message"
            (onDelete)="onDelete($event)"
           >
          </tr>    
           </tbody>
    </table>
    

    And in your component:

    @Component({
      selector: '[app-table-entries]',
      templateUrl: './table-entries.component.html',
      styleUrls: ['./table-entries.component.css']
    })