Recarregar mesma página em angular, sem o refresh na tela

Tenho este component

import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ViewEncapsulation,
} from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { PageEvent } from "@angular/material/paginator";
import { ActivatedRoute, Router } from "@angular/router";
import { fuseAnimations } from "@fuse/animations";
import { FuseMediaWatcherService } from "@fuse/services/media-watcher";
import { StateStorageService } from "app/core/auth/state-storage.service";
import { DefaultListarComponent } from "app/core/classes/default.listar.component";
import { environment } from "environments/environment";
import { ReplaySubject, Subject, takeUntil } from "rxjs";

@Component({
  selector: "pedido-venda",
  templateUrl: "./pedido-venda-pesquisa.component.html",
  styles: [
    `
      .pedido-venda-grid {
        grid-template-columns: 48px auto 40px;

        @screen sm {
          grid-template-columns: 48px auto 112px 72px;
        }

        @screen md {
          grid-template-columns: 48px 112px auto 112px 72px;
        }

        @screen lg {
          grid-template-columns: 48px 112px auto 112px 96px 96px 72px;
        }
      }
    `,
  ],
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  animations: fuseAnimations,
})
export class PedidoVendaPesquisaComponent extends DefaultListarComponent {
  colunas: string[] = [];
  rota = "pedido-venda/";
  urlBase = "pedido-venda";
  nomePagina = "Pedido de venda";
  environmentBackend = environment.VENDA;
  private _unsubscribeAll: Subject<any> = new Subject<any>();
  filtrarData: boolean = false;
  formGroup = new FormGroup({
    idEmpresa: new FormControl(),
  });
  reionais: any[] = [];
  regionalFilterCtrl: FormControl = new FormControl();
  filteredRegional: ReplaySubject<any[]> = new ReplaySubject<any[]>(1);

  constructor(
    protected router: Router,
    protected stateStorageService: StateStorageService,
    private _changeDetectorRef: ChangeDetectorRef,
    private _fuseMediaWatcherService: FuseMediaWatcherService,
    protected routaAtual: ActivatedRoute
  ) {
    super(router, stateStorageService);
    router.events.subscribe((x) => {
      this.pesquisar();
    });
  }

  async ngOnInit(): Promise<void> {
    await super.ngOnInit();
    const usuarioLogado = this.stateStorageService.getUsuarioLogado();
    if (
      usuarioLogado !== null &&
      usuarioLogado.tipoUsuario === "ROLE_ADMINISTRADOR"
    ) {
      this.colunas = [
        "botoes",
        "empresa",
        "cliente",
        "representanteVendedor",
        "operacao",
        "dataPedido",
        "valorTotal",
        "status",
        "statusDoRegistro",
      ];
    } else {
      this.colunas = [
        "botoes",
        "cliente",
        "representanteVendedor",
        "operacao",
        "dataPedido",
        "valorTotal",
        "status",
        "statusDoRegistro",
      ];
      this.idEmpresa = this.stateStorageService.getUsuarioLogado().idEmpresa;
    }
    await this.pesquisaBancos();
  }

  async pesquisaBancos(
    index = 0,
    length = this.numeroPaginaInicial
  ): Promise<void> {
    let idEmpresa: string = null;
    const usuarioLogado = this.stateStorageService.getUsuarioLogado();
    if (
      usuarioLogado !== null &&
      usuarioLogado.tipoUsuario === "ROLE_ADMINISTRADOR"
    ) {
      if (this.formGroup.controls.idEmpresa !== undefined) {
        idEmpresa = this.formGroup.controls.idEmpresa.value;
      }
    } else {
      idEmpresa = this.stateStorageService.getUsuarioLogado().idEmpresa;
    }
    this.pesquisa = {
      paginaAtual: index,
      quantidadeRegistros: length,
      direcao: this.sort.direction,
      campo: this.sort.active,
      idEmpresa,
    };
    super.pesquisar();
    await this.ajusteTela();
  }

