<Iframe> com pdf fica piscando a cada clique na tela

<h1 matDialogTitle>Impressão da requisição</h1>
<div mat-dialog-content>
  <iframe
    width="100%"
    height="570px"
    [src]="domSanitizer.bypassSecurityTrustResourceUrl(relatorio)"
  ></iframe>
</div>
<div class="buttons-div">
  <button
    matTooltip="Fechar"
    mat-mini-fab
    type="button"
    color="primary"
    mat-card-icon
    (click)="dialogRef.close(false)"
  >
    <mat-icon>transit_enterexit</mat-icon>
  </button>
</div>

código ts

import { HttpClient } from '@angular/common/http';
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { DomSanitizer } from '@angular/platform-browser';
import { FuseConfirmDialogComponent } from '@fuse/components/confirm-dialog/confirm-dialog.component';
import { API } from 'app/core/api/erp.api';
import { ErrorService } from 'app/core/service/error.service';
import { environment } from 'environments/environment';
@Component({
  selector: 'app-imprimir-requisicao',
  templateUrl: './imprimir-requisicao.component.html',
})
export class ImprimirRequisicaoComponent {
  public confirmMessage: string;
  relatorio: any;
  id: number;
  constructor(
    public domSanitizer: DomSanitizer,
    private http: HttpClient,
    private errorServiceS: ErrorService,
    public dialogRef: MatDialogRef<FuseConfirmDialogComponent>,
    @Inject(MAT_DIALOG_DATA) data: any
  ) {
    this.id = data.id;
  }
  async ngOnInit(): Promise<void> {
    await this.imprimir(this.id);
  }
  private async imprimir(id: number): Promise<void> {
    let httpReturn: any;
    try {
      httpReturn = await this.http
        .get(environment.RELATORIO + API + 'requisicao-compra/' + id + '/')
        .toPromise();
      this.relatorio = 'data:' + httpReturn['contentType'] + ';base64,';
      this.relatorio = this.relatorio + httpReturn['arquivo'];
    } catch (error: any) {
      if (error !== 'undefined') {
        this.errorServiceS.error(
          'Erro em gerar relatório de requisição de compras !'
        );
      }
    }
  }
}

Está abrindo, corretamente.

Só que fica piscando a cada clique na tela

O que pode ser ?

Assim nao vai piscar https://www.w3schools.com/code/tryit.asp?filename=GOGMBG8EQZSE

1 curtida

Mudei para ficar assim o html.

<div mat-dialog-content>
  <embed
    width="100%"
    height="570px"
    type="{{ contentType }}"
    [src]="domSanitizer.bypassSecurityTrustResourceUrl(relatorio)"
  />
</div>

Mas continuou piscando.

Acho que o problema é nesta parte: [src]="domSanitizer.bypassSecurityTrustResourceUrl(relatorio)"

Claro, pois nao ta igual ao exemplo que passei.

Ao invés de

[src]="domSanitizer.bypassSecurityTrustResourceUrl(relatorio)"

Coloque

src="diretamente o endereço do endpoint que retorne o binario do pdf no backend"

Caso for necessário passar parâmetros coloque direto nessa url.

1 curtida

Quando coloco assim:

  <embed
    width="100%"
    height="570px"
    type="application/pdf"
    src="http://localhost:8600/modulo-relatorio-api/api/cotacao/{{ id }}/"
  />

ou assim:

<embed
    width="100%"
    height="570px"
    type="application/pdf"
    src="{{ relatorio }}"
  />

Este segundo no ngOnInit, monta a variável relatorio

async ngOnInit(): Promise<void> {
    this.relatorio = environment.RELATORIO + API + 'cotacao/' + this.id + '/';
}

Dá este no console do nagegador

