Когда вызывать функцию, которая вычисляет ширину элементов?

В моем угловом проекте у меня есть две таблицы. В одну из таблиц загружаются данные из сервиса, и на ngOnInit эти данные возвращаются.

Я рассчитываю ширину столбцов заголовка и применяю ее к другой таблице. И я вызываю функцию this.resizeColumn():

  ngAfterViewInit() {
this.resizeColumns();    
 }

А также на:

 @HostListener('window:resize')
 onResize() {   
this.resizeColumns();
}

Проблема в том, что когда страница открывается в первый раз, рассчитанная ширина еще не применяется. Как только я изменяю размер окна, два заголовка совпадают. Идея состоит в том, что всякий раз, когда изменяется ширина таблицы, эта функция также вызывается. После какого события или хука жизненного цикла я должен вызвать resizeColumn, чтобы изначально обе таблицы имели одинаковую ширину столбца?


person Community    schedule 10.12.2017    source источник
comment
Хотя мне это не кажется дубликатом, взгляните на этот вопрос и комментарии к принятому ответу stackoverflow.com/questions/47729202/   -  person Hugo Noro    schedule 10.12.2017
comment
Спасибо . Я прочитал это и просто попробовал тот же код, что и в принятом ответе. Но это не решает мою проблему. Потому что, как только я изменяю размер окна, заголовок таблицы получает значения. Я пытался реализовать что-то вроде этого: ссылка Но, как видите, скрипка не есть эта проблема, потому что у него есть JS. Я не знаю, как сделать то же самое в angular, чтобы, как только программа запускается, она принимала эти ширины.   -  person    schedule 10.12.2017
comment
В таком случае попробуем разобраться в проблеме. Итак, когда вы открываете страницу, в коде ширина уже рассчитана правильно, но затем не применяется или она недоступна, пока вы не измените размер?   -  person Hugo Noro    schedule 10.12.2017
comment
Большое вам спасибо! Ширина есть, но проблема в том, что когда я обновляю страницу (или открываю ее в первый раз), таблица сначала пуста, а затем заполняется. Таким образом, заголовок получает ту же ширину, что и таблица в начале. Теперь, после заполнения таблицы, ширина исходного столбца явно изменилась. Но эти изменения не применяются к целевому заголовку, пока я не изменю размер окна. Есть ли способ прослушать изменение размера таблицы для вызова функции? Чтобы всякий раз, когда исходная таблица меняет ширину, вызывалась вычисляющая функция?   -  person    schedule 10.12.2017


Ответы (1)


Вы можете воспользоваться привязкой свойств, чтобы связать ширину столбцов двух таблиц, как показано в этот плункер. В моем примере ширина столбцов в верхней таблице увеличивается через равные промежутки времени, а ширина столбцов в нижней таблице соответствует привязке свойств.

<table>
  <tr #table1Row>
    <td>Column 1</td>
    <td>Column 2</td>
    <td>Column 3</td>
  <tr>
</table>

<table>
  <tr>
    <td [style.width.px]="getColWidth(table1Row, 0)">Column 1</td>
    <td [style.width.px]="getColWidth(table1Row, 1)">Column 2</td>
    <td [style.width.px]="getColWidth(table1Row, 2)">Column 3</td>
  <tr>
</table>
// Get the column width from Table 1
public getColWidth(row: HTMLTableRowElement, index: number): number {
  return row.cells[index].offsetWidth;
}


Обновление:

Если вам нужно сделать изменение асинхронным (чтобы избежать исключения Angular), вы можете попробовать следующий код (реализованный в этот плунжер). Он вызывает setTimeout, чтобы получить новую ширину после текущего цикла выполнения.

private colWidths: Array<number> = [ 0, 0, 0 ];

