ngFor над объектом, заполненным из обещания в Angular 2

Я анализирую zip-файл с изображениями, на которые я хочу ссылаться с помощью blobURL в объекте filesFromZip, и перебираю его с помощью ngFor, чтобы отобразить изображения на странице.

Это выглядит так

filesFromZip = {};
let zip = new JSZip();

zip.loadAsync(zipfileFromInput)
  .then(function (zip) {
    for (let file in zip.files) {

    let fileInZip = zip.files[file];

    zip.file(fileInZip.name)
      .async("arraybuffer")
      .then(function (content) {
        let buffer = new Uint8Array(content);
        let blob = new Blob([buffer.buffer]);

        // here is where I want to push this object into the filesFromZip object somehow....
        return {
          fileName: fileInZip.name,
          blobURL: URL.createObjectURL(blob)
        };
    });
   }
  });

в шаблоне:

<md-card *ngFor="let file of filesFromZip">
  <h3 md-line>{{file.fileName}}</h3>
  <img src="{{file.blobURL}}">
</md-card>

Как я могу получить данные из промиса на filesFromZip?

Я пытался просто вставить его в filesFromZip, но это дает мне эту ошибку:

error_handler.js: 47 ИСКЛЮЧЕНИЕ: неперехвачено (в обещании): TypeError: невозможно прочитать свойство «асинхронное» с нулевым значением

Я действительно борюсь с асинхронностью и Angular 2. Кто-нибудь, кто может направить меня в правильном направлении?


person mottosson    schedule 18.10.2016    source источник


Ответы (1)


Во-первых, вы не можете перебирать простой объект с помощью директивы *ngFor, поэтому filesFromZip должен быть массивом.

this.filesFromZip = [];
zip.loadAsync(zipfileFromInput)
  .then((zip)=> {
    for (let file in zip.files) {
      let fileInZip = zip.files[file];
      zip.file(fileInZip.name)
        .async("arraybuffer")
        .then((content)=> {
          let buffer = new Uint8Array(content);
          let blob = new Blob([buffer.buffer]);
          // here is where I want to push this object into the filesFromZip object somehow....
          this.filesFromZip.push({
            fileName: fileInZip.name,
            blobURL: URL.createObjectURL(blob)
          });
      });
   }
  });

или вы можете использовать Promise.all(), который создаст обещание из итерации Promise, а затем использует асинхронный канал:

javascript:

this.filesFromZip = Promise.all(
  zip.loadAsync(zipfileFromInput)
    .then((zip)=> {
      let out=[];
      for (let file in zip.files) {
        let fileInZip = zip.files[file];
        out.push(zip.file(fileInZip.name)
          .async("arraybuffer")
          .then((content)=> {
            let buffer = new Uint8Array(content);
            let blob = new Blob([buffer.buffer]);
            // here is where I want to push this object into the filesFromZip object somehow....
            this.filesFromZip.push({
              fileName: fileInZip.name,
              blobURL: URL.createObjectURL(blob)
            });
        }));
    }
    return out;
    });
)

шаблон:

<md-card *ngFor="let file of filesFromZip|async">
  <h3 md-line>{{file.fileName}}</h3>
  <img src="{{file.blobURL}}">
</md-card>

Однако ваша главная проблема заключается в том, что zip.file(fileInZip.name) возвращает null

person n00dl3    schedule 19.10.2016
comment
Чтобы использовать асинхронный канал, разве filesFromZip не должен возвращать обещание, а не то, что я сейчас пытаюсь вернуть объект? - person mottosson; 19.10.2016
comment
Просто новый пустой объект, в который я пытался вставить результат из промиса - person mottosson; 19.10.2016
comment
Вы имеете в виду этот результат: return { fileName: fileInZip.name, blobURL: URL.createObjectURL(blob) };? Потому что, поскольку это возвращается обещанием, оно станет обещанием... - person n00dl3; 19.10.2016
comment
Да, я пытался протолкнуть этот объект для каждого файла в filesFromZip вместо того, чтобы возвращать его, но это выдало ошибку. Но теперь возвращенный объект живет только в промисе, и я не знаю, как его получить в filesFromZip - person mottosson; 19.10.2016
comment
Откуда взялась эта переменная filesFromZip !!!??? Пожалуйста, отредактируйте свой вопрос со всей необходимой информацией... - person n00dl3; 19.10.2016
comment
Кажется, мы приближаемся к разгадке. Но я получаю сообщение об ошибке: Error:(36, 39) TS2345:Argument of type 'Promise<JSZip>' is not assignable to parameter of type '({} | PromiseLike<{}>)[]'. Property 'length' is missing in type 'Promise<JSZip>'. Я не могу поместить zip.LoadAsync... в Promise.all(... - person mottosson; 19.10.2016