{"id":3199,"date":"2024-04-17T22:26:01","date_gmt":"2024-04-17T20:26:01","guid":{"rendered":"https:\/\/nguenkam.com\/blog\/?p=3199"},"modified":"2024-04-17T22:43:13","modified_gmt":"2024-04-17T20:43:13","slug":"angular-17-3-new-features-output-api-outputfromobservable-typescript-5-4","status":"publish","type":"post","link":"https:\/\/nguenkam.com\/blog\/index.php\/2024\/04\/17\/angular-17-3-new-features-output-api-outputfromobservable-typescript-5-4\/","title":{"rendered":"[Angular 17.3] &#8211; new features: output() API, outputFromObservable(), Typescript 5.4 &#8230;"},"content":{"rendered":"\n<p>Let us list out the most important changes and new features in the minor versions Angular 17.3<\/p>\n\n\n\n<h4>New&nbsp;<code>output()<\/code>&nbsp;API<\/h4>\n\n\n\n<p>Angular 17.3 introduced the new&nbsp;<code>output()<\/code>&nbsp;API, for emitting output from a component. This API is designed to complement the&nbsp;<code>input()<\/code>&nbsp;and&nbsp;<code>model()<\/code>&nbsp;APIs, and it&#8217;s type safe.<\/p>\n\n\n\n<p><em>Official docs:&nbsp;<a href=\"https:\/\/next.angular.io\/api\/core\/output\">output<\/a><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Component({\n  selector: 'app-output',\n  standalone: true,\n  template: `\n    &lt;button (click)=\"onClick.emit()\"&gt;Button&lt;\/button&gt;\n    &lt;input #in type=\"text\" (keyup)=\"onChange.emit(in.value)\" \/&gt;\n  `,\n})\nexport class OutputComponent {\n  onClick = output();          \/\/ ? OutputEmitterRef&lt;void&gt;\n  onChange = output&lt;string&gt;(); \/\/ ? OutputEmitterRef&lt;string&gt;\n}\n\n@Component({\n  selector: 'app-output-wrapper',\n  standalone: true,\n  imports: &#91;OutputComponent],\n  template: ` &lt;app-output (onClick)=\"log('onClick')\" (onChange)=\"log('onChange', $event)\" \/&gt; `,\n})\nexport class OutputWrapperComponent {\n  log(t1: string, t2: string = '') { console.log(t1, t2); }\n}\n\n\/\/ after you click on the button, then type 'test' into the input field, \n\/\/ the messages on the console are:\n\/\/ onClick \n\/\/ onChange t\n\/\/ onChange te\n\/\/ onChange tes\n\/\/ onChange test<\/code><\/pre>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4><code>outputFromObservable()<\/code>&nbsp;helper functions<\/h4>\n\n\n\n<p>In addition the new&nbsp;<code>output()<\/code>&nbsp;API, Angular 17.3 also contains the&nbsp;<code>outputFromObservable()<\/code>&nbsp;helper function for transforming an observable to a component&#8217;s&nbsp;<code>output()<\/code>.<\/p>\n\n\n\n<p><em>Official docs:&nbsp;<a href=\"https:\/\/next.angular.io\/api\/core\/rxjs-interop\/outputFromObservable\">outputFromObservable<\/a>,<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Component({\n  selector: 'app-output2',\n  standalone: true,\n  template: `&lt;button (click)=\"onClick$.next('click2')\"&gt;Button&lt;\/button&gt;`,\n})\nexport class Output2Component {\n  onClick$ = new BehaviorSubject(''); \/\/ ? BehaviorSubject&lt;string&gt;\n  onClick = outputFromObservable(this.onClick$); \/\/ ? OutputRef&lt;string&gt;\n}\n\n@Component({\n  selector: 'app-output-wrapper2',\n  standalone: true,\n  imports: &#91;Output2Component],\n  template: `&lt;app-output2 (onClick)=\"log('onClick', $event)\" \/&gt;`,\n})\nexport class OutputWrapper2Component {\n  log(t1: string, t2: string = '') { console.log(t1, t2); }\n}\n\n\/\/ after you click on the button, the message on the console is:\n\/\/ onClick click2<\/code><\/pre>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4><code>outputToObservable()<\/code>&nbsp;helper functions<\/h4>\n\n\n\n<p>There is also a new&nbsp;<code>outputToObservable()<\/code>&nbsp;helper function for converting a component&#8217;s output to an observable.<\/p>\n\n\n\n<p><em>Official docs:&nbsp;<a href=\"https:\/\/next.angular.io\/api\/core\/rxjs-interop\/outputToObservable\">outputToObservable<\/a><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Component({\n  selector: 'app-output3',\n  standalone: true,\n  template: `&lt;button (click)=\"onClick.emit()\"&gt;Button&lt;\/button&gt;`,\n})\nexport class Output3Component {\n  onClick = output(); \/\/ ? OutputEmitterRef&lt;void&gt;\n}\n\n@Component({\n  selector: 'app-output-wrapper3',\n  standalone: true,\n  imports: &#91;Output3Component],\n  template: `&lt;app-output3\/&gt;`, \/\/ ? no (onClick)=\"...\" here!\n})\nexport class OutputWrapper3Component implements OnInit {\n  childComponent = viewChild(Output3Component);\n  destroyRef = inject(DestroyRef);\n\n  ngOnInit(): void {\n    const childComponent = this.childComponent();\n    if (childComponent) {\n      const onClick$ = outputToObservable(childComponent.onClick) \/\/ ? \n        .pipe(takeUntilDestroyed(this.destroyRef));\n      onClick$.subscribe(() =&gt; console.log('onClick'));\n    }\n  }\n}\n\n\/\/ after you click on the button, the message on the console is:\n\/\/ onClick<\/code><\/pre>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h4>Typescript 5.4 support<\/h4>\n\n\n\n<p><a href=\"https:\/\/twitter.com\/drosenwasser\">Daniel Rosenwasser<\/a>&nbsp;highlighted the most interesting new features of Typescript 5.4 in his&nbsp;<a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-4\/\">announcement<\/a>:<\/p>\n\n\n\n<ul><li>Preserved Narrowing in Closures Following Last Assignments<\/li><li>The&nbsp;<code>NoInfer<\/code>&nbsp;Utility Type<\/li><li><code>Object.groupBy<\/code>&nbsp;and&nbsp;<code>Map.groupBy<\/code><\/li><li>Support for&nbsp;<code>require()<\/code>&nbsp;calls in&nbsp;<code>--moduleResolution bundler<\/code>&nbsp;and&nbsp;<code>--module preserve<\/code><\/li><li>Checked Import Attributes and Assertions<\/li><li>Quick Fix for Adding Missing Parameters<\/li><li>Auto-Import Support for Subpath Imports<\/li><\/ul>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h5>Reference:<\/h5>\n\n\n\n<p><a href=\"https:\/\/www.angularaddicts.com\/\">https:\/\/www.angularaddicts.com\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let us list out the most important changes and new features in the minor versions Angular 17.3 New&nbsp;output()&nbsp;API Angular 17.3 introduced the new&nbsp;output()&nbsp;API, for emitting output from a component. This API is designed to complement the&nbsp;input()&nbsp;and&nbsp;model()&nbsp;APIs, and it&#8217;s type safe. Official docs:&nbsp;output outputFromObservable()&nbsp;helper functions In addition the new&nbsp;output()&nbsp;API, Angular 17.3 also contains the&nbsp;outputFromObservable()&nbsp;helper function for [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3201,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[37,83],"tags":[835,836,837,807],"_links":{"self":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3199"}],"collection":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=3199"}],"version-history":[{"count":2,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3199\/revisions"}],"predecessor-version":[{"id":3202,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/3199\/revisions\/3202"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media\/3201"}],"wp:attachment":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=3199"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=3199"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=3199"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}