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(); }); }
Это вольный перевод материала