Приветствую всех желающих накапливать информацию о тонкостях работы фреймворка Angular.
Сегодня посчитал нужным лучше изучить информацию, касающуюся организации взаимодействия между компонентами Angular и начать практиковать переводы интересующих меня статей с английского.
Надеюсь найдутся те, для кого перевод статьи с Medium будет полезен.
Давно имея желание начать переводить полезные статьи с английского, решил начать с простенькой, весьма не объемной, но возможно, дополняющей имеющиеся знания статейки. К Вашему вниманию, господа…
Для тех, кто новенький в изучении Angular, декораторы Input и Output могут вызывать смущение, особенно, когда Вы пытаетесь разобраться в их назначении с помощью примеров кода. В этой статье, я попытаюсь объяснить их максимально простым способом.
Инструмент для обмена данными
В первую очередь, задача декораторов Input и Output состоит в обмене данными между компонентами. Они являются механизмом для получения/отправки данных от одного компонента к другому.
Input используется для получения данных, в то время как Output для их отправки. Output отправляет данные выставляя их в качестве производителей событий, обычно как объекты класса EventEmitter.
Таким образом, когда Вы видите код, на подобии этого:
@Component({
  selector: 'todo-item',
  ...
})
export class TodoItemComponent {
  @Input()  item
  @Output() onChange = new EventEmitter()
}
он значит:
- Эй, я ожидаю отправленные мне данные. Я получу их и сохраню в качестве значения свойства item.
 
- Кстати, я буду причиной отправки данных с помощью свойства onChange.
 
Давайте представим что у Вас есть компонент TodoList, который содержит компонент TodoItem.
В шаблоне компонентаTodoList Вы ожидаете увидеть:
...
<todo-item
  [item]="myTask"
  (onChange)="handleChange($event)"
</todo-item>
...что значит:
-  Компонент TodoList помещает значение данных в принадлежащее ему свойство myTask и передает его компоненту TodoItem
 
-  Данные, переданные с компонента TodoItem, будут получены и обработаны функцией handleChange() компонента TodoList 
 
Хватит теории. Давайте посмотрим на пример.
@Input и Output в действии.
Обратите внимание на пример.
Здесь я создал 2 компонента, компонент hello, вложенный в компонент app. Компонент hello имеет Input и Output:
hello.component.ts
@Component({
  selector: 'hello',
  template: `
    <h3 (click)="onClick.emit('Neo')">
       ...
    </h3>
  `
})
export class HelloComponent  {
  @Input() myFriend: string
  @Output() onClick = new EventEmitter()
}
Компонент hello ожидает получить значение типа «строка» и поместить его в качестве значения свойства myFriend.
@Input() myFriend: string
Каждый раз, когда Вы кликните на него, свойство отправки данных onClick декоратора Output передаст «внешнему миру» строку с содержанием «Neo».
<h3 (click)="onClick.emit('Neo')">
Ниже расположен код компонента app:
app.component.ts
export class AppComponent  {
  ng = 'Angular'
  myName = 'Neo'
  upCase(st:string): void { ... }
}
app.component.html
<hello myFriend="{{ ng }}" (onClick)="upCase($event)"></hello>
<h3>My name is {{ myName }}</h3>
Обратите внимание что компонент app использует тег компонента hello в своем шаблоне, который совершает 2 действия:
- передает значение строки 'Angular' компоненту hello с помощью свойства ng
 
- и получает отправленное значение от компонента hello и обрабатывает полученное значение с помощью функции upCase():
 
