7
respostas

Inclusão de notificações não atualizam a tela

Olá amigos, essa situação tem me tirado o sono por mais de uma semana Implementei o componente de notificação conforme o padrão passado no curso e em um cadastro aciono um novo alerta de sucesso, entretanto o novo alerta não consta na tela fisicamente, apenas consigo visualizar seus detalhes e o estado da lista de alertas no console do desenvolvedor mas o template do componente não exibe a mudança, isso ocorre também para qualquer variável atualizada dentro de um subscribe Pesquisei muito e tentei acionar a detecção de mudanças manualmente via NgZone, ChangeDetectorRef e ApplicationRef mas nada surte resultado, creio ser algum problema de versão visto que uso um package.json com versões diferentes das utilizadas no curso, tentei até colar todas as versões iguais as usadas no projeto de exemplo do curso mas tenho uma série de problemas no npm install Pensei também em recriar o projeto com as versões usadas pelo professor mas pelo que entendi nas buscas não é possível gerar o projeto do zero com uma versão específica Agradeço se algum amigo conseguir me auxiliar Vou incluir o link do repositório para facilitar a depuração do problema e não ficar muito código aqui no tópico https://github.com/RenanFR/opinionatedWeb Os fontes referente ao componente de notificação estão dentro da pasta shared e faço a invocação dele dentro do componente layout Faço um ngIf para exibir um texto padrão caso não haja notificações na lista, porém mesmo quando uma nova é incluída e o length fica positivo o template não é alterado

7 respostas

Bom dia, Jefferson! Como vai?

No primeiro curso sobre Angular o mestre Flávio fala sobre a questão de detecção de mudanças e como esse sistema funciona! Ele mostra que para o Angular detectar uma mudança o correto, no caso de arrays, é sempre criar uma nova referência com um novo array em vez de dar push() adicionando novos itens num array previamente existente!

Sendo assim, imagino que o problema seja na classe NotificationComponent, pois seu código incorre justamente nesse erro! Hoje está assim:

// src/app/shared/notification.component.ts

export class NotificationComponent implements OnInit {

    @Input() timeToEase: number = 30000;

    public notifications: Notification[] = [];
    public testMessage: string = 'Default text';

    // Restante do código omitido.

    ngOnInit(): void {
        this.notificationService
        .notifications()
        .subscribe((alert) => {
            //this.testMessage = 'Service updated the text';
            //this.zone.run(() => {
            //    this.testMessage = 'Service updated the text';
            //});
            console.log(alert);
            if (!alert) {
                console.log('Null alert arrived to reset notifications');
                this.notifications = [];
                return;
            }
            console.log('Including new alert');
            this.notifications.push(alert);
            console.log(this.notifications);
            console.log('Number of notifications ' + (this.notifications.length));
            //this.viewUpdate.detectChanges();
            //this.app.tick();
            setTimeout(() => this.cancelAlert(alert), this.timeToEase);
        });
    }

    // Restante do código omitido.
}

Contudo, essa linha this.notifications.push(alert) deveria ser this.notifications = [ ...this.notifications, alert ]. Dessa forma o Angular detecta que houve uma mudança de referência no seu array e faz a atualização na tela.

Pode ser que o problema não seja somente esse, mas foi o que eu percebi até o momento!

Faça essa alteração aí e veja se as coisas passam a funcionar como vc esperava!

Qualquer coisa é só falar!

Grande abraço e bons estudos, meu aluno!

Bom dia Gabriel, obrigado pela atenção Tentei como você disse criar uma nova referência ao invés de só fazer o push, porém não funcionou, sendo que a segunda linha e a sintaxe que você deu como exemplo não compilam por conta do retorno

            // this.notifications = this.notifications.concat(alert);
            // this.notifications = this.notifications.push(alert);

Em relação a questão do array, imaginei que poderia ser essa particularidade mas fiz um teste também como uma string (Essa variável testMessage) e nem mesmo ela é alterada O interessante é que no CategoriesComponent fiz o teste de mudança de valor em variável no subscribe e nele funciona normalmente, a única diferença que notei em relação ao componente com problema é que ele consome um Observable de um serviço meu com tipo definido, já o de notificações consome o retorno de um Subject convertido com asObservable Imaginei que poderia ser também a tratativa de excluir os alertas após certo tempo que me impedia de ver os mesmos mas mesmo comentando todo o código envolvido o resultado é o mesmo A única forma que encontrei de visualizar o template com notificações foi inicializar fixo o vetor notifications com alguns objetos mas isso não permite a alteração dinâmica como é o esperado Se puder esclarecer qualquer outro ponto fico a disposição

