Requires the refreshing of an Angular component without altering any @Input properties

Currently delving into the world of Angular (along with Typescript). I've put together a small application consisting of two components. This app is designed to help track work hours (yes, I am aware there are commercial products available for this purpose, but this project is purely for educational reasons).

One component is responsible for creating new hour entries which include details like employee, project, hours, and date. It features input fields and an "Add" button.

The other component displays the hours booked by the user for the selected day. Upon clicking the "Add" button in the first component, the second component should refresh its data from the API or database.

After researching online, it seems that using @Input arguments is the recommended approach. In this scenario, the detail component takes employeeId and date as inputs, where these remain constant while only the results (database content) may vary. I considered invoking a method on the detail component from the container housing both components, but encountered challenges in doing so.

How can I trigger a refresh in the detail component after the "Add" button is clicked?

Any insights or suggestions will be greatly appreciated.

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 class="container">
    <div class="row">
        <div class="col-md-6 col-sm-8">
            <hours-new [employeeId]="employeeId" [hourDate]="date" (entryCreated)="onEntryCreated();"></hours-new>
        </div>
    </div>
    <div class="row">
        <div class="col-12">
            <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();
    }
}

Answer №1

If you're looking to enhance your code, consider implementing @Input() setters.

Check out this example that demonstrates the concept:

live demo

I trust you will find it beneficial!

Answer №2

In my approach, I delegate the responsibility of managing data creation and updates to main.component.html (smart), while newHourEntry and dailyHoursOverview components remain passive recipients of data (dumb). This strategy aligns with the concept of smart and dumb components.

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

``There seems to be a problem with the ngb time picker when using the up and

Currently, I am utilizing Bootstrap 4 and NG Bootstrap time picker for a project in Angular 10. Despite correctly adding all the code, I have encountered an issue where the up and down arrows on the time picker are not functioning as expected. Below is a s ...

Guide to making a personalized decorator in loopback4

async verifyUserMembership(userId: string, productId: string) { if (userId && productId) { const userExists = await Product.find({ where: { userId: userId, id: productId } }); return !!userExists; } return false; } I am ...

I'm eager to showcase live, incoming data on the chart. However, I'm feeling a bit lost on how to proceed. Can you help

I am currently utilizing the line chart feature of ng2-charts in my Angular project. However, I am unsure how to create a graph with real-time data. Here is an example of some sample data being used for the line chart: lineChartData: ChartDataSets[] = [ { ...

What is the best method for incorporating a delay within the upcoming subscribe block in Angular?

When subscribing to a service method, I have a sequence of actions that need to occur: displaying a toaster, resetting a form, and navigating to another component. However, I want to introduce a delay before the navigation so users can see the toaster mess ...

Whenever a file is chosen, I aim to generate the video HTML dynamically and display the video with play functionalities using Angular 2 and TypeScript

I am attempting to allow users to select a video file and display it so they can play it after choosing the file. Below is my HTML code: <br> <input type="file" (change)="fileChangeEvent($event)" placeholder="upload file..." class=" ...

Error in Angular 2 component when loading background images using relative URLs from an external CSS skin

In my angular2 component, I am utilizing a third-party JavaScript library. The skin CSS of the component attempts to load images using relative URL paths. Since I am following a component-based architecture, I prefer to have all component dependencies enca ...

What is the best way to locate this particular element on the webpage?

After using the right-click and selecting inspect element, I located the code of the desired element on the webpage: <input type="text" ng-if="!editing" ng-model="item.Price" ng-click="inputFocus()" ts="" required="" placeholder="قیمت :" class="ng- ...

Issue with noUnusedLocals flag detection within function* block

Compiler options: "noUnusedLocals": true, "noUnusedParameters": true, are not functioning properly within functions. An error is encountered in the following example: export class AllReduxSagas { [ts] Property 'someService' is declared bu ...

You cannot call this expression. The type 'String' does not have any call signatures. Error ts(2349)

Here is the User class I am working with: class User { private _email: string; public get email(): string { return this._email; } public set email(value: string) { this._email = value; } ...

Issue arises when TypeScript attempts to verify the presence of an array element

I am facing an issue with the following array declaration: // Using const as I require it to be a specific type elsewhere const fruits = ["strawberry", "banana", "orange", "grapefruit"] as const; When attempting to ...

Immutable.Map<K, T> used as Object in Typescript

While refactoring some TypeScript code, I encountered an issue that has me feeling a bit stuck. I'm curious about how the "as" keyword converts a Map<number, Trip> into a "Trip" object in the code snippet below. If it's not doing that, the ...

Direct your attention to the <input> element

I'm developing a front-end application using Angular 5, and I am facing the challenge of implementing a hidden search box that should be displayed and focused when a button is clicked. Although I have explored various solutions from StackOverflow inv ...

Troubleshooting issue with Material UI icons in React application with Typescript

I created a set of icons based on a github help page like this: const tableIcons = { Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />), DetailPanel: forwardRef((props, ref) => ( <ChevronRight {...props} ref={ref} /> ...

Customize the element of the root node of a MUI component using the styled()

I am trying to implement the "component" prop with a MUI component (such as ListItem) using the styled() API. However, I am facing an issue where it says that "component" is not a valid prop. Can someone guide me on how to correctly achieve this? I have se ...

Adding a language dynamically with Transloco: A step-by-step guide

I'm currently developing an app using Angular 8 and NativeScript 6.4.1. After some research, I am leaning towards utilizing Transloco as my translations library. An essential requirement for my app is the ability to dynamically change the language a ...

Solving Angular2 Dependency Issues

I'm curious about Angular 2 and whether there's a way to resolve dependencies without having to use the constructor. In .NET, you can inject dependencies in three ways (constructor, setter, interface-based). Is it possible to do setter injection ...

Visual Studio 2017, ASP.NET framework, Typescript programming language, and node package manager

My ASP.net application in Visual Studio used to only utilize JavaScript, but now I am looking to incorporate Typescript. While the installation and transpiling process went smoothly, I encountered an issue when attempting to import modules. I decided to u ...

Accessing Parent Component's Route Parameters in Child Component in Angular 5

Here we have the add-new-folder.component, which functions as a child component of the folder.component. When routing to the add-new-folder.component from the parent folder.component, I need to access the userid parameter of the parent component in its chi ...

Is it possible to extract specific columns from the Convex database?

I am looking to retrieve all columns from a table using the following code snippet. Is there a more efficient way to achieve this? I couldn't find any information in the documentation. Does anyone have a workaround or solution? const documents = await ...

Leveraging MatSort from Angular Material

In my customer.component.ts file, I have the following code: import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core'; import { NorthwindService } from 'swagger'; import {LiveAnnouncer} from '@angular/cdk/a11y&ap ...