  async paginacao(event?: PageEvent): Promise<void> {
    this.pesquisaBancos(event?.pageIndex, event?.pageSize);
  }

  async limpar(): Promise<void> {
    this.pesquisaBancos();
  }

  async abrirPesquisa(): Promise<any> {
    await this.ajusteTela();
  }

  private async ajusteTela(): Promise<any> {
    this._fuseMediaWatcherService.onMediaChange$
      .pipe(takeUntil(this._unsubscribeAll))
      .subscribe(({}) => this._changeDetectorRef.markForCheck());
  }
}

E este html

<div
  class="sm:absolute sm:inset-0 flex flex-col flex-auto min-w-0 sm:overflow-hidden bg-card bg-gray-50 dark:bg-transparent"
  style="width: 100%; height: 100%; padding-bottom: 100px"
>
  <div
    class="relative flex flex-col sm:flex-row flex-0 sm:items-center sm:justify-between py-8 px-6 md:px-8 border-b"
  >
    <div class="absolute inset-x-0 bottom-0" *ngIf="isLoading">
      <mat-progress-bar [mode]="'indeterminate'"></mat-progress-bar>
    </div>
    <breadcrumb paginaAtual="{{ nomePagina }}"></breadcrumb>
    <div style="top: 400px">
      <button
        pTooltip="Todos registros de {{ nomePagina }}"
        class="ml-4"
        mat-flat-button
        [color]="'primary'"
        (click)="limpar()"
      >
        <mat-icon [svgIcon]="'heroicons_outline:arrow-path'"></mat-icon>
      </button>
      <button
        class="ml-4"
        mat-flat-button
        [color]="'primary'"
        (click)="novo()"
        *ngIf="podeIncluir"
        pTooltip="Incluir {{ nomePagina }}"
      >
        <mat-icon [svgIcon]="'heroicons_outline:plus'"></mat-icon>
      </button>
    </div>
  </div>
  <div class="flex flex-auto overflow-hidden">
    <div
      class="flex flex-col flex-auto overflow-hidden sm:overflow-y-auto overflow-x-auto"
    >
      <div class="grid" fuseScrollbar>
        <table
          style="width: 100%"
          class="pedido-venda-grid"
          #table
          mat-table
          [dataSource]="dataSource"
          [trackBy]="trackByFn"
          #recentTransactionsTable
          matSort
          matSortActive="id"
          matSortDisableClear
          matSortDirection="desc"
          fusePerfectScrollbar
        >
          <ng-container matColumnDef="botoes">
            <th mat-header-cell *matHeaderCellDef>
              <span class="whitespace-nowrap"></span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <span
                class="pr-6 font-medium text-sm text-secondary whitespace-nowrap"
              >
                <button
                  *ngIf="podeAlterar"
                  class="ml-4"
                  mat-flat-button
                  [color]="'primary'"
                  (click)="alterar(entidade.idString)"
                  pTooltip="Alterar {{ nomePagina }}"
                >
                  <mat-icon [svgIcon]="'heroicons_outline:pencil'"></mat-icon>
                </button>
                <button
                  *ngIf="podeVisualizar"
                  class="ml-4"
                  mat-flat-button
                  [color]="'primary'"
                  (click)="visualizar(entidade.idString)"
                  pTooltip="Visualizar {{ nomePagina }}"
                >
                  <mat-icon [svgIcon]="'heroicons_outline:eye'"></mat-icon>
                </button>
                <button
                  *ngIf="
                    podeAtivarInativar &&
                    'ATIVO' === entidade.statusDoRegistro.key
                  "
                  class="ml-4"
                  mat-flat-button
                  [color]="'warn'"
                  (click)="ativarDesativar(entidade.idString, 'INATIVAR')"
                  pTooltip="Inativar {{ nomePagina }}"
                >
                  <mat-icon
                    [svgIcon]="'heroicons_outline:hand-thumb-down'"
                  ></mat-icon>
                </button>
                <button
                  *ngIf="
                    podeAtivarInativar &&
                    'ATIVO' !== entidade.statusDoRegistro.key
                  "
                  class="ml-4"
                  mat-flat-button
                  [color]="'accent'"
                  (click)="ativarDesativar(entidade.idString, 'ATIVAR')"
                  pTooltip="Ativar {{ nomePagina }}"
                >
                  <mat-icon
                    [svgIcon]="'heroicons_outline:hand-thumb-up'"
                  ></mat-icon>
                </button>
                <button
                  *ngIf="podeDuplicar"
                  class="ml-4"
                  mat-flat-button
                  [color]="'primary'"
                  (click)="duplicar(entidade.idString)"
                  pTooltip="Duplicar este registro"
                >
                  <mat-icon [svgIcon]="'heroicons_outline:sparkles'"></mat-icon>
                </button>
                <button
                  *ngIf="podeExcluir"
                  class="ml-4"
                  mat-flat-button
                  [color]="'warn'"
                  (click)="deletar(entidade.idString)"
                  pTooltip="Deletar {{ nomePagina }}"
                >
                  <mat-icon [svgIcon]="'heroicons_outline:trash'"></mat-icon>
                </button>
              </span>
            </td>
          </ng-container>
          <ng-container matColumnDef="empresa">
            <th mat-header-cell mat-sort-header *matHeaderCellDef>
              <span class="whitespace-nowrap">Empresa</span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <span
                class="pr-6 font-medium text-sm text-secondary whitespace-nowrap"
              >
                {{ entidade.nomeEmpresa }}
              </span>
            </td>
          </ng-container>
          <ng-container matColumnDef="cliente">
            <th mat-header-cell mat-sort-header *matHeaderCellDef>
              <span class="whitespace-nowrap">Cliente</span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <span
                class="pr-6 font-medium text-sm text-secondary whitespace-nowrap"
              >
                {{ entidade.cliente }}
              </span>
            </td>
          </ng-container>
          <ng-container matColumnDef="representanteVendedor">
            <th mat-header-cell mat-sort-header *matHeaderCellDef>
              <span class="whitespace-nowrap">Representante / vendedor</span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <span
                class="pr-6 font-medium text-sm text-secondary whitespace-nowrap"
              >
                {{ entidade.representanteVendedor }}
              </span>
            </td>
          </ng-container>
          <ng-container matColumnDef="operacao">
            <th mat-header-cell mat-sort-header *matHeaderCellDef>
              <span class="whitespace-nowrap">Operação</span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <span
                class="pr-6 font-medium text-sm text-secondary whitespace-nowrap"
              >
                {{ entidade.operacao }}
              </span>
            </td>
          </ng-container>
          <ng-container matColumnDef="dataPedido">
            <th mat-header-cell mat-sort-header *matHeaderCellDef>
              <span class="whitespace-nowrap">Data do pedido</span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <span
                class="pr-6 font-medium text-sm text-secondary whitespace-nowrap"
              >
                {{ entidade.dataPedido | date : "shortDate" }}
              </span>
            </td>
          </ng-container>
          <ng-container matColumnDef="valorTotal">
            <th mat-header-cell mat-sort-header *matHeaderCellDef>
              <span class="whitespace-nowrap">Valor total</span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <span
                class="pr-6 font-medium text-sm text-secondary whitespace-nowrap"
              >
                {{ entidade.valorTotal | number : "0.5-5" }}
              </span>
            </td>
          </ng-container>
          <ng-container matColumnDef="status">
            <th mat-header-cell mat-sort-header *matHeaderCellDef>
              <span class="whitespace-nowrap">Status do pedido</span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <span
                class="pr-6 font-medium text-sm text-secondary whitespace-nowrap"
              >
                {{ entidade.statusDescricao }}
              </span>
            </td>
          </ng-container>
          <ng-container matColumnDef="statusDoRegistro">
            <th mat-header-cell mat-sort-header *matHeaderCellDef>
              <span class="whitespace-nowrap">Status</span>
            </th>
            <td mat-cell *matCellDef="let entidade">
              <app-status-pesquisa
                [statusDescricao]="entidade?.statusDoRegistro?.descricao"
                [status]="entidade?.statusDoRegistro?.key"
              ></app-status-pesquisa>
            </td>
          </ng-container>
          <tr mat-header-row *matHeaderRowDef="colunas; sticky: true"></tr>
          <tr
            tooltipPosition="bottom"
            class="order-row h-16"
            class="order"
            mat-row
            *matRowDef="let row; columns: colunas"
          ></tr>
        </table>
      </div>
    </div>
  </div>
  <mat-paginator
    class="sm:absolute sm:inset-x-0 sm:bottom-0 border-b sm:border-t sm:border-b-0 z-10 bg-gray-50 dark:bg-transparent"
    [ngClass]="{ 'pointer-events-none': isLoading }"
    #paginator
    [length]="resultsLength"
    [pageIndex]="0"
    [pageSize]="numeroPaginaInicial"
    [pageSizeOptions]="[5, 15, 25, 50, 75, 100, 500]"
    (page)="paginacao($event)"
    [showFirstLastButtons]="true"
  >
  </mat-paginator>
