получить свойства ширины ElementRef.nativeElement из компонента после внедрения данных - PullRequest
0 голосов
/ 10 мая 2018

У меня есть компонент, предоставленный внешней библиотекой Angular, которая является частным проектом с открытым исходным кодом для компании, в которой я работаю. Компонент имеет свое содержимое, внедренное в него из Observable, и эти данные недоступны при первоначальной визуализации. Рассматриваемый компонент - это ячейка таблицы данных, часть большой таблицы данных, очень похожая на таблицу данных Material .

Одна из этих ячеек имеет длинную строку, которая, в зависимости от данных, возвращаемых из API, может переполниться из контейнера. В этом случае мне нужно укоротить строку, выделив середину и заменив ее на «...». Строка представляет собой путь к файлу, например, «C: \ Действительно \ действительно \ действительно \ действительно \ действительно \ длинный \ путь \ к \ file.txt». Скажем, переполнение было скрыто в разделе '\ path \ to \ file.txt', я бы хотел, чтобы середина была вырезана примерно так: 'C: \ Действительно \ действительно ... \ long \ path \ to \ file.txt' , Это похоже на то, как macOS обрабатывает длинные пути к файлам в Finder. Я могу сделать это нормально, используя трубу, однако я не уверен, как получить ширину компонента. Я пытался использовать ViewChild, как это:

@ViewChild('path') public path: ElementRef;

Однако, когда я смотрю на свойства измерения в path.nativeElement объекте, все они равны 0 - например:

scrollHeight: 0
scrollLeft: 0
scrollTop: 0
scrollWidth: 0

Я думаю, это потому, что данные загружаются в таблицу после загрузки. Я попытался просмотреть переменную path в ngAfterViewInit, и она получает правильный компонент, но атрибуты innerHTML, text, content все пусты. Как бы получить самую последнюю версию этой переменной?

В качестве альтернативы, если у вас есть какие-либо другие предложения о том, как мне этого добиться, это было бы замечательно. Спасибо.

РЕДАКТИРОВАТЬ: Некоторые обновления. Теперь у меня есть два варианта: я могу использовать Pipe в HTML и отправить путь ElementRef в pipe, например:

<div #path>{{ value | truncate: path }}</div>

И код трубы выглядит так:

@Pipe({ name: 'truncate' })
export class TruncatePipe implements PipeTransform {

  public transform(value: string, element: any): string {
    const { scrollWidth, clientWidth } = element;
    // computation to figure out what the value of the new string should be
    return value;
  }

}

Элемент имеет необрезанное значение, но scrollWidth и clientWidth равны, что неверно, если значение слишком длинное для контейнера (поэтому оно переполняется); scrollWidth должен быть длиннее clientWidth. Это означает, что я не могу вычислить, сколько символов должно быть усечено, так как канал не знает, как далеко он переполняется. Я думаю, что причина того, что эти две переменные имеют одно и то же значение, заключается в том, что данные еще не были внедрены, поэтому элемент (div, то есть элемент block) принимает ширину своего контейнера. Если я проверяю элемент после, я вижу, что scrollWidth больше, чем clientWidth.

Другой способ, которым я пытался, - это использовать прокси-функцию в моем классе компонентов, которая затем возвращает значение из канала, например:

public truncatePath(value: string, element: any) {
  return new TruncatePipe().transform(value, element);
}

и HTML:

<div #path>{{ truncatePath(value, path) }}</div>

Это работает (clientWidth и scrollWidth различаются), но многократно запускает функцию, что, очевидно, снижает производительность приложения.

РЕДАКТИРОВАТЬ 2: если я добавлю код канала в setTimeout, clientWidth будет правильным значением, и строка будет усечена, однако, поскольку она находится в setTimeout, она не отображает эту строку.

1 Ответ

0 голосов
/ 11 мая 2018

Я нашел ответ на это, используя Трубу.Вот мой код:

@Pipe({ name: 'truncate' })
export class TruncatePipe implements PipeTransform {

  public transform(value: string, element: any): Observable<string> {
    return new Observable<string>((observer: Observer<string>) => {
      setTimeout(() => {
        const { scrollWidth, clientWidth } = element;
        if (scrollWidth > clientWidth) {
          const avgCharWidth = Math.floor(scrollWidth / value.length);
          const middleOfString = Math.floor(value.length / 2);
          const numberToRemove = Math.ceil((scrollWidth - clientWidth) / avgCharWidth) + 1;
          const parts = [
            value.slice(0, middleOfString - (numberToRemove / 2)),
            '&#8230;',
            value.slice(middleOfString + (numberToRemove / 2))
          ];
          observer.next(parts.join(''));
        }
      });
      observer.next(value);
    });
  }

}

И HTML:

<div #path [innerHTML]="value | truncate:path | async"></div>

Некоторые примечания:

  • Канал возвращает значение за пределами setTimeout, иначе элемент не был обработан один раз и поэтому не имеет атрибутов DOMЗатем он запускается снова и проверяет, что начальное значение не переполняется, и, если это происходит, вычисляет новую строку с '...' в середине.Это означает, что канал запускается дважды для каждого значения, что может стоить довольно дорого с сотнями строк, но я не вижу другого способа сделать это прямо сейчас.
  • AsyncPipe отображает последнее значениеиз наблюдаемой
  • Он должен находиться внутри setTimeout, чтобы его рендеринг выполнялся в отдельном процессе

Результаты:

  • Исходная строка: C: \ Действительно \ действительно \ действительно \ действительно \ длинный \ путь \ к \ file1.txt (контейнер переполнения)
  • Усеченная строка: C: \ действительно \ действительно \ реальный ... длинный \ путь \ к \ file1.txt
  • Процесс: труба запускается один раз, и возвращается исходное значение.Затем запускается код setTimeout, который находит, что исходная строка переполняется, и вычисляет новую строку.Асинхронный канал обновляет значение при рендеринге.

-

  • Исходная строка: C: \ path \ to \ file1.txt (вписывается в контейнер)
  • Усеченная строка: C: \путь \ к \ file1.txt
  • Процесс: труба запускается один раз, возвращает исходное значение.Код setTimeout запускается, находит, что исходная строка строки не переполняется и поэтому не идет дальше.

Мне было бы очень интересно узнать, есть ли другие способы улучшить это, чтобыТруба не должна запускаться дважды, и способ удаления setTimeout также был бы фантастическим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...