web-dev-qa-db-fra.com

Angular 4.3: Obtenir un tampon de matrice avec le nouveau HttpClient

Je voudrais changer pour le nouveau HttpClient. Jusqu'à présent, je gère les téléchargements de fichiers suivants:

getXlsx (): Observable<any> {
    return this.http.get('api/xlsx', {
      responseType: ResponseContentType.ArrayBuffer, // set as ArrayBuffer instead of Json
    })
    .map(res => downloadFile(res, 'application/xlsx', 'export.xlsx'))
    .catch(err => handleError(err));
  }

export function downloadFile(data: any, type: string, filename: string): string {
  const blob = new Blob([data._body], { type });
  const url = window.URL.createObjectURL(blob);

  // create hidden dom element (so it works in all browsers)
  const a = document.createElement('a');
  a.setAttribute('style', 'display:none;');
  document.body.appendChild(a);

  // create file, attach to hidden element and open hidden element
  a.href = url;
  a.download = filename;
  a.click();
  return url;
}

Changer le respondeType en 'arraybuffer' aura pour résultat des fichiers vides. Des idées comment le résoudre?

3
Luke

Alors Martin a résolu mon problème:

getXlsx (): Observable<any> {
    return this.http.get('api/xlsx', {
      responseType: 'blob' // <-- changed to blob
    })
    .map(res => downloadFile(res, 'application/xlsx', 'export.xlsx'))
    .catch(err => handleError(err));
  }

export function downloadFile(blob: any, type: string, filename: string): string {
  const url = window.URL.createObjectURL(blob); // <-- work with blob directly

  // create hidden dom element (so it works in all browsers)
  const a = document.createElement('a');
  a.setAttribute('style', 'display:none;');
  document.body.appendChild(a);

  // create file, attach to hidden element and open hidden element
  a.href = url;
  a.download = filename;
  a.click();
  return url;
}
7
Luke

Ce qui précède fonctionne et constitue une solution acceptable. Cependant, cela ressemble à une odeur de code ajoutant simplement des balises d'ancrage au DOM et simulant un clic lorsque vous pouvez le faire d'une manière beaucoup plus propre. Nous avons récemment eu un problème similaire concernant le téléchargement de documents en général à partir d’un site Web Angular 5 dans lequel nous avons utilisé FileSaver ( https://www.npmjs.com/package/file-saver ).

En ajoutant FileSaver en utilisant npm install file-saver et en effectuant les importations pertinentes, vous pouvez utiliser le code suivant pour télécharger un fichier: 

getDocument(document: Document) {
    let headers = new HttpHeaders(); // additional headers in here

    return this._http.get(url, {
        headers: headers,
        responseType: "blob" // this line being the important part from the previous answer (thanks for that BTW Martin) 
    }).map(
        res => {
            var x = res;
            if (res) {
                let filename = documentName;
                saveAs(x, filename);
            }
            return true;
        },
        err => {
            return true;
        }
    );
} 

Ceci utilise la commande native saveAs si elle existe et implémente une autre logique pour répliquer la fonctionnalité si ce n'est pas le cas. 

Cela peut faire la même chose sous le capot (je ne sais pas vraiment car je n’ai pas eu le changement à regarder), mais cela le compartimentalise dans un paquet tiers facile à utiliser que j’espère pouvoir conserver (doigts croisés) sans avoir à mettre à jour les fonctionnalités pour prendre en charge les versions les plus récentes de différents packages/navigateurs. 

1
chunkydigits