{"id":2443,"date":"2025-10-10T11:10:39","date_gmt":"2025-10-10T11:10:39","guid":{"rendered":"https:\/\/www.cmarix.com\/qanda\/?p=2443"},"modified":"2026-02-05T11:58:54","modified_gmt":"2026-02-05T11:58:54","slug":"angular-two-way-binding-input-output-before-model","status":"publish","type":"post","link":"https:\/\/www.cmarix.com\/qanda\/angular-two-way-binding-input-output-before-model\/","title":{"rendered":"How Angular Managed Two-Way Binding with @Input() &amp; @Output() Before model()"},"content":{"rendered":"\n<p>In the traditional Angular approach, creating two-way binding meant setting up both an @Input() to receive data and an @Output() to emit changes. You also needed to wire up event emitters manually. This pattern worked, but it added boilerplate and split the logic for incoming and outgoing data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What model() Signal Does Differently<\/h2>\n\n\n\n<p>Introduced in Angular v17, the model() signal replaces the old binding setup with a single, writable signal. This signal acts both as an input and an output. When the parent updates the bound property, the signal gets updated. When the child sets a new value, that change automatically reflects back in the parent.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Comparing Old vs. New in a Real Example<\/h3>\n\n\n\n<p><strong>Old Way Using <\/strong><strong>@Input()<\/strong><strong> and <\/strong><strong>@Output()<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Component({\n selector: 'app-custom-input-old',\n template: `&lt;input &#91;value]=\"value\" (input)=\"onValueChange($event)\">`\n})\nexport class CustomInputOldComponent {\n @Input() value: string = '';\n @Output() valueChange = new EventEmitter&lt;string>();\n\n onValueChange(event: Event) {\n   const target = event.target as HTMLInputElement;\n   this.valueChange.emit(target.value);\n }\n}<\/code><\/pre>\n\n\n\n<p><strong>Usage:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;app-custom-input-old &#91;(value)]=\"parentProperty\">&lt;\/app-custom-input-old><\/code><\/pre>\n\n\n\n<p><strong>New Way Using model()<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Component({\n selector: 'app-custom-input-new',\n standalone: true,\n template: `&lt;input &#91;value]=\"value()\" (input)=\"onValueChange($event)\">`\n})\nexport class CustomInputNewComponent {\n value = model.required&lt;string>();\n\n onValueChange(event: Event) {\n   const target = event.target as HTMLInputElement;\n   this.value.set(target.value);\n }\n}<\/code><\/pre>\n\n\n\n<p><strong>Usage:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;app-custom-input-new &#91;(value)]=\"parentProperty\">&lt;\/app-custom-input-new><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Why model() Improves Component Design<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Less Code, Fewer Mistakes<br><\/strong>You define the binding in one place. No need for extra decorators or emitters.<\/li>\n\n\n\n<li><strong>Cleaner State Management<br><\/strong>The writable signal makes it clear where state comes from and where it goes.<\/li>\n\n\n\n<li><strong>Reactive by Nature<br><\/strong>Since it\u2019s a signal, you can hook into changes with computed() or effect() without extra wiring.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>The model() signal simplifies two-way binding into a single, readable, and reactive property. It cuts boilerplate, unifies component state, and improves maintainability. If you&#8217;re serious about building modern Angular apps with cleaner architecture and fewer moving parts, it\u2019s time to embrace signals. And if you want expert help modernizing your codebase, <a href=\"https:\/\/www.cmarix.com\/hire-angular-developers.html\">hire Angular developers<\/a> who already work with signals and understand how to architect with model() at the core. It\u2019ll save you time, money, and future headaches.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the traditional Angular approach, creating two-way binding meant setting up both an @Input() to receive data and an @Output() to emit changes. You also needed to wire up event emitters manually. This pattern worked, but it added boilerplate and split the logic for incoming and outgoing data. What model() Signal Does Differently Introduced in [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":2444,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7,3],"tags":[],"class_list":["post-2443","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular","category-web"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2443","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/comments?post=2443"}],"version-history":[{"count":2,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2443\/revisions"}],"predecessor-version":[{"id":2447,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2443\/revisions\/2447"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media\/2444"}],"wp:attachment":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media?parent=2443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/categories?post=2443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/tags?post=2443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}