</div>

<fuse-drawer
  class="w-screen min-w-screen sm:w-100 sm:min-w-100 z-999"
  fixed
  [mode]="'over'"
  [name]="'settingsDrawer'"
  [position]="'right'"
  #settingsDrawer
>
  <div
    class="flex flex-col w-full overflow-auto bg-card"
    style="padding-top: 50px; padding-bottom: 100px"
  >
    <div
      class="flex flex-row items-center px-6 h-20 min-h-20 text-white bg-primary"
    >
      <mat-icon
        class="icon-size-7 text-current"
        [svgIcon]="'heroicons_solid:search'"
      ></mat-icon>
      <div class="ml-3 text-2xl font-semibold tracking-tight">Pesquisar</div>
      <button
        pTooltip="Fechar pesquisar {{ nomePagina }}"
        class="ml-auto"
        mat-icon-button
        (click)="settingsDrawer.close()"
        pTooltip="Fechar pesquisa {{ nomePagina }}"
      >
        <mat-icon
          class="text-current"
          [svgIcon]="'heroicons_outline:x'"
        ></mat-icon>
      </button>
    </div>
    <div class="flex flex-col p-6">
      <form class="mt-8" name="formGroup" [formGroup]="formGroup">
        <div>
          <button
            class="ml-4"
            mat-flat-button
            [color]="'primary'"
            pTooltip="Pesquisar {{ nomePagina }}"
            (click)="pesquisaBancos()"
          >
            <mat-icon [svgIcon]="'heroicons_outline:search'"></mat-icon>
          </button>
          <button
            pTooltip="Todos registros de {{ nomePagina }}"
            class="ml-4"
            mat-flat-button
            [color]="'primary'"
            (click)="limpar()"
          >
            <mat-icon [svgIcon]="'heroicons_outline:arrow-path'"></mat-icon>
          </button>
        </div>
      </form>
    </div>
  </div>