public getColWidth(row: HTMLTableRowElement, index: number): number {
  let width = row.cells[index].offsetWidth;
  if (Math.abs(this.colWidths[index] - width) > 0.001) {
    setTimeout(() => {
      this.colWidths[index] = width;
    }, 0);
  }
  return this.colWidths[index];
}
person ConnorsFan    schedule 10.12.2017
comment
Но я меняю ширину столбцов с привязкой свойств. Проблема в том, что исходный заголовок столбца получает ширину в зависимости от содержимого. И когда вы впервые запускаете приложение, в таблице на долю секунды нет данных (целевой столбец получает ширину столбца исходных столбцов), а затем таблица получает данные, исходные столбцы расширяются по ширине. Целевой столбец остается прежним. Я пытаюсь понять, как заставить целевые столбцы изменять свою ширину всякий раз, когда изменяются исходные столбцы таблицы. Я также использую @ViewChildren, чтобы получить собственный элемент. - person ; 10.12.2017
comment
Я изменил свою функцию на это ранее: link И я не знаете, как внести изменения в таблицу, чтобы запустить вычисления и получить ширину. - person ; 10.12.2017
comment
В моем примере ширина в Таблице 2 связана с фактической шириной в Таблице 1 (измеренной с помощью offsetWidth). Если ширина в таблице 1 изменится, чтобы адаптироваться к их содержимому, ширина в таблице 2 изменится с помощью привязки свойств. Я адаптировал мой плункер, чтобы показать результат изменения содержимого в таблице 1. Обратите внимание что с этой привязкой свойства вам не нужно отслеживать событие и вам не нужно знать, когда изменяется ширина в первой таблице. Механизм обнаружения угловых изменений позаботится об этом за вас. - person ConnorsFan; 10.12.2017
comment
Большое спасибо!!!! Но мне трудно кое-что понять: Итак, вы используете getColWidth(index:number), чтобы получить ширину столбца таблицы? И затем вы привязываете это к столбцу в своей таблице, используя привязку свойств? this.row.cells[index].offsetWidth, откуда эта строка знает, какую ширину брать? или это this.row, строки, возвращаемые функцией get row()? Итак, что мне нужно сделать, это получить строки с помощью ViewChildren, и у меня будет их ширина в offsetWidth? Прошу прощения, просто хочу убедиться, что правильно понял. - person ; 10.12.2017
comment
Я упростил свой ответ и мой планкер, передав переменную ссылки на таблицу непосредственно в getColWidth() в шаблонная разметка. Примечание: ссылочная переменная шаблона table1Row также используется с @ViewChild() в коде планкера, но только для увеличения размера столбца в примере. Вам не нужно было бы делать это в вашем коде. - person ConnorsFan; 10.12.2017
comment
Спасибо, но у меня все та же проблема, за исключением того, что теперь, когда я изменяю размер таблицы, мне нужно щелкнуть в любом месте, чтобы другие столбцы получили свою ширину. Он не меняется динамически по мере изменения одного. :| - person ; 11.12.2017
comment
Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '90'. Current value: '85'. Всякий раз, когда изменяется размер таблицы - person ; 11.12.2017
comment
Трудно понять, что происходит, не видя кода. Можете ли вы положить его в плунжер? Даже если он не запускается и не компилируется, я могу проверить его, чтобы получить более полное представление. - person ConnorsFan; 11.12.2017
comment
Да ссылка У меня есть раскрывающийся список, который фильтрует таблицу. И когда я нажимаю на фильтр в реальной программе, таблица становится меньше по ширине. Фильтры тоже ставить? И он показывает ошибку, что Expression Has изменился после его проверки. - person ; 11.12.2017
comment
В вашем плункере в одной таблице есть два раздела заголовков. И привязка свойства находится между этими двумя заголовками. Ваша разметка действительно такая? Ваш первоначальный вопрос касался одинаковой ширины столбцов в двух таблицах. - person ConnorsFan; 11.12.2017
comment
Нет. Я обновлю его, извините. У меня есть две таблицы. В одной таблице есть только заголовок (который должен получить ширину), а в другой таблице есть данные и обычный заголовок. Ждать. - person ; 11.12.2017
comment
ссылка Я обновил ее здесь. Это фактический код. Я ошибся, когда копировал. - person ; 11.12.2017
comment
Должен быть способ решить упомянутую выше ошибку, но это не так просто. Это вызвано тем, что исходная таблица находится ниже той, которую вы хотите адаптировать. Просто ради отладки вы можете поменять местами две таблицы в своей разметке и посмотреть, работает ли код. - person ConnorsFan; 11.12.2017
comment
Я сделал это, и у меня все еще есть та же ошибка при фильтрации. Это потому, что он получает ширину столбцов. И затем, когда я фильтрую, как я уже сказал, ширина изменяется (потому что некоторые столбцы становятся меньше). И тогда я снова получаю сообщение об ошибке, говоря, что выражение изменилось после его проверки. Я думал, что привязка свойств будет означать, что всякий раз, когда изменяется исходный столбец, цель также будет меняться, потому что angular обнаруживает изменения. Но теперь выдает ошибку. - person ; 11.12.2017
comment
Хм. Нелегко. :-) Можешь закинуть код фильтрации в плункер? - person ConnorsFan; 11.12.2017
comment
Можете ли вы проголосовать за вопрос, чтобы у меня было достаточно репутации, чтобы перенести его в чат? И я могу объяснить код подробно? Или вы хотите, чтобы я написал трубу, которая фильтрует его и все в плункере? :) Я тоже так могу. - person ; 11.12.2017
comment
Я уже проголосовал за вопрос. :-) В плункер можно положить все полезное. Обратите внимание, что я буду немного занят в ближайшие 2 часа, но я буду периодически возвращаться сюда. - person ConnorsFan; 11.12.2017
comment
ссылка я добавил канал только как комментарий, так как код все равно не компилируется . Но дело в том, что когда у меня есть все цвета: у меня может быть красный, зеленый, синий ... и ширина этого столбца основана на самом большом тексте. Итак, если я фильтрую по красному. Тогда в этом столбце будет отображаться только красный цвет, поэтому его ширина будет меньше. Теперь вот где я получаю ошибку. Потому что когда я фильтрую и меняется ширина столбца, ошибка в консоли говорит, что Expression изменился после его проверки. Предыдущее значение 100 пикселей, текущее значение 88 пикселей. - person ; 11.12.2017
comment
Я добавил вариант кода в свой ответ, чтобы асинхронно получить новую ширину столбца (см. этот планкер ). Это может решить исключение, которое вы получаете от Angular. Массив prevWidths должен содержать как минимум столько элементов, сколько столбцов в ваших таблицах. - person ConnorsFan; 11.12.2017
comment
Еще одна вещь: в моем плункере я установил заполнение ячеек равным нулю. Если padding-left и/или padding-right не равны нулю, ширина столбцов не будет точно совпадать, потому что offsetWidth включает заполнение, а style.width — нет. Если вы хотите сохранить заполнение, вы должны внести поправку в getColWidth. - person ConnorsFan; 11.12.2017
comment
Спасибо . Это действительно решило проблему с ошибками, но даже несмотря на то, что его тайм-аут равен 0, по какой-то причине изменения применяются медленно. Но это определенно помогло, и я отмечу это как правильное :) !! Большое спасибо! - person ; 12.12.2017