- Overview
- Transcript
5.9 Observing Form State Changes
In this lesson you'll see how to use observables to listen for changes in either control value or form status. You'll also learn a little bit about what observables are and how they can be used.
1.Introduction6 lessons, 42:00
1.1Introduction00:48
1.2Get Started With Angular-CLI11:09
1.3Developing With Angular-CLI13:17
1.4TypeScript vs. JavaScript06:54
1.5Angular Modules From the CLI04:31
1.6CLI Options05:21
2.Get Started With Angular7 lessons, 42:38
2.1Bootstrapping the Application04:30
2.2The Application Module04:15
2.3The Application Component08:06
2.4Component Styling03:06
2.5Global Styling05:11
2.6Creating a Component With the CLI09:34
2.7Creating a Service With the CLI07:56
3.Core Concepts7 lessons, 55:20
3.1Component Trees06:20
3.2Dependency Injection06:52
3.3Content Projection05:38
3.4Component and Directive Lifecycle Methods06:31
3.5Component-Only Lifecycle Methods05:28
3.6Decorators07:36
3.7Models16:55
4.Template Deep Dive11 lessons, 1:10:56
4.1Basic Data Binding With Interpolation05:35
4.2Property Bindings07:07
4.3Attribute Bindings03:29
4.4Event Bindings08:16
4.5Class and Style Bindings05:44
4.6The `NgClass` and `NgStyle` Directives05:04
4.7The `*ngIf` Directive04:41
4.8The `*ngFor` Directive09:29
4.9Inputs05:33
4.10Using Pipes in a Template07:31
4.11Using Pipes in a Class08:27
5.Forms10 lessons, 1:45:41
5.1Handling User Input With Template Reference Variables07:06
5.2Template-Driven Forms11:10
5.3Template-Driven Forms: Validation and Submission14:00
5.4Reactive Forms11:26
5.5Using a `FormBuilder`08:01
5.6Reactive Validation With Built-in Validators14:53
5.7Creating Custom Validators for Template-Driven Forms12:18
5.8Creating Custom Validators for Reactive Forms08:26
5.9Observing Form State Changes12:40
5.10Working With the `@HostListener` Decorator05:41
6.Routing9 lessons, 1:15:10
6.1Defining and Configuring Routes07:53
6.2Rendering Components With Router Outlets10:14
6.3Using Router Links for Navigation05:25
6.4Navigating Routes Using the Router06:24
6.5Determining the Active Route Using an Activated Route07:16
6.6Working With Route Parameters10:42
6.7Using Route Guards07:36
6.8Observing Router Events10:55
6.9Adding Child Routes08:45
7.Using the HTTP Client5 lessons, 56:24
7.1Sending an HTTP Request10:52
7.2Handling an HTTP Response11:22
7.3Setting Request Headers12:33
7.4Intercepting Requests09:04
7.5Finishing the Example Application12:33
8.Testing10 lessons, 1:23:27
8.1Service Unit Test Preparation10:45
8.2Unit Testing Services13:24
8.3Component Unit Test Preparation12:35
8.4Unit Testing Components07:27
8.5Unit Testing Component Templates06:58
8.6Unit Testing Pipes04:41
8.7Unit Testing Directives04:56
8.8Unit Testing Validators04:48
8.9Unit Testing Observables11:37
8.10Unit Testing HTTP Interceptors06:16
9.Building for Production1 lesson, 03:40
9.1Building for Production03:40
10.Conclusion1 lesson, 01:32
10.1Conclusion01:32
5.9 Observing Form State Changes
Hi folks. In this lesson, we're going to look at how we can observe changes in the state of a form or individual form controls from within a component. There are multiple different ways that we can do this, ranging from simple event handling to more complex state change observables. If we want to observe the changes of a single element, like a text input. One way to do that is to use an event binding directly on the element. So, for example, if we wanted to be notified when someone typed into the telephone field in our feedback form. We could do something like this. And then we would need to add this handle input method to the component class. And let's go back to the browser now. As we start to enter characters into the input we start to see our logs in the console. So this approach works and it could be fine for simple situations, but there are problems with doing it this way. It's a reactive form, not a template driven form. So, it's not fantastic to go against that philosophy and start adding things in the template. Sure, it's only one event binding in this case, but what if we wanted to watch all of the inputs for changes? Now there are more bindings and the template is even more complex. I mean it's pretty complex as it is anyway. Partly that's because of my screen resolutions. But it's still pretty complex. So the last thing that we wanna do is make that more complex. This technique also relies on passing the event object. There are ways around this, sure. We could use a template reference variable to avoid passing the event object. But then there's even more stuff going into the template. But also, this approach has other limitations. What if we don't want our handler to be invoked on every single keypress? We'd need to add our own debouncing logic into the component and that would make the component more complex, as well as the template. So event binding works but it's basic and it has limitations. A better way would be to observe changes in the control from within the component and then we don't have to change the template at all. So let's get rid of the binding in the template. And we can get rid of the handler back in the class. Angular creates a number of things that we can use to subscribe to changes in our forms. One of these is called value changes, and we can subscribe to this in order top be notified whenever the controls value changes. Let's add a subscription in the ng on Init method for changes in the telephone inputs. We can get the control that we are interested in using the useful get method, and we parse it the name of the control that we want to get, just like if we were using that in a template which we have done previously. All controls have these value changes property which contains an observable that we can subscribe to using the subscribe method. This method takes a callback, which we used an arrow function for in this example. This handler has passed the value that changed. So let's save that, and let's go back to the browser again. And it's pretty much the same as before. We can see the console log statement every time we press a key. So, personally, I think this is already a big improvement. First of all, all of the changes are in one place. They're not split between the component and the template. Also, we don't have to work with the complex event object. We receive only the value which changed in the callback. These are already big benefits. But also, the whole observable concept gives us access to much more powerful tools. Let's say that we want to delay the console log so that we don't get the value change on every single keystroke. With observables this is easy. We just need to import the helpful debounce time operator from RXJS. Now we can pipe this function to our observable. The debounds function delays the firing of the observable by the specified number of milliseconds. So let's go back to the browser now. So this time we can type five or six characters easily before we see the first console log. Okay so now you've seen some of the benefits let's take a moment to clarify what observables actually are. Observables are similar conceptually to promises. And they're useful for asynchronous code, just like promises. We're interested in handling some event at some future point but we don't know when. So we can add a handler that will be in vote at some future point whenever that event occurs. The difference between observables and promises is that promises are intended for a single result at some future point. Whereas observables are intended for a stream of possibly many results at many future points. In our example here, a promise would not be suitable for watching value changes, because there could be many value changes. Observables also have a much richer API than promises, and can be retried, canceled, and much, much more. This brings me to the next point about observables. Unsubscribing. We've subscribed to these value changes inside the ngOnInit method, and this method will be fired every time the component is initialized. Which for us is every time the feedback form is opened. Look, if we add a console log to the top of ngOnInit. And now go back to the browser. We can see that we see that console log every single time the feedback form is opened. The point here is that we could end up with memory leaks. Angular takes care that we aren't adding multiple subscriptions for the same event, so we shouldn't any duplicate logs for the value changes, but in more complex forms I've experienced these memory leaks firsthand. And so it can happen and it can cripple an application if not handled properly. What we should do is cancel the subscription when we're done with the component. Thankfully this is incredibly easy to do. So first of all, let's bring some extra type information into our component. This also comes from the RxJS library, which is a separate third party library but comes included with Angular. We also need to bring in another of Angular's lifecycle methods. We already have the Oninit interface but we'll need the ondestroy interface as well. And let's add that to the list of interfaces that the class implements. And now we need to add an ng on destroy method. We'll populate this method in just a moment. Okay, so when we subscribe to something, the subscribe method returns an observable. And this is what we'll need to unsubscribe. So we'll need to store this as a property of the component. We don't need to expose this proxy to the template or outside of the component at all, so we can keep it private, and it will be of the type subscription. So now when we bind to value changes, we just need to capture the return and store it in this property. And now we can fill out the ng on destroy method. All we need to do to dispose of the subscription, is call the unsubscribe method of the subscription objects. This simple line of code will help us to avoid any impacts on performance due to memory leaks. It's recommended to always unsubscribe from any subscriptions of observables that we create. Okay, so although interesting we don't need to watch our telephone input for value changes. Let's make a slight change to see that we can also subscribe to status changes of the form itself. Okay, so this time we are binding to status changes on the entire form. Although you should note that you can do this for individual form controls as well. This time the callback function receives the status of the form as an argument. And if we go back to the browser now. We should start to see locked messages of the form status which is currently invalid. And now we can see that the last few log messages say valid because once we filled out the form correctly, the form should become valid. So, this can be extremely useful to monitor when the form becomes valid. Again, this example is purely to show you these concepts. We don't need this in this particular form, so let's go ahead and remove everything that we've added so far in this lesson. Or, if you prefer, you can just comment now and play around with it later. So, I just want to remind you that observables aren't a part of Angular. They are a part of this external third-party library called RxJS, and we used one of the operators from this framework, the. As well as this, there are many, many others. So this webpage shows all of the RxJS version 5 operators that can be used. You can see there are many, many of them. For all kinds of different situations. So I'd recommend that you come back here at some point and just have a look through some of these. And also if you want to learn a bit more about RxJS itself, and observables in general, this site also contains a wealth of information all about RxJS. So in this lesson we saw how to watch either a form or individual form controls for either value changes or status changes using the concept of observables. We've seen how to use the subscribe methods where they handler for events that we want to observe. We've seen how to use operators like Debounce time, and we've learned we should always unsubscribe from observables when we no longer need them. Thanks for watching.