Olá, alguém consegue me ajudar com isso?

Boa noite, Jefferson! Como vai!

sendo que a segunda linha e a sintaxe que você deu como exemplo não compilam por conta do retorno

Não entendi essa parte do que vc disse! Qual linha exatamente não compilou com a modificação que eu sugeri?

Usar o push para atribuir um novo retorno ao vetor de notificações não compila aqui para mim Consegui atualizar na inclusão do alerta mudando ChangeDetectionStrategy para OnPush, entretanto o trecho de código que zera o vetor com base no Timeout não atualiza o ngIf e o alerta recém incluído não some a menos que eu mude de página o que aciona o subscribe nas mudanças de rota feito pelo NotificationService Ficou assim o código, consegue só me auxiliar nessa parte de zerar as notificações e atualizar o template depois do Timeout?

import { Component, Input, ChangeDetectorRef, NgZone, OnDestroy, OnInit, ChangeDetectionStrategy, ApplicationRef } from "@angular/core";
import { Notification, AlertType } from "./notification";
import { NotificationService } from "./notification.service";

@Component({
    selector: 'opinionated-notification',
    templateUrl: './notification.component.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotificationComponent implements OnInit {

    @Input() timeToEase: number = 30000;

    public notifications: Notification[] = [];
    public testMessage: string = 'Default text';

    constructor(
        private notificationService: NotificationService,
        private zone: NgZone,
        private app: ApplicationRef,
        private viewUpdate: ChangeDetectorRef
    ){  }

    ngOnInit(): void {
        this.notificationService
        .notifications()
        .subscribe((alert) => {
            this.testMessage = 'Service updated the text';
            console.log(alert);
            if (!alert) {
                console.log('Null alert arrived to reset notifications');
                this.notifications = [];
                return;
            }
            console.log('Including new alert');
            this.notifications = this.notifications.concat(alert);
            console.log(this.notifications);
            console.log('Number of notifications ' + (this.notifications.length));
            setTimeout(() => this.cancelAlert(alert), this.timeToEase);
        }, (e) => {
            console.log(e);
            this.testMessage = 'Error on subscribe';
        });
    }

    private cancelAlert(notification: Notification): void {
        console.log('Current number of notifications ' + (this.notifications.length));
        console.log(notification);
        this.notifications = this.notifications.filter((not) => not != notification);
        console.log(this.notifications);
        console.log('Removing alerts, notification is now with length ' + this.notifications.length);
    }

    public getNotificationStyle(alert: Notification): string {
        if (!alert) return "";
        switch(alert.alertType) {
            case AlertType.ERROR:
                return "alert alert-danger";
            case AlertType.INFO:
                return "alert alert-info";
            case AlertType.SUCCESS:
                return "alert alert-success";
            case AlertType.WARNING:
                return "alert alert-warning";

        }
    }

    public updateView(): void {
        this.testMessage = 'Text updated by function';
    }

    public isEmptyAlerts(): boolean {
        console.log('Checking number of notifications');
        return this.notifications.length === 0;
    }

}
<div *ngIf="!isEmptyAlerts(); else emptyNotifications">

    <div *ngFor="let notif of notifications" class="{{ getNotificationStyle(notif) }}" role="alert">
        {{ notif.message }}
    </div>

</div>
<ng-template #emptyNotifications>
    <div class="alert alert-warning alert-dismissible" role="alert">
    <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>    
        List of notifications empty
    </div>
</ng-template>
<div (click)="updateView()">{{  testMessage   }}</div>

Opa, Jefferson!

Usar o push para atribuir um novo retorno ao vetor de notificações não compila aqui para mim

Mas na minha primeira sugestão o que eu falei foi justamente para deixar de usar o push() e passar a utilizar this.notifications = [ ...this.notifications, alert ].

Ficou assim o código, consegue só me auxiliar nessa parte de zerar as notificações e atualizar o template depois do Timeout?

Sem ter o código para poder executar fica difícil ajudar de forma efetiva. Se vc puder compartilhar o código completo de alguma forma, como pelo github, eu posso até tentar!

Obrigado Gabriel, o problema aqui não é o push, tanto é que se fizer o download do código final do projeto no último capítulo do curso vai ver que é a abordagem que o professor utiliza também, a questão é essa detecção de mudanças problemática mesmo O back end desse projeto está cheio de dependências de infraestrutura então creio que te sobrecarregaria subir tudo aí, vou tentar resolver aqui e atualizo o tópico com a solução se encontrar De qualquer maneira obrigado pela boa vontade