Skip to content

Lecture-4 - #76

Open
AK20001701 wants to merge 6 commits into
Letto228:lecture-4from
AK20001701:lecture-4
Open

Lecture-4#76
AK20001701 wants to merge 6 commits into
Letto228:lecture-4from
AK20001701:lecture-4

Conversation

@AK20001701

Copy link
Copy Markdown

No description provided.

@@ -0,0 +1,13 @@
<!-- <div class="popup"> -->

@AK20001701 AK20001701 Jan 7, 2023

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Возникла проблема, и какого-то адекватного решения не нашел. Я добавил стили для отобрадения popup в центре. Первое что я сделал, это обернул ng-container в <div class="popup">, но в таком случае при отсутствии содержимого шаблона выводится пустой элемент со стилем (получается пустая светлая точка в центре экрана). Потом решил попробовать сделать контейнер в шаблоне в котором уже будет <div class="popup">, но с данным вариантом тоже не получилось, и как-то он странно выглядит в любом случае. Как надо было поступить в таком случае?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ты шел в правильном направлении, стоит продолжить идею с div оберткой - #76 (comment)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Рабочего результата я добился.
Но не уверен что все красиво получилось.
Первый вопрос, я получается должен был добавить в .less .hide { display: none; } ?
И правильно ли я понимаю, если я вызову из AppComponent this.popupHost.popupTemplate = this.templateTwo;, то ngOnChanges не отработает в PopupHostComponent?

И насколько корректно мое решение с _popupTemplate?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Работа в компоненте PopupHostComponent выстроена корректно за исключением пары нюансов:

  1. Я бы не стал делать сеттер, раз тебе нужно хранить свойство полученное в инпуте, рекомендовал бы в таком случаи popupTemplate сделать обычным свойством, а изменения отслеживать через OnChanges хук.
    Тот подход, что ты использовал с сеттером и _popupTemplate свойством, тоже подходит и сторонников такого подхода не мало. Но в таком случаи смущает момент: свойство с _ обычно используется для нейминга приватных свойств, а в твоем случае данное свойство публично, если поправить нейминг, то будет все супер.
  2. По поводу closePopup метода. Сейчас компонент управляется за счет инпут свойства(передали значение TemplateRef - отображаем, передали undefined - скрываем), то есть то, что отображать - диктует родительский компонент.
    При закрытии попапа через метод closePopup нарушается архитектура описанная выше, т.к. дочерний компонент начинает сам управлять своим отображением и при этом нарушает консистентность своего состояния: Angular по прежнему считает, что в инпуте хранится значение отображаемого шаблона, а тем временем внутреннее свойство имеет значение undefined(Подобный кейс с рассинхронизацией мы рассматривали на 3 лекции, если не ошибаюсь, когда создавали sidenav компонент). По этому, если ты хочешь реализовать закрытие из PopupHostComponent по той архитектуре, что сейчас есть, то нужно создать Output, который будет сообщать родителю о необходимости закрыть popup, соответсвенно и вся логика будет реализовываться у родителя.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ответы на твои вопросы:

  1. получается должен был добавить в .less .hide { display: none; } ?

Да, все верно

  1. если я вызову из 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

Copy link
Copy Markdown
Owner

Привет!
Давай подброшу идею: <div class="popup"> можно скрыть при отсутсвии template(template === undefined).
Реализовать скрытие можно при помощи классов и стилей - [class.hide] или при помощи структурной директивы ngIf

@Letto228 Letto228 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавил еще пару комментариев, которые заметил, для проведения полноценного ревью - буду ждать обновления МР

private popupContainer!: ViewContainerRef;

@Input() set popupTemplate(popupTemplate: TemplateRef<unknown>) {
this.popupContainer?.clear();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Для this.popupContainer optional chaining не нужен, т.к. контейнер статичен на странице

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Убрал

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У меня optional chaining все еще отображается 🤔
Снимок экрана 2023-01-15 в 20 15 53

@ViewChild('popupContainer', { read: ViewContainerRef, static: true })
private popupContainer!: ViewContainerRef;

@Input() set popupTemplate(popupTemplate: TemplateRef<unknown>) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В popupTemplate может еще придти и undefined, давай обработаем этот кейс

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавил проверку, в случае undefined не создаю EmbeddedView. Или как лучше обработать такой случай?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Огонь, все по феншую, только давай еще в типизации отобразим, что может придти undefined

@Letto228 Letto228 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отписался по твоим правкам в комментариях, посмотри пожалуйста. Постарался все максимально подробно изложить, но если все таки что то будет не ясно, то обязательно напиши в Дискорде - договоримся о созвоне и на нем все разложим по полочкам

@@ -0,0 +1,13 @@
<!-- <div class="popup"> -->

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Работа в компоненте PopupHostComponent выстроена корректно за исключением пары нюансов:

  1. Я бы не стал делать сеттер, раз тебе нужно хранить свойство полученное в инпуте, рекомендовал бы в таком случаи popupTemplate сделать обычным свойством, а изменения отслеживать через OnChanges хук.
    Тот подход, что ты использовал с сеттером и _popupTemplate свойством, тоже подходит и сторонников такого подхода не мало. Но в таком случаи смущает момент: свойство с _ обычно используется для нейминга приватных свойств, а в твоем случае данное свойство публично, если поправить нейминг, то будет все супер.
  2. По поводу closePopup метода. Сейчас компонент управляется за счет инпут свойства(передали значение TemplateRef - отображаем, передали undefined - скрываем), то есть то, что отображать - диктует родительский компонент.
    При закрытии попапа через метод closePopup нарушается архитектура описанная выше, т.к. дочерний компонент начинает сам управлять своим отображением и при этом нарушает консистентность своего состояния: Angular по прежнему считает, что в инпуте хранится значение отображаемого шаблона, а тем временем внутреннее свойство имеет значение undefined(Подобный кейс с рассинхронизацией мы рассматривали на 3 лекции, если не ошибаюсь, когда создавали sidenav компонент). По этому, если ты хочешь реализовать закрытие из PopupHostComponent по той архитектуре, что сейчас есть, то нужно создать Output, который будет сообщать родителю о необходимости закрыть popup, соответсвенно и вся логика будет реализовываться у родителя.

@@ -0,0 +1,13 @@
<!-- <div class="popup"> -->

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ответы на твои вопросы:

  1. получается должен был добавить в .less .hide { display: none; } ?

Да, все верно

  1. если я вызову из 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();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У меня optional chaining все еще отображается 🤔
Снимок экрана 2023-01-15 в 20 15 53

@ViewChild('popupContainer', { read: ViewContainerRef, static: true })
private popupContainer!: ViewContainerRef;

@Input() set popupTemplate(popupTemplate: TemplateRef<unknown>) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Огонь, все по феншую, только давай еще в типизации отобразим, что может придти undefined

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants