Output(): новая функция в Angular 17.3
Angular v17.3 намекает, что декораторы скоро уйдут в прошлое. На этот раз в добавок к ранее введенным input() и model() была добавлена функция output().
import { output } from '@angular/core';
@Component({
selector: 'app-foo',
template: '',
standalone: true,
})
class FooComponent {
page = output<number>();
// Or use an alias
page = output<number>({ alias: 'currentPage' });
}Далее, как и с обычным output остается прочитать полученное значение
import { output } from '@angular/core';
@Component({
selector: 'app-main',
template: '<app-foo (page)="doSomething($event)">',
standalone: true,
})
class AppComponent {
doSomething(data) { сonsole.log(data) }
}Отклоняясь от EventEmitter, который расширяет класс Subject из RxJS, функция output возвращает OutputEmitterRef, у которого есть только два открытых метода — subscribe и emit. Этот функционал позволяет заменить EventEmitter любым другим наблюдаемым объектом внутри нашего декоратора Output.
Создание Output из Observable
Для поддержки совместимости с существующими рабочими процессами Angular вводит функцию outputFromObservable. Эта функция позволяет прокидывать вверх по дереву компонентов значения из Observalbe.
import { outputFromObservable } from '@angular/core';
@Component({
selector: 'app-foo',
template: '',
standalone: true,
})
class FooComponent {
form = new FormGroup({ ... })
value = outputFromObservable(this.form.valueChanges);
// You can also use an alias
value = outputFromObservable(this.form.valueChanges, { alias: 'valueChange' });
}
Эта функция может принимать как Subject и EventEmitter. Изучим её реализацию:
export function outputFromObservable<T>(
observable: Observable<T>, opts?: OutputOptions): OutputRef<T> {
return new OutputFromObservableRef<T>(observable);
}class OutputFromObservableRef<T> implements OutputRef<T> {
private destroyed = false;
destroyRef = inject(DestroyRef);
constructor(private source: Observable<T>) {}
subscribe(callbackFn: (value: T) => void): OutputRefSubscription {
const subscription = this.source.pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe({
next: value => callbackFn(value),
});
return {
unsubscribe: () => subscription.unsubscribe(),
};
}
}Класс OutputFromObservableRef принимает наблюдаемый объект и реализует метод subscribe класса OutputRef. При вызове этого метода он подписывается на предоставленный Observable и передает отправленные значения в коллбек. Более того, он обеспечивает очистку при уничтожении связанного компонента или директивы.
Преобразование Output в Observable
Так же у нас есть возможность использовать outputToObservable, который преобразует выходные данные в Observable:
import { output, outputToObservable } from '@angular/core';
@Component({
selector: 'app-foo',
template: '',
standalone: true,
})
class FooComponent {
page = output<number>();
page$ = outputToObservable(this.page);
}function outputToObservable<T>(ref: OutputRef<T>): Observable<T> {
const destroyRef = ɵgetOutputDestroyRef(ref);
return new Observable<T>(observer => {
destroyRef?.onDestroy(() => observer.complete());
const subscription = ref.subscribe(v => observer.next(v));
return () => subscription.unsubscribe();
});
}Это вольный перевод материала