Home > Net >  Force update of an Angular component, without changing @Input attributes
Force update of an Angular component, without changing @Input attributes

Time:09-06

I'm picking up Angular (and Typescript with it). I created a small app that has two components. It's for keeping track of work hours (yeah, I know, there are COTS products for that, this is for educational purposes).

One component is for creating a new hour entry (employee project hours date). It has some input boxes and an "Add" button.

The other component shows the hours that the user booked for the selected day. When the "Add" button is clicked in the first component, this component should refresh the data from the API/database.

When I google this, all answers point to @Input arguments. In this case, the detail component has an employeeId and a date as input. These inputs don't change. Only the result (database content) changes for those parameters. I thought of calling one of the methods on the detail component from the container of those two components, but I found no way to do that.

How can I force the detail component to refresh, after the "Add" button is clicked?

Would be grateful for any pointers.

EDIT: Relevant code

dailyHoursOverview.components.ts

import { HttpClient } from "@angular/common/http";
import { Component, Input, OnChanges, OnInit, SimpleChanges } from "@angular/core";
import { Activity } from "../shared/Activity";
import { Employee } from "../shared/Employee";
import { Project } from "../shared/Project";

@Component({
    selector: "hour-daily",
    templateUrl: "./dailyHoursOverview.component.html"
})
export class DailyHoursOverview implements OnInit, OnChanges
{
 //   @Input() date: string = "";
    @Input() employeeId: number = 0;
    @Input() date: string = "";
    _http: HttpClient;

    entries: HourEntry[] = [];
    totalHours: number= 0;

    constructor(http: HttpClient) {
        this._http = http;
    }

    ngOnChanges(changes: SimpleChanges): void {
        this.refreshData();
    }

    ngOnInit(): void {
        this.refreshData();
    }

    refreshData() {
        this._http.get<HourEntry[]>("http://localhost:5257/Employee/"   this.employeeId   "/HourEntry/ByDay/"   this.date)
            .subscribe(
                result => { 
                    this.entries = result;
                    this.totalHours = this.entries.reduce((sum, entry) => sum   (entry.hours), 0); 
                },
                error => console.error(error)
            );
    }
}

interface HourEntry {
    project: Project;
    activity: Activity;
    employee: Employee;
    hours: number;
    date: string;
}

main.component.html (container of both sub components)

<div >
    <div >
        <div >
            <hours-new [employeeId]="employeeId" [hourDate]="date" (entryCreated)="onEntryCreated();"></hours-new>
        </div>
    </div>
    <div >
        <div >
            <hour-daily [employeeId]="employeeId" [date]="date"></hour-daily>
        </div>
    </div>
</div>

newHourEntry.component.ts

import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Activity } from '../shared/Activity';
import { Project } from '../shared/Project';
import { Employee } from '../shared/Employee';
import { NewHourEntryDto } from '../shared/NewHoursEntryDto';

@Component({
    selector: "hours-new",
    templateUrl: "./newHourEntry.component.html"
})
export class NewHourEntryComponent implements OnInit {
    @Input() employeeId: number = 0;
    @Input() hourDate: string = "";
    @Output() entryCreated: EventEmitter<any> = new EventEmitter();

    private _http: HttpClient;

    employeeName: string = "";
    hourEntry: NewHourEntryDto;
    projects: Project[];
    activities: Activity[];

    constructor(http: HttpClient) {
        this._http = http;
        this.hourEntry = { "activityId": 0, "projectId": 0, "date": "", "hours": 0, "employeeId": 0 };
        this.projects = [];
        this.activities = [];
    }
    
    ngOnInit(): void {
        // Get options for comboboxes
        this._http.get<Project[]>('http://localhost:5257/Project')
            .subscribe({
                next: result => { this.projects = result; },
                error: error => console.error(error)
            });

        this._http.get<Activity[]>("http://localhost:5257/Activity")
            .subscribe({
                next: result => { this.activities = result; },
                error: error => console.error(error)
            });

        this._http.get<Employee>("http://localhost:5257/Employee/"   this.employeeId)
            .subscribe({
                next: result => { this.employeeName = result.name; },
                error: error => console.error(error)
            });
    }

    createHourEntry(): void {  // OnClick for the "Add" Button
        this.hourEntry.date = this.hourDate;
        this.hourEntry.employeeId = this.employeeId;
        this._http.post("http://localhost:5257/HourEntry", this.hourEntry)
            .subscribe({
                next: result => { }, 
                error: error => console.error(error)
            });
        this.entryCreated.emit();
    }
}

CodePudding user response:

you can use @Input() setters

Here is an example that shows what I mean

stackblitz

I hope it is useful for you

CodePudding user response:

I would let main.component.html handle the creation and refreshing the data (smart) and only pass data to newHourEntry and dailyHoursOverview (dumb) cfr Smart and dumb components

  • Related