</fuse-drawer>

Quando clicar em deletar, duplicar, ativar e desativar, ele vai no backend, faz a ação correspondente.

Como fazer com que após esta ação a tabela atualiza.

Vc não postou a função que deleta, duplica, etc. Mas o que vejo é vc refazer a consulta que popula a tabela e, ao atualizar o array de itens da tabela, o componente irá atualizar automaticamente.

Uma coisa que reparei é que vc utiliza Promise, o que não é recomendado. Em vez disso, é melhor preferir usar Observable’s em conjunto com o pipe async. Isso facilita bastante na hora de obter uma atualização reativa no componente.

1 curtida

O deletar , duplicar. São idênticos. Mas cada um vai para o endpoint especifico.

async ativarDesativar(id: string, status: string): Promise<void> {
    let tipo: string = "Ativar";
    let tipoBack: string = "ATIVO";
    if (status === "INATIVAR") {
      tipo = "Inativar";
      tipoBack = "INATIVO";
    }
    const confirmation = this.fuseConfirmationServiceS.open({
      title: tipo,
      message: "Deseja " + tipo + " este registro ?",
      actions: {
        confirm: {
          label: tipo,
        },
        cancel: {
          label: "Cancelar",
        },
      },
    });
    confirmation.afterClosed().subscribe(async (result: any) => {
      if (result === "confirmed") {
        try {
          const httpReturn = await this.http
            .get(
              `${this.environmentBackend}${API}${this.urlBase}/ativar-desativar/${id}/${tipoBack}/`
            )
            .toPromise();
          this.toastrServiceS.success(
            httpReturn["texto"],
            "Sucesso",
            this.tempoTolTip
          );
          await this.pesquisaBancos();
          await this.ajusteTela();
        } catch (error: any) {
          if (error !== "undefined") {
            this.errorServiceS.error(error);
          }
        }
      }
    });
  }

