Манипулирование неотрисованными элементами DOM для экспорта в Angular - PullRequest
0 голосов
/ 13 апреля 2020

Я создал сервис Angular для экспорта SVGElement для пользователя. Проще говоря, он создает SVG и добавляет символы к <defs>. Затем служба возвращает этот SVG компоненту с помощью Promise, а компонент копирует его в буфер обмена или экспортирует в виде файла.

Моя проблема в том, что экспортированный элемент SVG пуст в момент, когда компонент пытается его экспортировать. Если я вставлю setTimeout() вокруг resolve(svgElement) в сервисе, он будет работать.

Как я могу манипулировать этими динамически генерируемыми элементами DOM более синхронно? SVG никогда не будет отображаться для пользователя.

Вот несколько упрощенных кодов, чтобы попытаться проиллюстрировать функциональность.

\\ service.ts
public exportToSVG(ids: string[]): Promise<SVGElement> {
   return new Promise((resolve, reject) => {
      const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
      const defs = document.createElement('defs');

      ids.forEach(async id => {
         // use another method to get the symbol associated with the id
         const symbol = await this._getSymbolByString(id);
         defs.appendChild(symbol);
      });

      svg.appendChild(defs);
      resolve(svg);
   });
}

\\ component.ts
public copyToClipboard(ids: string[]) {
   this.myService.exportToSVG(ids).then(svg => {
      // this only copies `<svg><defs></defs></svg>`, unless a setTimeout is used
      this.clipboardService.copyFromContent(svg.outerHTML);
   });
}

Ответы [ 3 ]

0 голосов
/ 13 апреля 2020

Angular имеет асинхронный характер. Когда вы применяете Foreach l oop, angular, не ожидайте ответа и выполняйте следующую операцию, поэтому вы не можете получить переменную defs. Вы должны поместить этот код в состояние, которое срабатывает после завершения foreach l oop.

\\ service.ts
public exportToSVG(ids: string[]): Promise<SVGElement> {
   return new Promise((resolve, reject) => {
      const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
      const defs = document.createElement('defs');
      let lengthIds = is.length;
      let count = 0;

      ids.forEach(async id => {
         // use another method to get the symbol associated with the id
         const symbol = await this._getSymbolByString(id);
         defs.appendChild(symbol);
         count++;
      });
  
    // check length of total number of elements in array and its count
      if(count === lengthIds){
        svg.appendChild(defs);
        resolve(svg);
      }
     
   });
}

\\ component.ts
public copyToClipboard(ids: string[]) {
   this.myService.exportToSVG(ids).then(svg => {
      // this only copies `<svg><defs></defs></svg>`, unless a setTimeout is used
      this.clipboardService.copyFromContent(svg.outerHTML);
   });
}

Так что я думаю, что это сработает для вас.

0 голосов
/ 13 апреля 2020

Я решил это, связав Обещания, не используя asyn c ... await.

0 голосов
/ 13 апреля 2020

Попробуйте использовать внутренний HTML вместо:

\\ component.ts
public copyToClipboard(ids: string[]) {
   this.myService.exportToSVG(ids).then(svg => {
      this.clipboardService.copyFromContent(svg.innerHTML);
   });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...