core.js:4610 ERROR Error: unsafe value used in a resource URL context (see http://g.co/ng/security#xss)
    at ɵɵsanitizeResourceUrl (core.js:5539)
    at elementPropertyInternal (core.js:9099)
    at Module.ɵɵpropertyInterpolate1 (core.js:15873)
    at ImprimirCotacaoComponent_Template (imprimir-cotacao.component.html:7)
    at executeTemplate (core.js:8689)
    at refreshView (core.js:8558)
    at refreshComponent (core.js:9711)
    at refreshChildComponents (core.js:8355)
    at refreshView (core.js:8608)
    at refreshEmbeddedViews (core.js:9665)

backend, retornando o byte

controller

package br.com.ghnetsoft.comprasfood.relatorio.resource;

import static br.com.ghnetsoft.principal.enuns.TipoMensagemEnum.ERROR;
import static org.springframework.http.HttpStatus.OK;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import br.com.ghnetsoft.comprasfood.relatorio.service.CotacaoService;
import br.com.ghnetsoft.principal.exception.GeralException;
import br.com.ghnetsoft.principal.resource.PrincipalResource;
import io.swagger.annotations.ApiOperation;

@RestController
@RequestMapping("/api/cotacao")
public class CotacaoResource extends PrincipalResource {

	private static final long serialVersionUID = 3370601170855459651L;

	@Autowired
	private CotacaoService service;

	@ApiOperation("Imprime uma cotação pelo id")
	@GetMapping("{id}")
	public ResponseEntity<?> buscarPeloId(@PathVariable Long id) {
		try {
			return ResponseEntity.status(OK).body(service.imprimir(id));
		} catch (GeralException e) {
			return erroExceptionComRegra(e, "cotacao");
		} catch (Exception e) {
			return excecaoGeralSalvar(e, ERROR, "cotacao", "cotação");
		}
	}
}

service

package br.com.ghnetsoft.comprasfood.relatorio.service;

import static br.com.ghnetsoft.principal.util.DataUtil.DD_MM_YYYY;
import static br.com.ghnetsoft.principal.util.DataUtil.converterLocalDateParaString;
import static br.com.ghnetsoft.principal.util.DataUtil.converterLocalDateTimeJava;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;

import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import br.com.ghnetsoft.comprasfood.model.cotacao.Cotacao;
import br.com.ghnetsoft.comprasfood.model.cotacaoitem.CotacaoItem;
import br.com.ghnetsoft.comprasfood.relatorio.dto.CotacaoItemDTO;
import br.com.ghnetsoft.comprasfood.repository.cotacao.CotacaoRepository;
import br.com.ghnetsoft.comprasfood.repository.cotacaoitem.CotacaoItemRepository;
import br.com.ghnetsoft.principal.dto.ArquivoDTO;
import br.com.ghnetsoft.principal.exception.GeralException;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

@Service
public class CotacaoService {

	@Autowired
	private CotacaoRepository repository;
	@Autowired
	private CotacaoItemRepository cotacaoItemRepository;
	@Value("${url.angular}")
	private String urlAngular;
	private BigDecimal total;

	public byte[] imprimir(Long id) {
		try {
			Optional<Cotacao> cotacaoExiste = repository.findById(id);
			if (cotacaoExiste.isPresent()) {
				total = new BigDecimal("0");
				JRDataSource dataSource = new JRBeanCollectionDataSource(inserirLista(cotacaoExiste));
				Map<String, Object> parametros = new HashedMap<String, Object>();
				parametros.put("loja", cotacaoExiste.get().getLoja().getNome());
				parametros.put("numero", cotacaoExiste.get().getNumero());
				parametros.put("dataValidade", converterLocalDateParaString(
						converterLocalDateTimeJava(cotacaoExiste.get().getDataValidade()), DD_MM_YYYY));
				parametros.put("status", cotacaoExiste.get().getStatus().getDescricao());
				parametros.put("observacao", cotacaoExiste.get().getObservacao());
				parametros.put("total", total);
				parametros.put("aceitaMarcaSimilar", cotacaoExiste.get().getAceitaMarcaSimilar().getDescricao());
				parametros.put("imgParametro", urlAngular + "assets/images/");
				return JasperRunManager.runReportToPdf(
						this.getClass().getClassLoader().getResourceAsStream("relatorio/cotacao.jasper"), parametros,
						dataSource);
			} else {
				throw new GeralException("Não existe relatório com este registro !");
			}
		} catch (JRException e) {
			e.printStackTrace();
			throw new GeralException("Erro ao gerar relatório de Cotação !");
		}
	}

	private Collection<CotacaoItemDTO> inserirLista(Optional<Cotacao> requisicaoExiste) {
		Collection<CotacaoItemDTO> itens = new ArrayList<>();
		for (CotacaoItem item : cotacaoItemRepository.buscarItensPelaCotacao(requisicaoExiste.get().getId())) {
			itens.add(CotacaoItemDTO.builder().marca(item.getMarca()).insumo(item.getInsumo().getNome())
					.unidade(item.getUnidade().getNome()).quantidade(item.getQuantidade())
					.quantidadeEstoque(item.getQuantidadeEstoque()).ultimoCusto(item.getUltimoCusto()).build());
			total = total.add(item.getTotal());
		}
		return itens;
	}
}

O que pode ser ?

Outra forma que fiz, meio que funcionou foi assim:

ngOnInit(): void {
    this.service.imprimir(this.id).subscribe((response: any) => {
      let file = new Blob([response], { type: 'application/pdf' });
      var fileURL = URL.createObjectURL(file);
      window.open(fileURL);
      this.relatorio = fileURL;
    });
  }
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { API } from 'app/core/api/erp.api';
import { environment } from 'environments/environment';
@Injectable({
  providedIn: 'root',
})
export class CotacoesServiceService {
  constructor(private http: HttpClient) {}
  imprimir(id: number) {
    const url = environment.RELATORIO + API + 'cotacao/' + id + '/';
    const httpOptions = {
      responseType: 'arraybuffer' as 'json',
    };
    return this.http.get<any>(url, httpOptions);
  }
}

Gerou esta URL blob:http://localhost:4200/2ccdd4fe-26c3-424b-93ae-e9de9b2e931a, mas abriu em outra aba o relatório.

Como fazer para esta window abrir este relatório na mesma página ?

Dessa forma nao sei como ajudar. Sempre trabalhei daquela forma que passei, que é bem mais fácil.

Se chamar a url montada direto no browser o pdf vem?