Sobre Observable ’s, o projeto já está assim. Todo com Promisse.

É uma pena, mas entendo.


Se entendi direito, vi que a execução acaba caindo nessa chamada: super.pesquisar(); (dentro da função pesquisaBancos()). O que ele faz?

1 curtida

O código está na primeira página do tópico

Certo, mas a função pesquisaBancos parece que não está acessando nenhum backend, mas chama super.pesquisar();, que imagino que esteja de fato executando a consulta.

1 curtida

Realmente, ficou faltando esta parte. O super.pesquisar() é
O que acessa o backend está aqui:

import { Directive, ElementRef, ViewChild } from "@angular/core";
import { MatPaginator, PageEvent } from "@angular/material/paginator";
import { MatSort } from "@angular/material/sort";
import { MatTableDataSource } from "@angular/material/table";
import { Router } from "@angular/router";
import { merge, of as observableOf } from "rxjs";
import { catchError, map, startWith, switchMap } from "rxjs/operators";
import { NUMERO_INICIAL_PESQUISA } from "../api/erp.api";
import { StateStorageService } from "../auth/state-storage.service";
import { DefaultComponent } from "./default.component";

@Directive()
export class DefaultListarComponent extends DefaultComponent {
  isLoading: boolean = false;
  numeroPaginaInicial: number = NUMERO_INICIAL_PESQUISA;
  mostrarPesquisa: boolean;
  resultsLength: number;
  isLoadingResults: boolean;
  isRateLimitReached: boolean;
  retornoCompleto: any;
  pesquisa: any;
  lista: any[];
  dataSource: MatTableDataSource<any> = new MatTableDataSource();
  @ViewChild(MatPaginator, { static: true })
  paginator: MatPaginator;
  @ViewChild("filter", { static: true })
  filter: ElementRef;
  @ViewChild(MatSort, { static: true })
  sort: MatSort;
  entidades: any[];
  idEmpresa: string;
  paginaInicial: number = 0;
  qtdRegistros: number = 0;
  nomeEstoque: string;

  constructor(
    protected router: Router,
    protected stateStorageService: StateStorageService
  ) {
    super(router, stateStorageService);
    this.resultsLength = 0;
    this.isLoadingResults = false;
    this.isRateLimitReached = false;
    this.mostrarPesquisa = false;
  }

  async ngOnInit(): Promise<void> {
    await super.ngOnInit();
  }

  ngAfterViewInit() {
    super.ngAfterViewInit();
  }

  ngOnDestroy(): void {
    super.ngOnDestroy();
  }

  paginacao(event?: PageEvent): void {
    this.pesquisar(event?.pageIndex, event?.pageSize);
  }

