{"id":6628,"date":"2021-07-27T18:12:24","date_gmt":"2021-07-27T18:12:24","guid":{"rendered":"https:\/\/www.ardorsys.com\/blog\/?p=6628"},"modified":"2021-07-29T05:34:23","modified_gmt":"2021-07-29T05:34:23","slug":"exploring-forms-in-angular-types-benefits-and-differences","status":"publish","type":"post","link":"https:\/\/www.ardorsys.com\/blog\/exploring-forms-in-angular-types-benefits-and-differences\/","title":{"rendered":"Exploring\u202fForms in Angular \u2013 Types, Benefits and Differences\u202f\u202f"},"content":{"rendered":"<p>While developing a <a href=\"https:\/\/www.ardorsys.com\/web-application-development\/\">web application<\/a>, or setting dynamic pages and meta tags we\u202fneed to\u202fdeal with multiple input elements and value types, such limitations could seriously hinder our work \u2013 in terms of either data flow control, data validation, or user experience.<\/p>\n<p>This article is an excerpt from the book,\u00a0ASP.NET Core 5 and Angular, Fourth Edition by Valerio De\u202fSanctis\u202f\u2013 A revised edition of a bestseller that includes coverage of the Angular routing module, expanded discussion on the <a href=\"https:\/\/www.ardorsys.com\/hire-angularjs-developer\/\">Angular<\/a> CLI, and detailed instructions for deploying apps on Azure, as well as both Windows and Linux.<\/p>\n<p>Sure, we could easily work around most of the issues by implementing some custom methods within our form-based\u202fcomponents we could throw some errors such as\u202fisValid(),\u202fisNumber(), and so on here and there, and then hook them up to our template syntax and show\/hide the validation messages with the help of structural directives such as\u202f<em>*ngIf,\u202f*ngFor,<\/em>\u00a0and the like.\u00a0However, it would\u202fbe a horrible way to address our problem; we\u00a0didn\u2019t\u00a0choose a feature-rich client-side framework such as Angular to work that way.<\/p>\n<p>Luckily enough, we have no reason to do that since Angular provides us with a couple of alternative strategies to deal with these common form-related scenarios:<\/p>\n<ul>\n<li>Template-Driven Forms<\/li>\n<li>Model-Driven Forms, also known as\u202fReactive\u202fForms<\/li>\n<\/ul>\n<p>Both\u202fare highly coupled with the framework and thus extremely viable; they both belong to the\u202f@angular\/forms\u202flibrary\u202fand\u202fshare a common set of form control classes. However, they also have their own specific sets of features, along with their pros and cons, which could ultimately lead to us choosing one of them.<\/p>\n<p>Let\u2019s try to quickly summarize these differences.<\/p>\n<h4>Template-Driven Forms<\/h4>\n<p>If you\u2019ve come from AngularJS, there\u2019s a high chance that the Template-Driven approach will ring a bell or two. As the name implies, Template-Driven Forms host most of the logic in the template code; working with a Template-Driven Form means:<\/p>\n<ul>\n<li>Building the form in the\u202f.html\u202ftemplate file<\/li>\n<li>Binding data to the various input fields using ngModel\u202finstance<\/li>\n<li>Using a dedicated\u202fngForm\u202fobject related to the whole form and containing all the inputs, with each being accessible through their\u202fname.<\/li>\n<\/ul>\n<p>These things need to be done to perform the required validity checks.\u202fTo understand this, here\u2019s what a Template-Driven Form looks like:<\/p>\n<pre><code>&lt;form\u202fnovalidate\u202fautocomplete=\"off\"\u202f#form=\"ngForm\"\r\n(ngSubmit)=\"onSubmit(form)\"&gt;\r\n\r\n&lt;input\u202ftype=\"text\"\u202fname=\"name\"\u202fvalue=\"\"\u202frequired\u202f \r\nplaceholder=\"Insert the city name...\"\u202f\u202f \r\n[(ngModel)]=\"city.Name\"\u202f#title=\"ngModel\"\u202f \r\n\/&gt;\u202f\r\n\r\n&lt;span\u202f*ngIf=\"(name.touched\u202f||\u202fname.dirty) &amp;&amp;\u202f\u202f \r\n\u202f\u202f name.errors?.required\"&gt;\u202f \r\n\u202f\u202f\u202f\u202f\u202f\u202f\u202f Name is a required field: please enter a valid city name.\u202f \r\n&lt;\/span&gt;\u202f\r\n\r\n&lt;button\u202ftype=\"submit\"\u202fname=\"btnSubmit\"\u202f\u202f \r\n\u202f\u202f\u202f\u202f\u202f [disabled]=\"form.invalid\"&gt;\u202f \r\n\u202f\u202f\u202f\u202f\u202f Submit\u202f \r\n&lt;\/button&gt;\r\n&lt;\/form&gt;<\/code><\/pre>\n<p>Here, we can access any element, including the form itself, with some convenient aliases \u2013 the attributes with the\u202f#\u202fsign \u2013 and check for their current states to create our own validation workflow.<\/p>\n<p>These states are provided by the framework and will change in real-time, depending on various things:\u202ftouched, for example, becomes\u202fTrue\u202fwhen the control has been visited at least once;\u202fdirty, which is the opposite of\u202fpristine, means that the control value has changed, and so on. We used both\u202ftouched\u202fand\u202fdirty\u202fin the preceding example because we want our validation message to only be shown if the user moves their focus to the\u202f&lt;input name=\u201dname\u201d&gt;\u202fand then goes away, leaving it blank by either deleting its value or not setting it.<\/p>\n<p>These are Template-Driven Forms in a nutshell; now that we\u2019ve had an overall look at them, let\u2019s try to summarize the pros and cons of this approach. Here are the main advantages of Template-Driven Forms:<\/p>\n<ul>\n<li><strong>Template-Driven Forms are very easy to write.<\/strong> We can recycle most of our HTML knowledge (assuming that\u202fwe have any). On top of that, if we\u202fcome\u202ffrom AngularJS, we already know how well we can make them work once we\u2019ve mastered the technique.<\/li>\n<li><strong>They are rather easy to read and understand,<\/strong> at least from an HTML point of view; we have a plain, understandable HTML structure containing all the input fields and validators, one after another. Each element will have a name, a two-way binding with the underlying\u202fngModel, and (possibly) Template-Driven logic built upon aliases that have been hooked to other elements that we can also see, or to the form itself.<\/li>\n<\/ul>\n<p>Here are their weaknesses:<\/p>\n<ul>\n<li><strong>Template-Driven Forms require a lot of HTML code<\/strong>, which can be rather difficult to maintain and is generally more error-prone than pure TypeScript.<\/li>\n<li>For the same reason,\u202f<strong>these forms cannot be unit tested<\/strong>. We have no way to test their validators or to ensure that the logic we implemented will work, other than running an end-to-end test with our browser, which is hardly ideal for complex forms.<\/li>\n<li><strong>Their readability will quickly drop<\/strong>\u202fas we add more and more validators and input tags. Keeping all their logic within the template might be fine for small forms, but it does not scale well when dealing with complex data items.<\/li>\n<\/ul>\n<p>Ultimately, we can say that Template-Driven Forms might be the way to go when we need to build small forms with simple data validation rules, where we can benefit more from their simplicity. On top of that, they are quite\u202flike\u202fthe typical HTML code we\u2019re already used to (assuming that\u202fwe do have a plain HTML development background); we just need to learn how to decorate the standard\u202f&lt;form&gt;\u202fand\u202f&lt;input&gt;\u202felements with aliases and throw in some validators handled by structural directives such as the ones we\u2019ve already seen, and we\u2019ll be set in (almost) no time.<\/p>\n<p>For additional information on Template-Driven Forms, we highly recommend that you read the official Angular documentation at:\u202f<a href=\"https:\/\/angular.io\/guide\/forms\" target=\"_blank\" rel=\"nofollow noopener\">https:\/\/angular.io\/guide\/forms\u202f<\/a><\/p>\n<p>That being said;\u202fthe lack of unit testing, the HTML code bloat that they will eventually produce, and the scaling difficulties will eventually lead us toward an alternative approach for any non-trivial form.<\/p>\n<h4>Model-Driven\/Reactive Forms<\/h4>\n<p>The Model-Driven approach was specifically added in Angular 2+ to address the known limitations of Template-Driven Forms. The forms that are implemented with this alternative method are known as\u202f<strong>Model-Driven Forms<\/strong>\u202for Reactive Forms, which are the exact same thing.<\/p>\n<p>The main difference here is that (almost) nothing happens in the template, which acts as a mere reference to a more complex TypeScript object that gets defined, instantiated, and configured programmatically within the component class: the form <strong>model<\/strong>.<\/p>\n<p>To understand the overall concept, let\u2019s try to rewrite the previous form in a Model-Driven\/Reactive way (the relevant parts are highlighted). The outcome of doing this is as follows:<\/p>\n<pre><code>&lt;form\u202f[formGroup]=\"form\"\u202f(ngSubmit)=\"onSubmit()\"&gt;\u202f\r\n\r\n&lt;input\u202fformControlName=\"name\"\u202frequired\u202f\/&gt;\u202f\r\n\r\n&lt;span\u202f*ngIf=\"(form.get('name').touched\u202f||\u202fform.get('name').dirty)\u202f\u202f \u202f\u202f\u202f\u202f\u202f\u202f\u202f \r\n&amp;&amp;\u202fform.get('name').errors?.required\"&gt;\u202f \u202f\u202f\u202f\u202f\u202f\u202f\u202f \r\nName is a required field: please enter a valid city name.\u202f \r\n&lt;\/span&gt; \r\n\r\n&lt;button\u202ftype=\"submit\"\u202fname=\"btnSubmit\"\u202f \u202f\u202f\u202f\u202f\u202f\u202f\u202f \r\n[disabled]=\"form.invalid\"&gt; \r\nSubmit \r\n&lt;\/button&gt;\u202f \r\n\u202f\r\n&lt;\/form&gt;<\/code><\/pre>\n<p>As we can see, the amount of required code is much lower.\u202f Here\u2019s the underlying form model that we will define in the component class file (the relevant parts are highlighted in the following code):<\/p>\n<pre><code>import {\u202fFormGroup,\u202fFormControl\u202f}\u202ffrom\u202f'@angular\/forms';\u202f\r\n\r\nclass\u202fModelFormComponent\u202fimplements\u202fOnInit\u202f{\u202f \r\nform:\u202fFormGroup;\u202f\u202f \r\n\u202f\u202f \u202f\u202fngOnInit() {\u202f \r\n\u202f\u202f\u202f\u202fthis.form\u202f=\u202fnew\u202fFormGroup({\u202f \r\n\u202f\u202f\u202f\u202f\u202f\u202f title:\u202fnew\u202fFormControl()\u202f \r\n\u202f\u202f\u202f });\u202f \r\n\u202f }\u202f \r\n}<\/code><\/pre>\n<p>Let\u2019s try to understand what\u2019s happening here:<\/p>\n<ul>\n<li>The\u202fform\u202fproperty is an instance of\u202fFormGroup\u202fand represents the form itself.<\/li>\n<li>FormGroup, as the name suggests, is a container of form controls sharing the same purpose. As we can see, the\u202fform\u202fitself acts as a\u202fFormGroup, which means that we can nest\u202fFormGroup\u202fobjects inside other FormGroup objects (we didn\u2019t do that in our sample, though).<\/li>\n<li>Each data input element in the form template \u2013 in the preceding code,\u202fname\u202f\u2013 is represented by an instance of\u202fFormControl.<\/li>\n<li>Each\u202fFormControl\u202finstance encapsulates the related control\u2019s current state, such as\u202fvalid,\u202finvalid,\u202ftouched, and\u202fdirty, including its actual value.<\/li>\n<li>Each\u202fFormGroup\u202finstance encapsulates the state of each child control, meaning that it will only be valid if\/when all its children are also valid.<\/li>\n<\/ul>\n<p>Also, note that we have no way of accessing the\u202fFormControls\u202fdirectly like we were doing in Template-Driven Forms; we\u202fhave to\u202fretrieve them using\u202fthe\u202f.get()\u202fmethod of the main\u202fFormGroup, which is the form itself.<\/p>\n<p>At first glance, the Model-Driven template doesn\u2019t seem too different from the Template-Driven one; we still have a\u202f&lt;form&gt;\u202felement, an\u202f&lt;input&gt;\u202felement hooked to a\u202f&lt;span&gt;\u202fvalidator, and a\u202fsubmit\u202fbutton; on top of that, checking the state of the input elements takes a bigger amount of source code since they have no aliases we can use. What\u2019s the real deal, then?<\/p>\n<p>To help us visualize the difference, let\u2019s look at the following diagrams: here\u2019s a schema depicting how <strong>Template-Driven Forms<\/strong>\u202fwork:<\/p>\n<p><img  loading=\"lazy\"  decoding=\"async\"  class=\"aligncenter size-full wp-image-6639 pk-lazyload\"  src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAApAAAAFBAQMAAAD68Q0EAAAAA1BMVEUAAP+KeNJXAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAADFJREFUeNrtwTEBAAAAwqD1T20JT6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIMBaBMAASHwRhMAAAAASUVORK5CYII=\"  alt=\"\"  width=\"656\"  height=\"321\"  data-pk-sizes=\"auto\"  data-ls-sizes=\"auto, (max-width: 656px) 100vw, 656px\"  data-pk-src=\"https:\/\/www.ardorsys.com\/blog\/wp-content\/uploads\/2021\/07\/Template-Driven-Forms.jpg\"  data-pk-srcset=\"https:\/\/avfockc25ltq.cdn.shift8web.com\/blog\/wp-content\/uploads\/2021\/07\/Template-Driven-Forms.jpg 656w, https:\/\/avfockc25ltq.cdn.shift8web.com\/blog\/wp-content\/uploads\/2021\/07\/Template-Driven-Forms-300x147.jpg 300w, https:\/\/avfockc25ltq.cdn.shift8web.com\/blog\/wp-content\/uploads\/2021\/07\/Template-Driven-Forms-380x186.jpg 380w\" ><\/p>\n<p>By looking at the arrows, we can easily see that, in\u202f<strong>Template-Driven\u202fForms<\/strong>, everything happens in the template; the HTML form elements are directly bound to the\u202f<strong>DataModel<\/strong>\u202fcomponent represented by a property filled with an asynchronous HTML request to the\u202f<strong>Web Server<\/strong>, much like we did with our cities and country table.<\/p>\n<p>That <strong>DataModel<\/strong> will be updated as soon as the user changes something, that is, unless a validator prevents them from doing that. If we think about it, we can easily understand how there isn\u2019t a single part of the whole workflow that happens to be under our control; Angular handles everything by itself using the information in the data bindings defined within our template.<\/p>\n<p>This is what\u202fTemplate-Driven\u202factually means: the template is calling the shots.\u202f Now, let\u2019s\u202ftake a look\u202fat the\u202f<strong>Model-Driven Forms<\/strong>\u202f(or Reactive Forms) approach:<\/p>\n<p><img  loading=\"lazy\"  decoding=\"async\"  class=\"aligncenter size-full wp-image-6640 pk-lazyload\"  src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoIAAAE9AQMAAAClSpFrAAAAA1BMVEUAAP+KeNJXAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAADBJREFUeNrtwQENAAAAwqD3T20ON6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3g1ligABSitJ0gAAAABJRU5ErkJggg==\"  alt=\"\"  width=\"642\"  height=\"317\"  data-pk-sizes=\"auto\"  data-ls-sizes=\"auto, (max-width: 642px) 100vw, 642px\"  data-pk-src=\"https:\/\/www.ardorsys.com\/blog\/wp-content\/uploads\/2021\/07\/Model-Driven-Forms.jpg\"  data-pk-srcset=\"https:\/\/avfockc25ltq.cdn.shift8web.com\/blog\/wp-content\/uploads\/2021\/07\/Model-Driven-Forms.jpg 642w, https:\/\/avfockc25ltq.cdn.shift8web.com\/blog\/wp-content\/uploads\/2021\/07\/Model-Driven-Forms-300x148.jpg 300w, https:\/\/avfockc25ltq.cdn.shift8web.com\/blog\/wp-content\/uploads\/2021\/07\/Model-Driven-Forms-380x188.jpg 380w\" ><\/p>\n<p>As we can see, the arrows depicting the\u202fModel-Driven Forms\u202fworkflow tell a whole different story. They show how the data flows between the\u202fDataModel\u202fcomponent \u2013 which we get from the\u202fWeb Server\u202f\u2013 and a UI-oriented form model that retains the states and the values of the HTML form (and its children input elements) that are presented to the user. This means that we\u2019ll be able to get in-between the data and the form control objects and perform\u202fa number of\u202ftasks firsthand: push and pull data, detect and <a href=\"https:\/\/www.ardorsys.com\/blog\/react-vs-angular-which-one-choose-for-your-project\/\">react<\/a> to user changes, implement our own validation logic, perform unit tests, and so on.<\/p>\n<p>Instead of being superseded by a template that\u2019s not under our control, we can track and influence the workflow programmatically, since the form model that calls the shots is also a\u202fTypeScript\u202fclass; that\u2019s what Model-Driven Forms are about. This also explains why they are also called <strong>Reactive Forms<\/strong>\u202f\u2013 an explicit reference to the Reactive programming style that favors explicit data handling and change management throughout the workflow.<\/p>\n<h4>Summary<\/h4>\n<p>In this article, we focused on\u202fthe <a href=\"https:\/\/www.ardorsys.com\/angularjs-development\/\">Angular framework<\/a> and the two form design models it offers: the\u202fTemplate-Driven\u202fapproach, mostly inherited from <a href=\"https:\/\/angular.io\/\" target=\"_blank\" rel=\"nofollow noopener\">AngularJS<\/a>, and the\u202fModel-Driven\u202for\u202fReactive\u202falternative. We took some valuable time to analyze the pros and cons provided by\u202fboth, and then we\u202fmade\u202fa detailed comparison of the underlying logic and workflow. At the end of the day, we chose the\u202fReactive\u202fway, as it gives the developer more control and enforces a more consistent separation of duties between the\u202fData Model\u202fand the\u202fForm Model.<\/p>\n<p style=\"font-size: 13px;\">Source: <a href=\"https:\/\/hub.packtpub.com\/exploring%e2%80%afforms-in-angular-types-benefits-and-differences%e2%80%af%e2%80%af%e2%80%af-%e2%80%af\/\" target=\"_blank\" rel=\"nofollow noopener\">hub.packtpub.com<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"While developing a web application, or setting dynamic pages and meta tags we\u202fneed to\u202fdeal with multiple input elements and value types, such limitations could seriously hinder our work \u2013 in terms of either data flow control, data validation, or user experience&#8230; \n","protected":false},"author":1,"featured_media":6631,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[104],"tags":[101],"class_list":{"0":"post-6628","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-angular","8":"tag-angularjs-development"},"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/posts\/6628","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/comments?post=6628"}],"version-history":[{"count":0,"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/posts\/6628\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/media\/6631"}],"wp:attachment":[{"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/media?parent=6628"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/categories?post=6628"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ardorsys.com\/blog\/wp-json\/wp\/v2\/tags?post=6628"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}