<hello myFriend="{{ ng }}" (onClick)="upCase($event)">
Вы можете увидеть приложение в действии здесь.
Комментарии (14)
 - Kanut28.08.2019 18:11- Присоединюсь к предыдущему оратору. Думал здесь что-то интересное будет: особенности, отличия от стандартного/ожидаемого поведения, подводные камни. 
 
 Но перевод банального и не особо интересного туториала? Дамс… - kussch Автор28.08.2019 22:08- Благодарен за мнение. Напишите статью с указанными Вами нюансами и поделитесь. Будет здорово.  - c_kotik29.08.2019 08:29- Так этого ждали от вас. Я вот тоже думал — статья будет чуть более, чем банальной.  - kussch Автор29.08.2019 21:54- Извините, но я не использовал рендер для привлечения Вашего внимания. Ищите — найдете не банальщину на данную тему. Я был лишь одним из пунктов вашего длительного плавания в поиске прекрасной земли под названием «Небанальщина». 
 
  - Kanut29.08.2019 08:49- Пока я ещё нахожусь в той стадии знания Angular когда логичнее искать ньюнасы чем ими делиться :) 
 
 Но по теме статьи могу например написать что для меня в своё время было полезно понять что объекты в «banana in the box» передаются по указателю и если меняешь только состояние объекта, то в такой ситуации сам объект через Output возвращать не надо. Из обычных мануалов/туториалов это было ну вообще не понятно. Но не думаю что ради этого стоит писать целую статью на хабре :) - serf29.08.2019 12:05- Я вас наверно удивлю, но передача объекта по ссылке это обычное поведение в JS, здесь ведь нет встроенной иммутабельности. Если выполняется сериализация, то это уже часть логики приложения.  - Kanut29.08.2019 12:08- Абсолютно не удивите. Но на тот момент я не знал как конкретно ведёт себя data binding или ngModel в Ангуляре и поэтому везде ставил Output как это было в мануалах/туториалах :)  - Vahman29.08.2019 14:17+1- output надо ставить для того, чтобы оповестить родительский объект о том, что что-то произошло. EventEmitter названием как бы намекает на это. Дело в том, что изменив состояние, не изменяя ссылку, не имея обработчика на output и при стратегии onchange ваш родительский компонент никогда не узнает, что ему надо проверить свое состояние м перерендериться.  - Kanut29.08.2019 14:30- Это опять же зависит от того как сделан этот самый родительский объект. Если там всё работает с подходящим датабайндингом, то он и «рендериться» будет автоматом. Но это опять же всё зависит от конкретной имплемемнтации и у каждого есть свои предпочетения как он хочет это делать. 
 
 Я скорее о том что я поначалу просто не знал о существовании альтернативы и абсолютно всё делал через Output и эмиттеры. И мне бы в своё время сильно помогло если бы в моих первых мануалах/туториалах это было описано подробнее.
 
 
 
 
  - serf29.08.2019 12:12- Нюансы. Ну например такой нюанс что организацию обмена данными между компонентами можно делать и без input/output, например через центральный стор (ngrx/redux подобные поделки). Ведь input/output часто не самый удобный вариант, например когда нужно перекидывать данные между компонентом верхнего уровня и сидящим глубоко в иерархии или между «глубокими сидящими» компонентами в разных ветвях иерархии. Ну и разумеется иммутабельный центральный стор довольно удобно использовать c «onPush» компонентами.  - Vahman29.08.2019 14:18- Да можно просто через сервис даже устроить обмен, благо внедрять зависимости можно и на уровне компонент  - serf29.08.2019 14:23- Для шаринга данных и сервисы и шину событий прикрутить можно и еще что-то придумать. Но в больших приложениях хочется использовать единый и стандартный подход. Кроме этого часто цель не только в шаринге данных между частями системы используя единый стор, но также сериализация и обратная операция состояния приложений. 
 
 
 
 
 
           
 
Vahman
То есть на медиуме кто-то написал то что есть в доках и в любой обучалке для начинающих, а потом для этого шедевра на Хабре вышел перевод. Приплыли
kussch Автор
Да, вы все правильно поняли. Хорошо что есть еще в этой жизни вещи, которые могут вас удивить. Но в то же время странно, ведь это не первый случай перевода статьи с медиума, увы. У вас есть публикации в профиле, которые мне интересны и я обязательно ознакомлюсь. В заключение: не у каждого найдется желание перевести статью. Я буду очень рад если найдутся люди для которых она будет полезна. Успехов.