So far we’ve only extracted the value from our form by callingonSubmitwhen the form is submitted.
But often we want to watch for any value changes on a control.
BothFormGroupandFormControlhave anEventEmitterthat we can use to observe changes.
EventEmitteris an Observable, which means it conforms to a defined specification for watching for changes. If you’re interested in the Observable spec,you can find it here⁴⁷
To watch for changes on a control we:
1. get access to theEventEmitterby callingcontrol.valueChanges. Then we 2. add an observer using the.subscribemethod
Here’s an example:
Here we’re observing two separate events: changes on the sku field and changes on the form as a whole.
The observable that we pass in is an object with a single key:next (there are other keys you can pass in, but we’re not going to worry about those now).nextis the function we want to call with the new value whenever the value changes.
If we type ‘kj’ into the text box we will see in our console:
1 sku changed to: k
2 form changed to: Object {sku: "k"}
3 sku changed to: kj
4 form changed to: Object {sku: "kj"}
As you can see each keystroke causes the control to change, so our observable is triggered. When we observe the individualFormControlwe receive a value (e.g.kj), but when we observe the whole form, we get an object of key-value pairs (e.g.{sku: "kj"}).
ngModel
NgModelis a special directive: it binds a model to a form.ngModel is special in that it implements two-way data binding. Two-way data binding is almost always more complicated and difficult to reason about vs. one-way data binding. Angular is built to generally have data flow one-way: top-down. However, when it comes to forms, there are times where it is easier to opt-in to a two-way bind.
Just because you’ve usedng-modelin Angular 1 in the past, don’t rush to usengModelright away. There are good reasons toavoid two-way data binding⁴⁸. Of course,ngModelcan be really handy, but know that we don’t necessarily rely on two-way data binding as much as we did in Angular 1.
Let’s change our form a little bit and say we want to inputproductName. We’re going to usengModel to keep the component instance variable in sync with the view.
First, here’s our component definition class:
⁴⁸https://www.quora.com/Why-is-the-two-way-data-binding-being-dropped-in-Angular-2
code/forms/src/app/demo-form-ng-model/demo-form-ng-model.component.ts
23 console.log('you submitted value: ', value);
24 }
25 }
Notice that we’re simply storingproductName: stringas an instance variable.
Next, let’s usengModelon ourinputtag:
code/forms/src/app/demo-form-ng-model/demo-form-ng-model.component.html
Now notice something - the syntax forngModelis funny: we are using both brackets and parenthesis around thengModelattribute! The idea this is intended to invoke is that we’re using both the input []brackets and the output ()parenthesis. It’s an indication of the two-way bind.
Notice something else here: we’re still usingformControlto specify that thisinputshould be bound to theFormControlon our form. We do this becausengModelis only binding theinputto the instance variable - theFormControlis completely separate. But because we still want to validate this value and submit it as part of the form, we keep theformControldirective.
Last, let’s display ourproductNamevalue in the view:
code/forms/src/app/demo-form-ng-model/demo-form-ng-model.component.html
4 <div class="ui info message">
5 The product name is: {{productName}}
6 </div>
Here’s what it looks like:
Demo Form with ngModel
Easy!
Wrapping Up
Forms have a lot of moving pieces, but Angular makes it fairly straightforward. Once you get a handle on how to useFormGroups,FormControls, andValidations, it’s pretty easy going from there!
As our programs grow in size, we parts of the app need to communicate with other modules. When moduleArequires moduleBto run, we say thatBis a dependency of A.
One of the most common ways to get access to dependencies is to simplyimporta file. For instance, in this hypothetical module we might do the following:
1 // in A.ts
2 import {B} from 'B'; // a dependency!
3
4 B.foo(); // using B
In many cases, simplyimporting code is sufficient, but other times we need to provide dependencies in a more sophisticated way. For instance, we may want to:
• substitute out the implementation ofBforMockBduring testing
• share a single instance of theBclass across our whole app (e.g. the Singleton pattern)
• create a new instance of theBclass every time it is used (e.g. the Factory pattern) Dependency Injection can solve these problems.
Dependency Injection (DI) is a system to make parts of our program accessible to other parts of the program - and we can configure how that happens.
One way to think about “the injector” is as a replacement for the new operator. That is, instead of using the language-provided new operator, Dependency Injection let’s us configure how objects are created.
The term Dependency Injection is used to describe both a design pattern (used in many different frameworks) and also the specific implementation of DI that is built-in to Angular.
The major benefit of using Dependency Injection is that the client component needn’t be aware of how to create the dependencies. All the client component needs to know is how to interact with those dependencies. This is all very abstract, so let’s dive in to some code.
How to use this chapter
This chapter is a tour of Angular DI system and concepts. You can find the code for this chapter incode/dependency-injection.
While reading this chapter, run the demo project by changing into the project directory and running:
1 npm install 2 npm start
As a preview, to get Dependency Injection to work involves configuration in your
NgModules. It can feel a bit confusing at first to figure out “where” things are coming from.
The example code has full, runnable examples with all of the context. So if you feel lost, we’d encourage you to checkout the sample code alongside reading this chapter.