Angular - Problem passing message between components

Asked

Viewed 86 times

0

Good evening, everyone.

I am, for the sake of studies, doing a simple CRUD for managing authors. I got stuck in the part of sending a success message by registering a new author. My current structure is as follows:

--- autores
    --- autores-create
        --- autores-create.component.html (página com o formulário para criação do novo autor)
        --- autores-create.component.ts
    --- shared
        --- autores.service.ts
    --- autor.model.ts
    --- autores.component.html (página principal com a tabela listando todos autores)
    --- autores.component.ts
    --- autores.module.ts

Code of the authors.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { Autor } from './autor.model';
import { AutoresService } from './shared/autores.service';

@Component({
    selector: 'app-autores',
    templateUrl: './autores.component.html'
})
export class AutoresComponent implements OnInit {

    message: string;
    autores: Autor[];

    constructor(private service: AutoresService, private router: Router) { }

    ngOnInit(): void {
        // Chamando o serviço para listar todos os autores
        this.service.getAutores().subscribe(data => {
            this.autores = data;
        })

        // Me inscrevendo no EventEmitter do serviço para saber quando foi gerada nova mensagem
        this.service.message.subscribe(
            (data: string) => { alert(data); this.message = data; }
        );
    }

    removerAutor(id: number) {
        this.service.removerAutor(id).subscribe(resultado => this.autores = this.autores.filter(autores => autores.id !== id));
    }

    // Apenas navega para página com formulário de criação de novo autor
    criarAutor() {
        this.router.navigate(['autores/create']);
    }
}

Code of the authors-create.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';

import { Autor } from './../autor.model';
import { AutoresService } from '../shared/autores.service';

@Component({
    selector: 'app-autores-create',
    templateUrl: './autores-create.component.html'
})
export class AutoresCreateComponent implements OnInit {

    form: FormGroup;
    emailPattern: "^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$";

    constructor(private service: AutoresService, private route: Router) { }

    ngOnInit(): void {
        this.form = new FormGroup({
            'nome': new FormControl(null, [Validators.required]),
            'endereco': new FormControl(null, [Validators.required, Validators.minLength(5)]),
            'email': new FormControl(null, [Validators.required, Validators.email]),
        })
    }

    // Chama o método de criação de novo autor no serviço e quando finaliza navega para a página inicial com a tabela
    criarAutor(data: Autor) {
        this.service.criarAutor(data).subscribe((data) => {
            this.route.navigate(['/autores']);
        });
    }

    campoInvalido(campo: string) {
        if (this.form.get(campo).invalid && (this.form.get(campo).dirty || this.form.get(campo).touched)) {
            return this.form.get(campo).errors;
        }
    }
}

Code of the authors.service.ts

import { Injectable, EventEmitter, Output } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Autor } from '../autor.model';

@Injectable({
    providedIn: 'root'
})
export class AutoresService {

    API_URL: string = 'http://localhost:3000';
    // Campo de mensagem que seria exibida na página da tabela indicando que o novo autor foi criado com sucesso
    @Output() message: EventEmitter<string> = new EventEmitter<string>();

    constructor(private http: HttpClient) { }

    httpOptions = {
        headers: new HttpHeaders({
            'Content-Type': 'application/json',
            'Authorization': 'my-auth-token'
        })
    };

    getAutores(): Observable<Autor[]> {
        return this.http.get<Autor[]>(`${this.API_URL}/autores`)
            .pipe(catchError(this.handleError));
    }

    removerAutor(id: number) {
        return this.http.delete(`${this.API_URL}/autores/${id}`, this.httpOptions)
            .pipe(catchError(this.handleError));
    }

    criarAutor(dados: Autor) {
        // Emissão do evento ao criar novo autor
        this.message.emit("Autor criado com sucesso.")
        return this.http.post(`${this.API_URL}/autores`, dados, this.httpOptions)
            .pipe(catchError(this.handleError));
    }

    private handleError(error: HttpErrorResponse) {
        if (error.error instanceof ErrorEvent) {
            // A client-side or network error occurred. Handle it accordingly.
            console.error('An error occurred:', error.error.message);
        } else {
            // The backend returned an unsuccessful response code.
            // The response body may contain clues as to what went wrong,
            console.error(
                `Backend returned code ${error.status}, ` +
                `body was: ${error.error}`);
        }
        // return an observable with a user-facing error message
        return throwError(
            'Something bad happened; please try again later.');
    };
}

Code of the authors.component.html

<div class="container py-5">
    <div class="row">
        <div class="col-md-12 mb-5 d-flex justify-content-between align-items-center">
            <h1 class="d-inline">Autores</h1>
            <button (click)="criarAutor()" class="btn btn-success">+ autor</button>
        </div>

        <!-- Aqui deveria aparecer a mensagem -->
        <div class="alert alert-success">{{ message }}</div>

        <div class="col-md-12">
            <table *ngIf="autores?.length > 0" class="table" style="table-layout: fixed;">
                <thead>
                    <th>ID</th>
                    <th>Nome</th>
                    <th>Ações</th>
                </thead>

                <tbody>
                    <tr *ngFor="let autor of autores">
                        <td>{{ autor.id }}</td>
                        <td>{{ autor.nome }}</td>
                        <td>
                            <button class="btn btn-warning mr-3">Editar</button>
                            <button (click)="removerAutor(autor.id)" class="btn btn-danger">Remover</button>
                        </td>
                    </tr>
                </tbody>
            </table>

            <p *ngIf="autores?.length === 0">Não existem autores cadastrados.</p>
        </div>
    </div>
</div>

What I found more strange is that in the file authors.component.ts, specifically in this code snippet:

this.service.message.subscribe(
            (data: string) => { alert(data); this.message = data; }
        );

Alert is working correctly but the message is not exchanged! Would anyone have any suggestions? I would like to do this without using libraries ready to fix my learning.

inserir a descrição da imagem aqui inserir a descrição da imagem aqui

I don’t know if that’s the case, but here’s the code of the authors.module.ts

import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http'
import { ReactiveFormsModule } from '@angular/forms';

import { AutoresService } from './shared/autores.service';

import { AutoresComponent } from './autores.component';
import { AutoresCreateComponent } from './autores-create/autores-create.component';

@NgModule({
    declarations: [AutoresComponent, AutoresCreateComponent],
    imports: [CommonModule, HttpClientModule, RouterModule, ReactiveFormsModule],
    providers: [AutoresService]
})

export class AutoresModule { }

And finally, here’s the contents of my app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AutoresModule } from './autores/autores.module';

import { AppComponent } from './app.component';
import { HeaderComponent } from './components/header/header.component';
import { HomeComponent } from './home/home.component';
import { RouterModule } from '@angular/router';

@NgModule({
    declarations: [
        AppComponent,
        HeaderComponent,
        HomeComponent
    ],
    imports: [
        BrowserModule,
        AutoresModule,
        AppRoutingModule,
        RouterModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }

  • So when you say: Alert is working correctly but the message is not exchanged!, the alert will definitely be triggered because it is in the NgOnInit() and when the component is rendered Angular automatically calls this method. I think the error might be this eventEmitter pq it works to make communication from the child component to the parent component, but, by the hierarchy that put in the question, all components are brothers one of the others.

  • Yes but Alert is inside the subscribe, not loose in Ngoninit().. That is, I’m just seeing that Alert after going on the form page and giving Ubmit on it.. and the alert is coming with the right message, the variable data. Throwing that date into my this.message is that nothing happens.

No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.