  pesquisar(index = 0, length = this.numeroPaginaInicial) {
    this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0));
    merge(this.sort.sortChange, this.paginator.page)
      .pipe(
        startWith({}),
        switchMap(() => {
          this.pesquisa.direcao = this.sort.direction;
          this.pesquisa.campo = this.sort.active;
          return this.pesquisaServiceS.pesquisar(
            this.pesquisa,
            this.urlBase,
            this.environmentBackend
          );
        }),
        map((data: any) => {
          this.isLoadingResults = false;
          this.isRateLimitReached = false;
          this.resultsLength = data.body.paginacao.totalElementos;
          this.retornoCompleto = data.body;
          this.nomeEstoque = data.body.nomeEstoque;
          return data.body.lista;
        }),
        catchError((error: any) => {
          console.log("error");
          console.log(error);
          this.isLoadingResults = false;
          this.isRateLimitReached = true;
          if (error !== undefined) {
            if (
              error.error !== null &&
              error.error !== undefined &&
              error.error.texto !== undefined
            ) {
              this.errorServiceS.error(error);
            } else {
              this.errorServiceS.error({
                error: { texto: "Erro em pesquisar um registro !" },
              });
            }
          }
          return observableOf([]);
        })
      )
      .subscribe((data: any) => {
        let contador = 1;
        data.forEach((element: any) => {
          element.contador = contador++;
        });
        this.entidades = data;
        this.dataSource.data = data;
        this.mostrarPesquisa = true;
      });
  }
}

No metodo pesquisar., nesta parte:

return this.pesquisaServiceS.pesquisar(
this.pesquisa,
this.urlBase,
this.environmentBackend
);

Que é this.pesquisaServiceS.pesquisar

import { HttpClient, HttpParams, HttpResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { API } from "app/core/api/erp.api";
import { Observable } from "rxjs";
import { createRequestOption } from "./request-util";

@Injectable({
  providedIn: "root",
})
export class PesquisaService {
  constructor(private http: HttpClient) {}

  pesquisar(
    pesquisa: any,
    url: string,
    environment: string
  ): Observable<HttpResponse<any>> {
    const params: HttpParams = createRequestOption(pesquisa);
    return this.http.get<any>(environment + API + url + "/pesquisar", {
      params,
      observe: "response",
    });
  }
}

Então assim chama o backend.

Fiz isto e funcionou. Mas ainda não vou marcar como resolvido

async ativarDesativar(
    id: string,
    status: string,
    mesmaPagina: boolean = false
  ): Promise<void> {
    let tipo: string = "Ativar";
    let tipoBack: string = "ATIVO";
    if (status === "INATIVAR") {
      tipo = "Inativar";
      tipoBack = "INATIVO";
    }
    const confirmation = this.fuseConfirmationServiceS.open({
      title: tipo,
      message: "Deseja " + tipo + " este registro ?",
      actions: {
        confirm: {
          label: tipo,
        },
        cancel: {
          label: "Cancelar",
        },
      },
    });
    confirmation.afterClosed().subscribe(async (result: any) => {
      if (result === "confirmed") {
        try {
          const httpReturn = await this.http
            .get(
              `${this.environmentBackend}${API}${this.urlBase}/ativar-desativar/${id}/${tipoBack}/`
            )
            .toPromise();
          this.toastrServiceS.success(
            httpReturn["texto"],
            "Sucesso",
            this.tempoTolTip
          );
          if (mesmaPagina) {
            this.router
              .navigateByUrl("/", { skipLocationChange: true })
              .then(() => {
                this.router.navigate([this.rota]);
              });
          } else {
            this.router.navigate([this.rota]);
          }
        } catch (error: any) {
          if (error !== "undefined") {
            this.errorServiceS.error(error);
          }
        }
      }
    });
  }

Este parte:

this.router
.navigateByUrl(“/”, { skipLocationChange: true })
.then(() => {
this.router.navigate([this.rota]);
});

Vc podia fazer um teste sem o changeDetection: ChangeDetectionStrategy.OnPush, para ver se funciona a atualização sem o refresh.

1 curtida