Lecture-4 - #76
Conversation
| @@ -0,0 +1,13 @@ | |||
| <!-- <div class="popup"> --> | |||
There was a problem hiding this comment.
Возникла проблема, и какого-то адекватного решения не нашел. Я добавил стили для отобрадения popup в центре. Первое что я сделал, это обернул ng-container в <div class="popup">, но в таком случае при отсутствии содержимого шаблона выводится пустой элемент со стилем (получается пустая светлая точка в центре экрана). Потом решил попробовать сделать контейнер в шаблоне в котором уже будет <div class="popup">, но с данным вариантом тоже не получилось, и как-то он странно выглядит в любом случае. Как надо было поступить в таком случае?
There was a problem hiding this comment.
Ты шел в правильном направлении, стоит продолжить идею с div оберткой - #76 (comment)
There was a problem hiding this comment.
Рабочего результата я добился.
Но не уверен что все красиво получилось.
Первый вопрос, я получается должен был добавить в .less .hide { display: none; } ?
И правильно ли я понимаю, если я вызову из AppComponent this.popupHost.popupTemplate = this.templateTwo;, то ngOnChanges не отработает в PopupHostComponent?
И насколько корректно мое решение с _popupTemplate?
There was a problem hiding this comment.
Работа в компоненте PopupHostComponent выстроена корректно за исключением пары нюансов:
- Я бы не стал делать сеттер, раз тебе нужно хранить свойство полученное в инпуте, рекомендовал бы в таком случаи
popupTemplateсделать обычным свойством, а изменения отслеживать черезOnChangesхук.
Тот подход, что ты использовал с сеттером и_popupTemplateсвойством, тоже подходит и сторонников такого подхода не мало. Но в таком случаи смущает момент: свойство с_обычно используется для нейминга приватных свойств, а в твоем случае данное свойство публично, если поправить нейминг, то будет все супер. - По поводу
closePopupметода. Сейчас компонент управляется за счет инпут свойства(передали значениеTemplateRef- отображаем, передалиundefined- скрываем), то есть то, что отображать - диктует родительский компонент.
При закрытии попапа через методclosePopupнарушается архитектура описанная выше, т.к. дочерний компонент начинает сам управлять своим отображением и при этом нарушает консистентность своего состояния: Angular по прежнему считает, что в инпуте хранится значение отображаемого шаблона, а тем временем внутреннее свойство имеет значение undefined(Подобный кейс с рассинхронизацией мы рассматривали на 3 лекции, если не ошибаюсь, когда создавали sidenav компонент). По этому, если ты хочешь реализовать закрытие изPopupHostComponentпо той архитектуре, что сейчас есть, то нужно создатьOutput, который будет сообщать родителю о необходимости закрыть popup, соответсвенно и вся логика будет реализовываться у родителя.
There was a problem hiding this comment.
Ответы на твои вопросы:
-
получается должен был добавить в .less .hide { display: none; } ?
Да, все верно
-
если я вызову из AppComponent this.popupHost.popupTemplate = this.templateTwo;, то ngOnChanges не отработает в PopupHostComponent?
Да, тут тоже все верно, ngOnChanges отрабатывает только при изменении свойства через механизм CD, а у тебя оно меняется через JS.
В целом, не очень хорошая практика так менять Input свойства, потому что это идет в обход механизма CD и флоу общения компонентов в парадигме Angular. Попробуй изменить этот момент - убрать любое обращение к PopupHostComponent из класса AppComponent и выстроить всю работсу через Input и Output.
P.S. К popupTemplate инпуту можно привязать свойство из AppComponent, назовем его, например, popupTemplate. Значение свойства popupTemplate в AppComponent можно будет изменять как угодно и значение будет передано в инпут по флоу Angular: <app-popup-host [popupTemplate]="popupTemplate"></app-popup-host>; closePopup метод в AppComponent в таком случае будет выглядить так closePopup() { this.popupTemplate = undefined; }
|
Привет! |
Letto228
left a comment
There was a problem hiding this comment.
Добавил еще пару комментариев, которые заметил, для проведения полноценного ревью - буду ждать обновления МР
| private popupContainer!: ViewContainerRef; | ||
|
|
||
| @Input() set popupTemplate(popupTemplate: TemplateRef<unknown>) { | ||
| this.popupContainer?.clear(); |
There was a problem hiding this comment.
Для this.popupContainer optional chaining не нужен, т.к. контейнер статичен на странице
| @ViewChild('popupContainer', { read: ViewContainerRef, static: true }) | ||
| private popupContainer!: ViewContainerRef; | ||
|
|
||
| @Input() set popupTemplate(popupTemplate: TemplateRef<unknown>) { |
There was a problem hiding this comment.
В popupTemplate может еще придти и undefined, давай обработаем этот кейс
There was a problem hiding this comment.
Добавил проверку, в случае undefined не создаю EmbeddedView. Или как лучше обработать такой случай?
There was a problem hiding this comment.
Огонь, все по феншую, только давай еще в типизации отобразим, что может придти undefined
Letto228
left a comment
There was a problem hiding this comment.
Отписался по твоим правкам в комментариях, посмотри пожалуйста. Постарался все максимально подробно изложить, но если все таки что то будет не ясно, то обязательно напиши в Дискорде - договоримся о созвоне и на нем все разложим по полочкам
| @@ -0,0 +1,13 @@ | |||
| <!-- <div class="popup"> --> | |||
There was a problem hiding this comment.
Работа в компоненте PopupHostComponent выстроена корректно за исключением пары нюансов:
- Я бы не стал делать сеттер, раз тебе нужно хранить свойство полученное в инпуте, рекомендовал бы в таком случаи
popupTemplateсделать обычным свойством, а изменения отслеживать черезOnChangesхук.
Тот подход, что ты использовал с сеттером и_popupTemplateсвойством, тоже подходит и сторонников такого подхода не мало. Но в таком случаи смущает момент: свойство с_обычно используется для нейминга приватных свойств, а в твоем случае данное свойство публично, если поправить нейминг, то будет все супер. - По поводу
closePopupметода. Сейчас компонент управляется за счет инпут свойства(передали значениеTemplateRef- отображаем, передалиundefined- скрываем), то есть то, что отображать - диктует родительский компонент.
При закрытии попапа через методclosePopupнарушается архитектура описанная выше, т.к. дочерний компонент начинает сам управлять своим отображением и при этом нарушает консистентность своего состояния: Angular по прежнему считает, что в инпуте хранится значение отображаемого шаблона, а тем временем внутреннее свойство имеет значение undefined(Подобный кейс с рассинхронизацией мы рассматривали на 3 лекции, если не ошибаюсь, когда создавали sidenav компонент). По этому, если ты хочешь реализовать закрытие изPopupHostComponentпо той архитектуре, что сейчас есть, то нужно создатьOutput, который будет сообщать родителю о необходимости закрыть popup, соответсвенно и вся логика будет реализовываться у родителя.
| @@ -0,0 +1,13 @@ | |||
| <!-- <div class="popup"> --> | |||
There was a problem hiding this comment.
Ответы на твои вопросы:
-
получается должен был добавить в .less .hide { display: none; } ?
Да, все верно
-
если я вызову из AppComponent this.popupHost.popupTemplate = this.templateTwo;, то ngOnChanges не отработает в PopupHostComponent?
Да, тут тоже все верно, ngOnChanges отрабатывает только при изменении свойства через механизм CD, а у тебя оно меняется через JS.
В целом, не очень хорошая практика так менять Input свойства, потому что это идет в обход механизма CD и флоу общения компонентов в парадигме Angular. Попробуй изменить этот момент - убрать любое обращение к PopupHostComponent из класса AppComponent и выстроить всю работсу через Input и Output.
P.S. К popupTemplate инпуту можно привязать свойство из AppComponent, назовем его, например, popupTemplate. Значение свойства popupTemplate в AppComponent можно будет изменять как угодно и значение будет передано в инпут по флоу Angular: <app-popup-host [popupTemplate]="popupTemplate"></app-popup-host>; closePopup метод в AppComponent в таком случае будет выглядить так closePopup() { this.popupTemplate = undefined; }
| private popupContainer!: ViewContainerRef; | ||
|
|
||
| @Input() set popupTemplate(popupTemplate: TemplateRef<unknown>) { | ||
| this.popupContainer?.clear(); |
| @ViewChild('popupContainer', { read: ViewContainerRef, static: true }) | ||
| private popupContainer!: ViewContainerRef; | ||
|
|
||
| @Input() set popupTemplate(popupTemplate: TemplateRef<unknown>) { |
There was a problem hiding this comment.
Огонь, все по феншую, только давай еще в типизации отобразим, что может придти undefined

No description provided.