Build Forms in Angular
with Jennifer Wadella
Every web app is going to end up needing forms at some point. In this episode, Jennifer Wadella will teach us how to use the @angular forms API to create custom web forms!
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
Jason: Hello, everybody. And welcome to another episode of Learn with Jason! Today on the show, we're bringing in Jennifer Wadella. Jennifer, thank you so much for hanging out with us today. How you going?
Jennifer: Thanks for having me. I'm excited to be here.
Jason: I'm really happy to have you on the show. We first met at what was that? That conference?
Jennifer: Yeah, that conf.
Jason: A few years ago. It was an absolute blast, it was super-fun, at a hotel full of elephant statues and Tiki bars.
Jennifer: It is the Kalahari, and there's Code smash.
Jason: What was that place? The Wisconsin Dells. I ate cheese curds.
Jennifer: Cheese curds are delicious. The only problem with the conference is it's a paint in ass to get to.
Jason: You fly into Madison and everyone is trying to car pool out to the Wisconsin Dells. Yeah, it was really, really fun. For those what weren't at that Conf or aren't familiar with your work. Back ground?
Jason: Yeah. I'm -- I'm feeling -- really feeling the urge to do some just any kind of in-person hangouts. Like yeah. I'm excited. I get my first vaccination shot today. I was talking to my partner about this. We were just like, all I want to do is sit at a bar. I just to want sit at a bar. That's it.
Jennifer: Yeah. Like, people in the chat, tell us the first thing you're gonna do once you're vaccinated. I had shot number two on last -- no, this Monday, last Monday. Oh, my god, COVID time has no meaning. All I wanted to do was go and wander around a Home Goods store. Not with an inclination to buy anything. But just to wander around a store for no reason. And I did that this week. It was a sense of normally. Of course I miss my friends and want to go out to bars. But that was the random obscure thing.
Jason: I hadn't thought of that. For real, it was like a weekend activity. We would go, we would get a coffee and then we would go wander around like the antique shops and --
Jason: We were never buying stuff. It was a thing to do that's not looking at a computer.
Jennifer: yeah. It's nice to have that separation. I don't know if you have tried to furnish a house. But it's hard to go and set up for a specific thing. But when you're doing this preambling, strolling, that's where you find the perfect thing. I have a bourbon shelf at my house. Whenever I travel, I buy a cookbook from the region.
Jennifer: It's the bourbon shrine. The perfect piece I found while wandering.
Jason: That's so cool. Seeing good stuff in the chat. People are going to take the kids downtown. Yeah, date nights. Live concerts. Yes. In-person D & D. Yeah, I have been playing a remote game of not D & D, but Rogue Trader which is like it's space D & d. And it's really fun and let's me play with friends from Texas and stuff. But I do miss the in-person game nights. We would all bring snacks and stuff. Ben is going to bring a bunch of trees. I to want hang out, Ben. But you want to show up at my house with trees. There's a joke, I many partner has been slowly converting the house into a tree house. And wants to buy a tree farm. I'm done with trees. I'm done with trees.
Jennifer: I too have become a pandemic-crazy plant lady. It's curbed a little bit. But I actually -- one, two, three, four, five, six, seven, eight, nine, ten plants in my office right now. And there was this great sub Reddit -- or there was a great Reddit thread. I don't remember what it was. There was some guy, my wife keeps buying house plants, how do I make her stop? And all the crazy plant ladies descended on his ass. I'm team your partner. You will get no support from me.
Jason: I tried to rally support on Twitter and it went very much in the opposite direction. Please help me, I have nowhere to leave. There are only plants. Deal with it. Buy more tables.
Jason: All right. So, let's see, I bet if you got a tree farm, you could get at least three more video production toys. Maybe that's what I do. Barter. Buy more gear if I let Melissa get trees.
Jason: Okay. So, I think -- I mean, we could just talk about this all day.
Jennifer: So true, okay. Focus.
Jason: But let's -- let's talk a little bit about what we're actually here for which is, you know, you mentioned you're a Angular specialist.
Jason: I've done a bit of Angular. I work with Tara on my team at Netlify. Every once in a while we pair, she's been on the show to teach a little bit. But I'm not familiar with Angular. It's a framework that I can use if I have to. And one of the thing that is always kind of fascinates me about it is that it's very different from what I'm used to in other languages. And probably the thing that fascinates me the most, you don't write as much code as you generate. At least when you're kind of scaffolding things out. Which is fascinating to me. So, I'm always just kind of curious on the tick, I assume this is your preference since you're an Angular expert. What drew you to that style of coding?
Jennifer: Well, I'm gonna say like when I started my career, it was at the time where I was classified as a frontend developer, I grew up on GeoCities writing web pages. Right as my career took off, there was the transition of the definition of a web developer, from implementing a file in JSS and CSS, to jQuery and single page applications. My first adventure was with Backbone JS.
Jennifer: Yeah. I was at a marketing agency at the time. There was a very rapid progression of projects and prototyping. And so, I was able to get my hands dirty in a lot of different things. Like did a little bit of knockout. Trying to think if there's anything else big I did. But this was right around the time that, you know, Google had jumped in this game and dropped AngularJS. We had a couple of startups, they were rocking AngularJS. And I went to one of those. And I knew the struggles from Backbone that dealing with shadow views and all sorts of drama there. And having to learn on the fly. Going into Angular, there was a lot of problems solved and architecture provided. And I was also like I'm in Kansas City. We are in a .NET town. Angular was a common choice for pairing. It wasn't like I set out say I'm going to be an Angular developer. It's kind of where my career led me.
Jennifer: And figuring out how to be successful and operate in that environment. That being said, jumping around different frameworks, I have to generate, literally do touch and file name to create a new file. It's funny. I'm not saying I'm CLI-dependent. It's not like I don't know how to do these things. But any time I can save key strokes, like, yeah. It's really nice to have scaffolding tools and I don't think a lot of people are aware if they're not in the Angular community how powerful the scaffolding tools are. And we'll do this when we start to walk through the code. We generate a new app. As you're building, okay, I have a new feature, I can automatically run a command to create a module and create components which are like building blocks in that. And we have commands due to all these. And those commands are going to scaffold our base component class file, a TypeScript file, an HTML file, a template with the markup. It's going to create a test file, like a spec file for us to test our component and then a style file. And with the CLI, we can specify do we want to use SaaS, do we want to use less, basic CSS if you're a pleb. Sorry. I'm in the consulting field, you would not believe some of the dumpster fire codebases. No shade, but I can tell pretty much in 30 seconds if a code base was written by a backend developer or a frontend developer. No shade. We have different skill-sets and you know what you know. But it's kind of funny. You can do all these great things and spin up the files. But Angular uses what are called schematics. There are some built in using scaffolding for you. But find the team creating components or modules in a similar manner, you can use the schematics to generate a lot of the bootstrap code if you. Of a good example is Angular is built on TypeScript and RxJS. There are A lot of patterns that we use with Angular. We might be using an observable in there and might have to subscribe to the observable and clean up the subscription. We can write Angular schematics to write that code for us. Any time we create a new module or component that's going to be following this pattern we know that we're using, we can scaffold that out and run a command to generate this. There's a lot of tooling that people outside of the Angular community don't know.
Jason: And one of the things I have noticed about this, it creates an incredible amount of consistency. When you look at Angular codebases, you're not going to be surprised by the way things are organized in there.
Jennifer: Unless you're a consultant and see goofy ass shit. There's a UI -- sometimes I'm working with the team, this is honestly so bad and incorrect, I can't tell you what's going to happen. Because nobody does this. It's just so wrong. I don't know. This is going to cause bugs. I can't tell you the level of bugs. But, yeah. So, anyway. If you --
Jason: There will be bugs.
Jennifer: If provided, there will be consistency. Yes.
Jason: All right. Fair enough, fair enough. So, maybe, actually, that's a good segue, maybe we should hop over and actually start playing with this stuff.
Jason: Let's move over. Remember, first and foremost -- no, this is the browser we want to be in. This show, like every show is being live captioned while we speak. We have Amanda with us today. Thank you, Amanda, for hanging out. Amanda is with White Coat Captioning. And you can go to the home page and follow along if you want to read along. That is made possible through the generous support of sponsors, Netlify, Fauna, Auth0, and Hasura, all kicking in to make the show more accessible to more people which means a lot to me. And when you go to the home page, you can click these. Check them out. Also, while you're clicking things on the Internet, make sure you click over to Jennifer's page and follow her. It's a good account to follow. Look at the stuff she's created. I was thinking how smart it was to do this. Because I feel like I'm trying to like -- how much can I fit into 160 characters here? And then I just give up and post nonsense.
Jason: But, yeah. So, head over there. And then we're playing with Angular today. So, this is what we're going to be doing. Okay. So, links, all those things are out of the way. If I want to get started, I made an empty folder on my computer called Angular Forms. And I am very ready to learn things today.
Jennifer: Cool. So, I'm going to go ahead and assume that you've already installed. The Angular CLI.
Jason: So, I have the latest version. And let's also look at the Angular CLI. Here is a link to that this you want to see how to install it. I just used the npm command. So, I just installed that. And we are using version 11.2.9. I just installed it today so I'm assuming that's the latest.
Jennifer: Yes. And since there are a lot of people I think I've seen in the chat that are new to the Angular ecosystem, I want to call out things about how things process. The team behind Angular at Google does try to release a new version every 6 months. For a long time, this was a common pattern. That being said, at one point they set out to rewrite their compiler. And now modern Angular versions, I think it dropped in Angular 9 are using the IV compiler. We could do TypeScript checking in our templates. So, we have something that's called strict mode. Where you -- this is what is preferred where you opt into a couple different flags that are going to be doing certain checks for maintaining the integrity of your codebase. But it's nice to have that template type checking available so if you're, you know, dealing with really complex objects or something like that, you're going to get that notification of, hey, you're calling a prop here that may not actual exist. Very cool there. That being said, Angular 12 is on the horizon. If you're looking and exploring, and Angular updates too often, blah, blah, blah, they go every 6 months. Twelve is on the horizon and they're really conscious about breaking changes. I don't think we have had really anything that was a serious breaking change since Angular 6. Because the new versions are rolling out, it doesn't mean you're reworking the project every time.
Jason: Angular is not following SemVer, just a new release every 6 months.
Jennifer: That's the goal. They're balancing optimizations and long-term performance against desires of the community. Some of those we will get into when we talk about forms and what we like to see from forms. But yeah. That's the loose goal they try to follow.
Jason: Cool. I guess I remember that. And what you said earlier about Angular being like a really natural pairing for Dotnet. That also points to something that maybe you can confirm which is that my suspicion is that Angular has been really popular for like larger businesses and more enterprisey teams.
Jason: That's why a lot of us extremely online and startup culture might not think Angular is that popular. It's wildly popular, just not in the extremely online channels.
Jennifer: There are nuances there. Talk to people and our back ground, we have been in the frontend, been through every burned up -- build it up, burn it down iteration of a single page application framework. We are so deeply vested in the frontend and solving those problems that we know what those problems are. There's a lot of power that you have when you jump into a framework like React or Vue. You know the problems you're constantly solving and running into and you know what you're doing. For enterprise companies that have a backends focus, Angular is often a much safer choice because it's very opinionated. There are guardrails. Sometimes the teams need guardrails because they're not experienced frontend developers. And we joke a lot on my team when we're on client projects. We try to do things the right way. But we want to be aware of what we call foot guns. We're cautious about the code we implement and things that clients will accidently shoot themselves in the foot with, don't have the time, jumping around the codebase, copy and pasting.
Jason: That is such an important thing to consider. Because I feel like as I've gotten more experienced, when I was younger, I was very much like, well, we should just build it ourselves. It will be faster. Because I always thought, you know, I -- well, it's just me. I can build it like this. I don't need to learn all these other conventions, et cetera, et cetera. And when it was just me, that was okay. Like, I still felt the pain of maintenance later on.
Jason: Because as the old saying goes, if you're not using a framework, you're building a framework. But then as I started working with more and more people. As I said people -- they were Java Devs who got put on to a frontend team. That's your job now. They didn't want to be frontend Devs. They just got moved. Then you start to realize, the conventions, the guardrails, the setting up like automatic defaults that get you 90% of the way there, there's so much value in that. Even if for me is feels a little inconvenient to -- why am I creating three files for one component when I could just create one. Well, the convention, the, you know, that system that makes it really predictable and very, like, hey. This is the box. Fit in the box. You don't have to think about the box. Just use it. That is -- it means so much when you're looking at like long-term sustainability of a system and, you know, can you move somebody off this team without the whole system imploding?
Jennifer: Yep. Yeah. And, like, not that, you know, any solution is foolproof, but these are the patterns I see. And why I think Angular is widely adopted as it is at that corporate level. You know? Had that maintainability is huge. If you have ever had to write your own docs, you know what it's like. Imagine if you're doing something custom versus already existing.
Jason: Yeah. I see we have some Kansas City love in the chat. What's up, Will?
Jennifer: Will here, whoo!
Jason: And, yes, Chris, I was talking specifically to you about being extremely online. Okay. So, we've got -- we've got ourselves the Angular CLI. We've got an empty folder. And I'm ready.
Jennifer: You're ready.
Jason: If I wanted to get started...
Jennifer: We're going to build a new app.
Jason: Let's do that.
Jennifer: The command for that is NG new.
Jason: If I wanted to use this folder and not create a new one, will it do that.
Jennifer: I can't remember if there's a flag to do that. Because I don't think about it because I know how it works. It's going to generate a folder based on whatever name you give it.
Jason: Okay, let me do this, then. I'm going to delete my folder and try that again. NG new, and put the name in first?
Jennifer: NG new and whatever you want the application to be.
Jennifer: The CLI, the schematics are going to do a couple things. All right, do you want to enforce stricter type checking and stricter bundle budgets in the work space? Yes. Because we like our code quality control. Y'all wouldn't believe one of the codebases, they have not used TypeScript. It's like buying a truck with four-wheel drive and using two-while drive to go through fields. It's absurd. Yes to Angular routing. I don't know if we'll use it in the application. But one of the things I enjoy about modern Angular is they have the router built in. This was not in AngularJS, you had to do routers and figure out what worked. Single page applications. We need a routing strategy. I really like this is built-in with Angular. And I know it's not necessarily in React or anything like that.
Jennifer: You can choose whatever styling language is your preference.
Jason: I assume we're not going to do too much. So, I'm just going to get regular CSS. Like a pleb.
Jennifer: Like a pleb that I want to throw a bunch. Any time I ever see CSS as the default choice of a client codebase, I'm like, okay. We're dealing with backend engineers here that don't know how to write styles.
Jason: I love my plain CSS.
Jennifer: If you're using a lot of built-in third-party component libraries, I think Angular material is built in SaaS.
Jason: Oh, okay.
Jennifer: Yeah. Sometimes it can be easier because if you're doing any custom formatting or overriding or anything like that, sometimes it can make sense to stay in parallel.
Jennifer: We are sometimes seeing really heavy consumption of UI libraries, right? Where companies don't have time to build their own UI libraries, don't have the considerations or a design staff to think about building a coherent design system. So, I think that consumption is really, really heavy in the Angular community.
Jennifer: Yep. So, I so that you have opened your app. And let's kind of just give everybody a little overview --
Jennifer: Of what exactly has been generated for us if VSCode decides to get its shit together.
Jason: What is it doing over here?
Jennifer: Oh, no!
Jason: Oh, no, beach ball. Do I have something running? What is happening right now? Okay. Make let's just try that again. Let's -- let's just close code. Okay, bye.
Jason: All right.
Jennifer: I did -- I was trying to stream a little bit last year before some work stuff got crazy and I had an older laptop forever. But like I could not stream. I could not share code in Google Hangouts or do OBS. Table flip, aisle getting a new computer.
Jason: I think I had a runaway process. When I quit, it opened up.
Jennifer: What's going on, you have the source code. But there are things to point out to people new to the Angular ecosystem. One is the Angular.JSON file. Where the options for our different schematics and things are available. So, any pre-set modes you've picked like, for instance, you see strict mode, we opted in as true it's going to be there. If you picked less or SaaS, that would be indicated in the file. This is what schematics that you generate are going to look at to get information how to compile the code. We have a couple of things. Under architect, we have build props with information on how to build the code. We have any additional styles we might be bringing in. If you are having to bring in specific scripts from a Node library.
Jason: Oh, my global styles. I put them here. Got it. Okay.
Jennifer: Yep. And this is just a thing I like to call out bauds, you know, if -- even if you are an Angular developer, let's say you've got dumped on a project that's already existing. You may never have touched this file in your life and may not know what it's doing. We have that. A couple different production issues here. One of the things that I like that Angular rules with, they create this environments folder for you and automatically environment the environment.ts and the environment.prod.ts. It's built in. And you have the head versus the production API. That's wired up and ready to be pulled from the environments file. In frontend development and building the applications, it's solving the problems over and over again. Angular has dealt with a lot of them.
Jennifer: A couple other quick things, another complaint, scroll back up, sorry. There was a budgets prop here. This is setting default sizes for our component styles. We're going to get warnings and errors if our components exceed a certain size. Yep. These are really, really helpful because a lot of times you might be writing code and midnight not be thinking about the performance applications that's gonna have. And again, some of the compliant projects and the highly imperative code, that shit can sneak up on you and you don't realize it.
Jason: This is clever. This feels like the thing, of course, why wouldn't we do this? This is great.
Jennifer: Yeah, and personally, I love this. Because a lot of times in client projects, they're hiring us because they need us to fix their shit, right? We're coming in probably as a more competent development team and want to get best practices in place. We can use gatekeeping techniques like this to throw warnings on the codebase and use those to safeguard when you have different team members crash into the codebase and have no idea what they're doing. So, a lot of great options like that. And we have this down here, the cool thing is we don't have to do anything in particular to serve and live reload our app. That's all built in. You can do additional to modification. The CLI is being consumed by Webpack. Webpack is the tool being used under the hood to compile assets, to do bundling, yada, yada, yada. If you did AngularJS, I implemented Webpack to get it up and running and I was crying myself to sleep for like a week. It was a disaster. And this shit just works. Chef's kiss. Every time. So, just kind of calling out the black box magic. Webpack is going to use the base level configs to use the magic. You can do additional integrations if you need to use custom plugins for any sort of thing. That is all there. We have some stuff for internationalization. We've got, you know, servers for doing our testing. This is at a unit testing level. So, all sorts of cool stuff going on in there. Yep.
Jason: Linters, end-to-end tests.
Jennifer: Yeah. These are tied to our command. We did the NG new, any time we do an NG, it's going to look at this to get the linting rules.
Jason: So, something just clicked for me. Which is what I put in this Angular.JSON, this is the command that I can run. Would you like to share anonymous data usage? Sure, Google. You can have my data. And then it lints.
Jason: Cool. Okay.
Jennifer: So, these are providing that customization or that information for these different things to run.
Jason: Nice, okay.
Jennifer: Yep. Yep, yep, yep. If you have never touched this before, you have no idea. And whoever researches this thing. I figured we would drop some knowledge nugs here.
Jason: And I can run NG serve and it's going to work.
Jennifer: Why don't we do that. NG serve and see what the team has delivered us that's going to be ready and available in our browser. What power shell are you using? iTerm2?
Jennifer: Like a boss.
Jason: I got turned on to starship RS, it shows the Node version you're using and what branch you're on.
Jennifer: I like it.
Jason: It makes me so happy.
Jennifer: Question. Does it track what npm registry you're on?
Jason: I think there's an option for that. I don't use custom npm registries, but I don't. I'm pretty sure I saw somebody set that up.
Jennifer: I like to do that. I have projects and that will show me, why won't my npm install work? You're on the wrong registry, idiot. Nice.
Jason: It's a really nice one. There's a whole bunch of cool stuff. It's also very fast. It's a Rust deal. And then if you want to see -- to anybody who is interested. I have a -- I have all this stuff. Where is my -- there's my .files. You can see my Starship TOML system there. If you want to copy and paste.
Jennifer: This is so much fun. You get to see the cool tooling that other people use that you never allocate time to during your day.
Jason: For real, I pick this up all the time. Somebody will be on, and run this command. What is that command? How have I never known about that?
Jennifer: Do you remember when the synth wave 84 theme for VSCode dropped? So, that dropped like right before I was giving a talk at ng-conf. I put it in the last slide of the conversation talk. I know people are going to ask what this theme is.
Jason: My favorite was watching the Internet trying to get the glow to work. Nobody could get it to work. It was amazing.
Jennifer: And every time you get it to work, and you're code sharing, ew! Why is it glowing? How can you read that? Bitch. Get off my vibe. We are super-off track.
Jason: In the context of this show, we are ahead of schedule, I think.
Jennifer: Oh, fabulous, all right. Yeah, so, we can go ahead, boot up local 4200 and this is our Angular application is nice and served for us.
Jason: Look at that. It's beautiful.
Jason: So, this is gonna come from app, I assume. And then if --
Jennifer: Yep, let's go code Splunking. Here is our basic structure. We have our app.module.ts. This is the root application module. In Angular, you organize the code into modules. We will use them to encapsulate features. But it's a way to share code we have written or code that is provided for us by the Angular framework and, ooo -- I like that you have the different sizes in here. I'm so creeping on your editor and setup right now. This is great. All right, back on track, Jennifer. All right. So, this is our kind of home base for everything going on. And so, we've got a couple different things going on inside of this NG module. We have our declarations which is where we're going to list any of our components that are going to be used by this module. We've got our imports. This is where we're going to import any modules that are used by our components that are declare ready inside this module. So, we've got a couple basic ones here. We've got the browser module which is provided by Angular. Some really common ones that people are going to be using are HB client module. This is the module that has a service for us to make HTTP requests. Another really common one is going to be the forms module whichever forms module we decide to use to provide us with that functionality. These modules are bundling all sorts of different codes. As we get more into Angular development, I'll talk about these things. For instance, if we're in a component, we might be using what are called logic or structural directories. If you have seen NG if and a statement there, those are directives. And provided by a common module that we'll probably end up having to import. I never remember what lives where. I wait until the compiler yells at me and import what I need.
Jason: The compiler will tell me. I don't have to remember this, it will be like, you're missing a thing you need. Install this.
Jennifer: Yes. As an example, let's go into our app.component.HTML file. This is the app component exported there. They have the HTML that's generated and dumped in a bunch of stuff. Right?
Jason: I love this. It's almost a haiku. The content below is only a place holder and can be replaced. It's a haiku.
Jennifer: Is it? Nice.
Jennifer: Oh, that's great.
Jason: I bet that was intentional. That was great. I love it. Comment, like insider comment stuff makes me so happy. Because this -- this is how Devs do art. This is our finger fainting. Okay.
Jennifer: So, that reminds me, like a lot of times we'll did performance audits on the Angular website. But for our Botovia.com, we are use a third-party CRM. It's not built the best. And therefore the actual performance of our personal website is to the had great because we're coupled to this stupid CRM. I went in on our performance assessment pages. And so, if any developer pops open the Dev tools, do they know what they're doing? I have comments, please don't judge this page. Take it up with our third-party CRM vender. Because we're petty and we will look at source code for shit like that.
Jason: You're so petty. There was a link to the synth wave. I'm going to put up here so we remember to include it in the show notes. Synth wave.
Jennifer: 84? Okay, I remember it right.
Jason: Look at this fun. It's got the glow. It's beautiful.
Jennifer: Did you ever use the power-up plugin?
Jason: You know, I didn't.
Jennifer: As you typed, it would be exploding.
Jason: Yes, Sarah Drasner uses that one in her terminal. And so, she would be giving very serious companywide presentations where she would open up her terminal and there's like explosions and high score racking up. It's like, Sarah! It makes me smile, I don't care.
Jennifer: Oh, god, yeah. You got to take those little joys in life.
Jason: Okay. So, here, then, I can kind of -- we can kind of empty this out, right?
Jennifer: Yes. The only thing you're cared about that was generated here is a tag you will called router outlet. Fatherly close to the bottom. This is a lot of markup. And then we've got this router outlet someday.
Jason: Oh, here.
Jennifer: There we do. And this is what the Angular router is gonna look at and what it's going to use as a place to render content as we change routes throughout the application.
Jason: Okay. so, how about I do this? I'm going to --
Jennifer: No, don't do that. I'm just kidding. I'm just kidding.
Jason: You got me. I was like, now what did I do?
Jennifer: Aw. I have my dad's sense of humor.
Jason: Make a little one of these. We'll do an H1 and say, hello, chat.
Jason: And then we'll take one of these.
Jennifer: And then you'll -- oh, yeah, go ahead, sorry.
Jason: I don't know. I'm just going to text-align: Center or something.
Jason: And then take the H1 and do --
Jennifer: I would say even go even crazier and instead of this div, put it in the app.component.CSS file. Then you're a true Angular developer.
Jason: Okay. Nice. Let's do it.
Jason: Let's get that out of here. Then we can go into app.component.CSS. We can drop this in and see that. See what Angular did.
Jennifer: Did you want to style your H1? Let's make it pink.
Jason: What a good pink? Hot pink?
Jason: Oh, there's no way that passes accessibility. Make the -- let's make it stylish.
Jennifer: Deep pink. Oh, that's not bad.
Jason: Look at that. That's the move.
Jennifer: It's like I'm back in those GeoCities, days. Do we want to pour one out for the blank tag going away, by the way?
Jason: What we did do is in the chat you can use the marquee tag in the chat for the show.
Jennifer: Did I do it? No.
Jason: No, you have to write HTML.
Jason: Yeah, we found out a while ago that I had forgotten to do HTML escaping for my -- look at it go.
Jennifer: are we spelling it right? Is it working?
Jason: It only shows up on the overlay.
Jennifer: I see it.
Jason: I forgot to do HTML escaping. People would rewrite CSS on my livestream. It went very poorly.
Jennifer: Shit. That is delightful.
Jason: When I was doing the HTML, I left in marquee because that was very fun. This is not going win any design awards. I'm okay with that. If I go to my styles.CSS. I can do a body, margin zero. And actually, why don't we put the font stuff in here? And then we can do a background of black.
Jennifer: Because dark mode makes us a 10x developer, right?
Jason: Exactly. I appreciate that you saw where was going with this. Okay. So, now we have our -- our dark mode Angular app. I love the chat is just all about it.
Jennifer: Oh, gosh.
Jason: Wow. That -- the nested marquee is pretty wild. Good. But I'm into it. Okay. Let's -- is so, now, next, I think, what we want is let's get ourselves a something. Do you want to set up a form? Do you want to do a --
Jennifer: So, let's set up a form. And I want to challenge the chat to give us a use case. Like, we're creating a form. What kind of information are we going to collect with the user while you and I talk through what we need to do to start creating a form.
Jennifer: Let's do this in reverse and I will talk about the error stuff you were saying. Let's go into VSCode.
Jason: Leave the server running while I do this?
Jennifer: Yep with. Leave the server running. My flow is I will have it running in VSCode. Spanning through projects, I'm swiping through windows. And one of the cool things in Angular 11, if you have multiple Angular applications and go to serve up a new one, hey, you're running an app at 4200 can I set you up in a different port. You know what, Angular? Yes.
Jason: I sure would.
Jennifer: Thank you for comping the attitude of my running too many projects at a given time. Okay. Anyway. Let's go back in here and let's go ahead and let's create a form. And so, we are going to create a semantic form. We're going to start using our form tag.
Jason: Okay. So, we've got a form. And then am I setting it up like one of these?
Jennifer: No, just do a -- nothing like that. We'll just do it and build from there.
Jason: Got it. Okay.
Jennifer: Okay. Cool. And our form is going to need an input. Let's go ahead and create an input tag.
Jason: Okay. What is the chat coming up with? I see a job application form.
Jason: That looks like the only -- everybody else is just doing marquees.
Jennifer: Thank you for the one person staying on track right now to help us. Oh. Gosh. Okay. All right. So, we'll have an input. And if we're doing a job CV, we're probably going to have a field for our first name.
Jason: Okay. So, we'll type it --
Jennifer: Equals text. And let's not use our name tag yet.
Jason: Oh, not use the name tag yet.
Jennifer: Well, okay. We'll talk about this in two different ways. But yeah. We'll just leave it like that for now. So, in typical, you know, if you're just creating a form on the web, you are going to use a name tag. And what that is gonna do is like when you're getting the value of your form that's gonna create that key with the value of whatever is entered in that input. So, just like so we're talking about things under the hood. Because you feel like one of the problems we have, especially for newer developers, is they're coming into like framework land, right? And sometimes that keeps you from thinking about the underlying core concepts that are just our basic HTML APIs and the way the Internet of the meant to work.
Jason: Yeah, okay. I gotcha.
Jason: I'm adding the for and the ID so that we have ourselves an accessibility semantic form.
Jennifer: Fabulous. We have a couple different ways to create some sort of binding. Because at the end of the day when we were building a form, we want to capture information from the user and do something with that information. Typically submitting it to an API.
Jennifer: And I like to call this out because sometimes people start with the UI in mind. They know they have to implement X, Y and Z features. And they forget at the end of the day, you are just trying to get information from the user that you're going to translate to the back end. When I see people developing forms in Angular, the number one thing I tell them it, don't start with the UI. Start thinking about the data that you need to submit to the backend and then work from there. Because they'll get really -- like, you know, just UI-happy and hooking everything up and being doing all this weird like where they're having to pull out certain values and map and glob together the value they want to submit. And it's more imperative, hard to maintain code.
Jennifer: All right. I thought I muted notifications on my Mac. I'm getting calendar invites non-stop. Calm your titties, people. Story of my life. Okay. So, back to our Angular forms. I'm going to kill you on this, aren't I? Okay. With Angular, we have two different form modules that we can use. One is called the template-driven forms approach and the other is the wrapped up forms approach. So, if you ever did coding in AngularJS. Template-driven forms field is really familiar. We have the NG model directive that we apply and we use that to get the value that the user has entered and tie it with it programmatically. I tend to do things in reactive form. That's what I'm more comfortable with. Both approaches are completely fine. Both implement things the same way under the hood. If you look at the code and the way things function, they are built on the same pieces what have Angular provides. So, just -- just know that there are two approaches there. Template driven forms is going to use NG model. Reactive forms are gonna use different directives. And typically the equivalent to an NG model is going to be called form control.
Jennifer: So, essentially what we're going to do is create a link between the element and the DOM to the, you know, let's just say variable that we want to access and be able to do things with and manipulate in our component. The first thing we're going to do here is --
Jason: The input.
Jennifer: Yeah, on our input. And I'm going to kind of work backwards and kinds of show you like some things that you will do. Inside of brackets, I'm going to have you type form control.
Jason: Square boys or --
Jennifer: Square boys.
Jason: Okay. Like this?
Jennifer: Yep. Sorry. Camel case. So, upper case C, no dash.
Jennifer: Okay. And then you're going to set that equal to FirstName. And we'll just -- no, sorry, after the brackets. There you go.
Jason: What? Like this? In quotes?
Jennifer: No quotes, FirstName.
Jason: Got it.
Jennifer: We're going to work backwards and do things goofy. I'm going to show you what Angular is going to yell at you about what understanding what to import in what module.
Jennifer: And now into the app.component --
Jason: It's yelling.
Jennifer: Don't look at it yet. We're to do things first.
Jason: App component.
Jennifer: And call it FirstName. So, under title, sorry.
Jason: Oh, okay. Yep.
Jennifer: Sorry, on our app component class, yep, FirstName. And send it to the string for now. I don't really care what's going on. Because I'm going to kind of show you what it's going to do. We have a variable. We have a member on our class that our template is going to be binding to, okay? So, go ahead and save that. And now let's go and look at our errors.
Jennifer: All right. So, this error is can't bind to form control since it isn't a known property of input. So, basically, what's happening is we're using this form control directive. But we haven't imported it anywhere. And so, our component doesn't have a reference to form control to know what we're trying to do here. And I feel like this is a really common error. That if you're jumping into Angular for the first time, you're going to see something like this. What this means is if you're trying to use a directive or a piece of Angular that you know exists and is available, you have to import the correct module that's going to allow you to access that directive.
Jason: Right. And so, that part happens -- wait. I remember.
Jason: It happens here.
Jennifer: Yeah. Yep.
Jennifer: So, what we're going to do in our imports array is we are going to import the reactive forms module. And so, I think with your plugin -- oh, bam! Look at that.
Jason: Look at it go.
Jennifer: Look at that! Look at that! So, we have a reactive forms module now. We can save that. And when this recompiles, we are maybe going to be happy again. Okay. So, now we have a different error. Okay. So, what this form control directive is looking for is for us to create an instance of a form control. And so --
Jennifer: One of the things that I advise people to have pulled up in the docs all the time dealing with forms is a single page on Angular docs. I'm going to have you go to Angular.io. And search for abstract control camel cased.
Jennifer: Click that first one. Any time we are dealing with building forms, the base building block of a form that we would tie to an inputs value, for instance, is a form control. We use form input and array to help nest and reflect the data that we would want to submit to a backend. We're collecting a CV, might have a FirstName and LastName key. And maybe an abstract key which is a nested object. We can use form group and form control to create that structure. And the reason I have you pull up this abstract control class, this is the base class that all the different instances extend. So, all of these properties, all of these methods where available when we're dealing form control, form group and form array. And so, I find -- this is a lot of stuff to memorize, right? And you will get this from the IntelliSense. I ask people to pull it up to see what is going on. They are reinventing the wheel because they are not aware what's available in the API. Documentation is hard. No shade on the Angular team, but it's hard to document every little thing, right? So, having a really good understanding of the base underlying API of how these things work I think is really key to you being able to build forms better in Angular. Cool.
Jennifer: All right. So, what we are going to be doing is we're going to go back to our code and create an instance of this form control to bind to our group. Oh, actually, sorry, I completely spazzed out. Let's go back to the docs real quick. I want to show you why. This abstract control is like let's just make it really, really basic if we think about like an object, right? It's going to have a value. Because at the end of the day, we have to get the value from the user. But building forms, there are a lot of other things to care about. We care whether that is disabled or enabled. Being able to know if it's enabled or disabled as well as being able to trigger enabled or disabled function key. A lot of times dealing with validation. We want to have a certain ruling, with based on XY and Z, this is valid or invalid. We want access to that. We want to set validation rules. A form control is going to manage the value that the user is given. So, we're creating that finding. But it's also managing its own state, okay? And so, that has to do whether it is valid. It is valid. And in the chat, somebody is asking about dirty and pristine. These are ways that we can track exactly what level a control has been interacted with. Let's say we want to outline some piece of our UI in red if an input is wrong. Fairly common use case. It's really, really frustrating from a user experience standpoint if everything is technically invalid when you first log in to look at a form, right? Because no information is there when we need it. It's really, really irritating when everything is in red, okay, shitty bank we said, I know it's invalid. If you want to show that status after you have clicked into something. You have a bur events, clicked into a field, moved away. Then it's appropriate to let the user know, hey, FYI, this is invalid. How user interacts with the form control, we can create a better user experience with how we're reflecting validation.
Jason: To repeat this back, pristine is before any interaction is happened.
Jason: Nobody's clicked on it or typed in it. And dirty is any interaction, including a focus event.
Jennifer: A good example of dirty is somebody typed something in. Or maybe typed in it and backspaced. Those are two differences. If there's content, it might be valid. But backed out, it's invalid, but not necessarily never interacted with. We have the ones like this, touched, untouched. These are just kind of properties like a way of tracking state on this form control that allow us to hook in and create, you know, a much better user experience.
Jason: Got it. Okay.
Jennifer: Yep. Let's see what else we have here. We'll probably flip back and forth to this documentation. But I wanted to give people a kind of base level understanding of when I say we're going to create a new instance of a form control, why that is and what we're doing.
Jason: Yeah. Okay.
Jennifer: Somebody is asking, is it dirty when you started typing with but haven't blurred the field. I don't remember the exact rule.
Jason: I think this is the sort of thing where we need to start logging everything and just check.
Jennifer: You might be able to get it from the IntelliSenser. But I don't remember. I tend to do a lot of stuff on touch. Let's go ahead and get this started. We have our FirstName. What we want to do is set this to an instance of form control. Instead of that empty string, we're going to back up. So, you can get rid of that. And then we're going to set FirstName equal to new. And then form control. Yep. And that should --
Jason: It autocompletes.
Jennifer: Cool. All right. So, that's like our initialization and then the second parameter that this would take would be validators and any custom options. But we're going to keep things simple for now.
Jason: We don't need any of those for now? Keep this as-is?
Jennifer: Yep. Do that. We compiled successfully.
Jennifer: I could say, hey, import forms module first. But if you were new, crashing into Angular -- a new codebase, and seeing the errors I wanted to walk you through what that's going to look like so people can groc, this is what it means it, and this is where to import and get it from wherever I need it.
Jason: Look at this, these are just linked. Like when I type in this, it's -- like we now have access to this value. We don't have to -- that's pretty slick.
Jennifer: Yeah. So --
Jennifer: Yeah, so, let's build a silly little use case. Let's add a new member in our component called LastName.
Jennifer: So, just similar --
Jason: New member, sorry, I was getting ahead of you.
Jennifer: You're fine. Change this. LastName, it's going to be exactly the same thing there.
Jennifer: Save that. Let's do in the app component and add that new -- yes, copy pasta for our LastName. LastName.
Jason: What am I doing?
Jennifer: I don't know. What are you doing?
Jason: I don't know why I made that so hard. I could have just typed capital L.
Jennifer: You're fine. Here is our little form. Let's add some ruling around this. Let's say that we don't even want our LastName field to be enabled until a user has entered a first name because we feel like micromanaging the shit out of them with how they're dealing with the form.
Jennifer: Change to true. We need to understand when that FirstName value changes to enable new ruling or cause something to happen with our LastName field, right? All right. So, let's go into our app component. And then what we're gonna do is we are going to add a life cycle hook. This is pretty common for Angular development. Angular is built on these different life cycle hooks that are running in different times during the component life cycle. So, what we're going to do because we are type safe is where we are defining our app component class, we're gonna say, implements on init. So, after -- yep. There. Implements on init. And I always get these backwards. Yep, hit there. This is kind of cool. If you're new to TypeScript, new time we say we are going to be implementing something, a type face, if we don't satisfy the requirements of the interface, we get the TypeScript warning.
Jennifer: It's inspecting ngOnInit to be in the class. Some cool ruling there. We have news guards with the TypeScript to make sure we're doing things right. So, ngOnInit is that. That's the method. And then type this to return void because this method is not going to return anything. Oh, sorry. I mean, type the -- or type the return type of the function.
Jason: I gotcha, I gotcha.
Jennifer: Okay. Okay. Yeah. There you go. Okay. Just because I want to teach everybody best practices while we go on our form adventure. All right. So, a lot of times, this -- this life cycle hook is going to run when our component is initialized. So, after the class has been created, but like the component has been initialized is when this is gonna run. So, we end up putting a lot of our functional code where we're interacting with something like this in our OnInit life cycle hook. I'm seeing, is the auto-import thing happening a TS thing too? Where it's automatically updating the import statements?
Jason: It should be.
Jennifer: I can never remember what VSCode is doing and what my plugins are doing.
Jason: So, VSCode uses TypeScript under the hood to do auto-importing. So, it is TypeScript, but it's not like because we're writing a TypeScript library. It will work in -- if you enable that setting, it will work anywhere in VSCode. It's more predictably good in TypeScript projects, though, because it's, like, the project is TypeScript all the way down.
Jennifer: Yes. It's delightful. And it's really helpful. I say to have the documentation pulled up. But the great thing about TypeScript is as you're importing the different modules and using the pieces of the Angular API, you're getting IntelliSense, which makes it really, really powerful. As an example, go back to the problem. We want to do something different. We want to enable the LastName input when the FirstName input changes and has a value. What you can do -- I like your code comments. I also like to include the why. Why are we going this? Because business has a stupid requirement. Like, I feel like a lot of times people will be like, oh, well, I should document what the code is doing. I want to know why the code is doing something. If you have written something a little bit squirrely, I want to know there's a purpose behind it to satisfy some bullshit requirement that's not detectable from the way you have written the code. So, why? Because we're the worst. Like when I'm reviewing pull requests for my team, and they do something weird, will are you add the why comment there. Yep, no problem. I forgot. Yep. Oh, gosh. Okay. So, the first thing we're gonna do is we're gonna get access to our FirstName form control. So, we can do this.firstname. And we get access to our component member.
Jennifer: Okay. Cool. This is if you do the properties and methods available to us because it knows this is the type of form control. So, you know, don't think I'm so the magic wizard or anything like that. I'm just as dependent on IntelliSense as anybody else. I have spent way too much time trolling through Angular source code to unlock secrets of Angular forms. So, anyway. We are going to get into a little bit of RxJS magic here.
Jennifer: So, reactive forms are built on top of RxJS. That means there is going to be an observable that mitts when the value changes on the form control. There is a value changes method we're going to use. I saw it a second ago. Value changes. Yes. Cool. And so, if you look at this -- sorry, I shouldn't have said method. That's not the proper terminology. Hover over and that it should give you the type of observable it's going to emit. It's going to emit an observable of many. Observables are streams of data over time. And so, RxJS is a beast. Have you done any RxJS talks on Learn with Jason?
Jason: No. We have used observables in a couple projects. But we've never actual like learned observables.
Jennifer: Oh, might have to hook you up with some resourcing there if that's of interest.
Jason: I think it definitely would be. I think -- because I don't get them. And I think it's something that would be very useful to a lot of folks, including me.
Jennifer: Like if you've heard about more declarative program organize reactive programming, it's a style we've started to adopt. Definitely heavily in the Angular side. But reactive -- or RxJS makes it really great to deal with reactive programming or do more reactive programming because we are dealing with streams. Whether it's a response from an API, whether it's interaction with a user. We can combine these things in a very stream-like way to write just very, very declarative code. And so, the idea here is probably everybody's used to write imperative code which is where you're constantly manually changing the state of your code. Let's say, you know, your state, you have a loading member on your component. An imperative approach, you would have a function that executes. Okay, this.loading and set it to true. And something else happens and you say this.loading and set it to false. A declarative approach is where you declare what the loading state is based on what these things happen. And declare on top of that with hippy love, yeah, you did. And the layer on top of that is reactive programming. Bringing together streams. Let's say form values changing over time as the user interacts with it. And using that as a part of our declaration to say what's going to determine the value of loading.
Jason: Gotcha. Okay. Yeah. I can see the value in that. I definitely think that would be a good follow-up episode to dig into this.
Jennifer: When my schedule calms down. Let's schedule a reactive programming session.
Jennifer: Sweet. I'm going to be that bossy bitch who is like, I think you people need to know about this. Anyway, it is an observable. But it's going to be whatever the user enters in the input. If you're used to thinking about this, dealing with inputs on change event. Every time a change occurs, it's a what the observable occurs.
Jason: Mike showed up.
Jennifer: He have Mike Harrington on deck. So, what we are going to do is subscribe to this observable. When we create this subscription, we will start getting any values emitted by this value changes observable. All right. Inside of this, we can go ahead and do another parentheses. And we'll just call this FirstName Value. All right. And then --
Jennifer: And just to give people a visual representation, let's just log out to the console what FirstName value is. Or if you want to print it somewhere or whatever you want to do that jives with your workflow. I'm a very visual person. I'm probably more console-log dependent than I should be. But it helps me map things better.
Jason: I'm all the way with you there. That is how I -- look at it go.
Jennifer: Hey, hey. Hot damn, hot damn, hot damn. Oh, my god.
Jason: Hey, what's up? Thank you for the raid.
Jennifer: One of my team members dabs all the time. It brings me joy. Another created a Jennifer rage emoji. It's like my head and it shakes. Anyway, quality culture. Okay. We have done something really awesome here. Now we have access to whenever the value changes. Hey, if FirstName has a value, then enable the LastNameControl and allow a user to interact with that.
Jason: Oh, okay. I can work out part of this. If I do like FirstName value.
Jason: .length is greater than zero. That's how far -- that's where I've gotten.
Jennifer: Cool. Let's be super-lazy and use our Intellisense. We know we want to access the LastNameFormControl. This.LastName. And then we want to enable our formControl if our thing has a value. Hey, look at that. There's an enable method. I bet that's the one we want to use.
Jason: Just like that?
Jennifer: Yep. Bam!
Jennifer: Let's see how that looks.
Jason: Ta-da! Hey, wait, you didn't go away when I said -- oh, because I didn't disable.
Jennifer: Yes. So, here's part of the problem that we don't love a lot about reactive forms is in Angular reactive forms are built on RxJS. So, they have observables. They are not necessarily reactive. They are still highly imperative in the way we have to interact with them. I hope actual forms are on the horizon for reactivity. But they are reacting -- reactive forms in name and not in true philosophical reactivity.
Jason: They're reactive charlatans.
Jennifer: Yes, exactly. So, you know, I bet you can figure out, yeah. What you need to do is else disable and go there. Kind of the hook we can have with value changes that are firing off and be able to make different things happen. There's a lot of control and there's a lot of power we have in here just from, you know, whatever kind of use cases we want to manipulate for our forms.
Jason: Yeah. It's really, really handy.
Jason: I can do something like this. Let's make it pretty.
Jennifer: This is always the hardest part of my talks. Or my talks. I want to create demo apps. I don't have the emotional or mental ability to make them pretty. Can I hire you to make stupid demo projects. A lot of them reinvolve around Animal Crossing. There's an API that was created.
Jason: Oh, nice.
Jennifer: A lot of them are with that API.
Jason: Forms are a bunch of inputs in a trench coat anyway. Yes.
Jennifer: Not wrong. No the wrong.
Jason: We have a form. Our form has some intelligence where we can saw, if I type here, I can put the LastName in. If I then delete this, I can no longer interact with this until I put a value back in here.
Jason: Good. That all makes sense.
Jason: What's -- so, I feel like there's a little more we can do here around like submission or --
Jason: Differences of inputs.
Jennifer: Let's start with inputs and work backwards to figure out better flows for implementing forms. Nice. Just before this talk, I sent a cat out of the bedroom because it was harassing the other cats. What you can do is you can bind a button click to your form. And then do a submission that way. But we're gonna just use a basic click event for our button and wire things up that way. Although I'll give you a second to update your styling.
Jason: Yes. Max width of we'll say 500 pixels. Make it responsive. Why not? And then here we can go with a margin of -- just center that up. And that should make this work. Not quite. Maybe we'll just make it a lot smaller. You know? You try to make -- you try to do something nice and then you're in a CSS hole. We want to go left now. And let's make our inputs and buttons 100% wide. Hey! Close enough. Kind of. Not quite. It's fine. We're gonna leave that. That's good enough.
Jennifer: Okay. Oh, man.
Jason: I know what I need to fix. But that's not what we're here to do.
Jennifer: Oh, god. This was how we go down rabbit holes. For somebody who just turned if had, right now we are talking about reactive forms.
Jason: Cassidy has arrived we can tell because I'm nearly buried.
Jennifer: Oh, shit, quality.
Jason: Oh, Cassidy.
Jennifer: Love it. Let's talk about getting the values of our form.
Jennifer: So, right now if we were to submit information about our user about their resume to a backend, we want to get the first name and LastName. Let's wire up the function.
Jason: Right now when I do it, nothing happens.
Jennifer: Let's just wire this up a little bit. On our button, do a click event. In Angular land, that's inside of a parentheses. Do click. And then we're gonna set that equal to my submission function.
Jason: Just like --
Jennifer: In parentheses -- in quotation marks. Sorry, I can't talk.
Jason: Like that?
Jennifer: Yep and then parentheses.
Jason: Oh, we just drop it right in.
Jennifer: Like we're executing a function. Yeah. Yeah, there grow. Like your calling it. Yeah. And why aren't we getting yelled at? Save that. Because the linter should be yelling at us for trying to call a function that doesn't exist because we love TypeScript. I love that. I love errors! Oh, come on, you know we've all been there when we're not getting errors. And you're like, what's wrong with my life?
Jennifer: Cool. Let's go into our component and let's wire up this function.
Jason: Okay. So, I need a function. I can just name this whatever I want, right? Or not name it whatever I want --
Jennifer: Submission function. Yep. All right. And let's go ahead and type that to return void. Because we're going to console log out of form value right now. So, I guess pop quiz time, Jason. If you were going to attempt to get the value of our form inputs right now, how would you do that?
Jason: I would do it like this.
Jennifer: Okay. Okay
Jason: That seems right. Let's find out!
Jennifer: So, you want me to wait?
Jason: Oh! Objects! No!
Jennifer: What you're actually logging out is the form control instance. This. FirstName is form control not the value of it. But. I bet your IntelliSense would tell you that there's a dot value prop on there that would control the current value of that current form control.
Jason: How do I prevent the default submission? Do I get an event in here? It's refreshing the page when I hit the submit.
Jennifer: Oh. you can do the event.default. I totally forgot about that.
Jason: Do I pass that in?
Jennifer: Yes. The way you do that, I think it's dollar sign event. This is stuff I will not lock in my brain that I look up every time.
Jason: Like that?
Jennifer: I don't remember.
Jason: It doesn't like -- event implicitly has any type.
Jennifer: Oh. All right. The people in the chat, I'm forgetting, dollar event. But, all right. Oh, man, we might have to force --
Jason: What I just make it a regular any? Will you leave me alone then?
Jennifer: It might yell at you. But we'll see.
Jason: Ah-ha! I have defeated TypeScript.
Jennifer: God. Ah. Nice. Nice.
Jason: Well-placed, well-placed.
Jennifer: Oh, god, this is great. I feel like there are all these other random nugs that I want to drop. But I want to somewhat keep on track while I watch the time. And doing something like this would get tedious in a quick hurry if we were having to just access every different key that we want doing something like this. So, this is where some of our other available directives come in handy. What we're going to do is create a new member on our class and call it my form.
Jason: I should probably put this above the function, huh?
Jennifer: Well, I kind of want to throat punch you for doing shit in a weird order.
Jennifer: Just kidding. We're going to do my form. And set this equal to new form group. What this is gonna do is a create an object and expect whatever we pass into the object to be something. A form group or a form array. Yep. Your autoimport there. Here what we're going to do is do FirstName as our key.
Jason: And then do I pass in like that?
Jennifer: No. We're -- I guess technically, yeah. You could do that. I mean, if it was like -- like if I was doing this from the get-do, I would just go ahead and do new form control and not have them chunked out like that. But your way works because it's still just a reference it that.
Jason: So, we can consolidate this, then?
Jennifer: Yes, yes.
Jason: Let's consolidate.
Jennifer: There's a step further to consolidate. I'm worried it might be too much of a rabbit hole. But there's something in Angular called form builder that gives short hand to build this. Let's do it this way for now. This is a learning session and I want people to understand the basics.
Jason: Let's do that. But some homework for y'all, go figure out what form builder is and does. We have FirstName and LastName. This obviously will not work anymore. Will it continue to work in the component?
Jennifer: So, no. It will not continue to work in the component. So, we have to kind of redo things there.
Jennifer: What we want to do for the parent-level form group is bind it to a container where everything inside of that container is going to have access to it. In this case, it makes sense to put it on our form. So, we can use the form group directive. Inside of your square brackets, you do form group. Yep. And then had you can pass it the my form. Whatever we called it.
Jason: My form.
Jennifer: Yes. Look at that IntelliSense. Hot damn, hot damn. Cool. So, now save it and you're gonna get an error. And we'll kind of look at this. Because I want to kind of walk through -- people through the changes we're working. Okay. Property FirstName does not exist on app component. That is correct. We no longer have a member on our component, FirstName. We have a member on our component, my form group, which is a nest of form controls. So, there are two different ways to solve this. One is get programmatic access from our my form object. Instead of FirstName, do my form. Dot controls. Dot FirstName. Okay.
Jennifer: So, there's a controls prop on our -- our form group. And that's gonna have a list of anything inside of our form group. Whether it's a form control, form array, whatever. This is a way to get programmatic access. This is not super-readable and I think it's really, really intimidating to people newer to forms. So, what's really cool is we have a different directive that we can use that is kind of a getter directive that we can pass a string to. So, instead of form control, get rid of our -- your brackets there and we're gonna call it form control name, camel cased. All right. And then what this directive is gonna accept is a string. What it's going to do is attempt to look at its parent object. In this case, our my form, and find a string, find a key in it is that is FirstName.
Jason: Got it.
Jennifer: This is much more readable, in my opinion, way, to deal with these complex forms scenarios. You can have my form .controls, it's just nasty. Versus you can use the form control name directive that's more readable, a little bit more friendly. All right. So --
Jason: Oh, wait. I'm getting ahead of us now.
Jason: We're not getting errors around this anymore. But we're getting errors around our change.
Jennifer: Yes. And that is again because we're trying to subscribe to the value changes of a member of our component that no longer exists.
Jason: Are we doing this one here?
Jennifer: Yeah. We can do that way. Controls. Or we can do my form.get and pass in a string. Two different options. I don't have as much of a preference here.
Jason: I feel like I like this a little bit -- this feels a little bit more --
Jennifer: Human readable?
Jennifer: This is a TypeScript thing. The deal here is TypeScript is not able to determine from this string what type this might be. It doesn't know -- it just doesn't know what it is. A lot of times what I'll do is here is create a variable inside of this function called FirstNameControl. Okay. And I'm gonna set that equal to this.my form.get, FirstName. And tell TypeScript what it's going to do. So, do itas form control. I'm telling TypeScript, hey, this is what it is. Now if we replace is that with form control. TypeScript says I know this is a form control, I know it has a value changes observable. And also more readable, because reactive forms are truly reactive, we have to do some imperative coding, drama, and you will be referencing the same form controls over and over again. This is a good pattern to get into is, you know, essentially A-listing your controls that you know you're going to be accessing over and over and over again.
Jason: Okay. So, this then, we're back in business again.
Jennifer: Hot damn, magic.
Jason: But I don't know the -- we don't have the value back. But we can submit.
Jennifer: Right. So I want to back to what I said about that abstract control class. And then everything weather conditions tends that form group, form array. The same way we're using that dot value on the form control, we can use the dot value on the form group, what it's going to return is the key value fair of whatever the key is whatever the value is of the form group, control or array.
Jason: Okay. If I do this.myform.value.
Jason: We'll just find out what that does.
Jennifer: Yep. And you're going to want to restructure your console log base on this. We'll see.
Jason: Oh, look at that. It gives me the name. How did it do that?
Jennifer: What do you mean?
Jason: Wait, I'm a doofus. I was like, it's learning! The computers are thinking!
Jennifer: No, we are. Oh, boy.
Jason: Okay. So, then I can do something like FirstName, LastName equals this, my form values. Nope. Value.
Jennifer: Value, yep.
Jason: And then down here, we can get back to what we were doing before.
Jennifer: Yes. That being said, typically if you're dealing with forms and you're gonna be wanting to submit like let's say an object to an API. And so, that's a mistake that I see people making is like they -- they, again, start with the UI instead of understanding how to structure this using form group, form control and form array to build that data structure that they want to ultimately submit to the backend. That way you can just call dot value in the parent-level form group and not have had that this mapping and pull out this value and not use that value and that kind of thing.
Jason: To look at that in a more what we would send to the database way. We can stringify this.my form.value. And make it a little bit easier to read by prettifying it a bit. We can send this directly to the backend. That's pretty handy.
Jennifer: Yeah. This is a again a mistake I see people making. They get really hung up on the UI part of it. No, hang on. Think about the data that you're trying to collect and convey and then work backwards from there.
Jason: Yeah. This is -- I mean, this is really, really nice. Like, I'm a big fan of this approach. And I mean, we, like, we've hit the end of what we're going to be able to do today.
Jason: But there's a ton of like -- you can see here how like the conventions are here. The base building blocks are here. The fact that we ran one Angular command and then everything else just kind of worked as we could inned stuff and Angular yelled at me whenever I didn't import something and didn't know what to include. That's really, really handy. And you can see why this is a good way to go.
Jennifer: Yeah. Real quick I did see something in the chat that I would not recommend as a good thing to do. I want to call that out just to be informative. Somebody said if TS is explaining complaining about it not being defined, you can add the exclamation. I have a blog post when You should it and not use it. Do not use non-null to get around this. I can send you the link.
Jason: Where is it?
Jennifer: It's -- that one. That will link to the Dev too.
Jennifer: So, I want to call that out because that's not a best practice. A lot of times we're using this when things are actually declarative. I want to give an example of what it's an appropriate time to use a non-null assertion operator in Angular. Go back to the code. I want to do this because was fighting with a client about this and the problems it causes. All right. Here where you declare title, get rid of initializing it to anything and just have it be title, semi colon. All right. You're going to get an error because we haven't defined it, right? Go down into the NG life cycle hook and set the title to be Jason is awesome. All right. So, this is a really, really common pattern in Angular. Where a lot of times we won't be assigning a value to something until our life cycle hook executes.
Jennifer: Let's go back up and see that TypeScript error. It's still there. Because TypeScript is not aware of Angular's life cycle hooks. This is a case where we use the operator, that exclamation mark, hey, we're not declaring a value here. We will later on in the life cycle hook. That is a use case.
Jason: No, I'm definitely doing this wrong.
Jennifer: Do the exclamation mark, sorry, before the colon.
Jason: I've never used this in TypeScript. I'm learning today.
Jennifer: A couple things here. Declare -- assign a value to this in the constructer function, TypeScript can determine there's a value. But a lot of times in Angular, we are doing the hooks. We are telling the TypeScript compiler this is not defined. Do not use this for to get around TypeScript errors when you may or may not have something. Some consultant will clean up your code and drink heavily and cry themselves to sleep. Yes, it's a way to get around the TypeScript compiler. But your goal should not be get around the TypeScript compiler. It's there are to help you find errors that you don't know you're creating. Understand the reasoning of what's going on under the hood. I saw that that the chat and I was like, no! Let's make sure we clarify here. That's a good example is not typing any to get around stuff even though we kind of did that with our event handler. But it's okay for now.
Jason: Mike just out there trolling in the chat. So, lightning round of wrapping up because we are out of time. Everyone, go and follow Jennifer on Twitter immediately. Or else! Also, you can always check out the show. We have live captions all day, thank you to Amanda for hanging out with us, she's from White Coat Captioning. Very much appreciated. And that's made possible by our sponsors, Netlify, Fauna, Auth0, and Hasura. All kicking in to make this show more accessible. Make sure while you're on the site, go and check out our schedule. We have so much good stuff coming up. Add the add on Google calendar. We have Nathaniel Okenwa next week and Shaundai Person, and learning about Twilio, and functional style with components. And then next week we have Ben Hong doing a take yore. Two episodes, one on workflow automation and one on note taking with Obsidian. They are fascinating. Please check those out. Jennifer, anywhere people should go to check out about how or what we talked about today?
Jennifer: Go to Jennifer Wadella.com. ng-conf is in a week. It's online. I'm doing a talk on template versus reactive forms. My blog is a little bit out of date. I have not been getting stuff posted to there.
Jason: It's currently down.
Jennifer: It's your fault. It's in Gatsby.
Jason: I did it.
Jennifer: Yeah. But I do a lot of blogging on Dev 2. That's where most of my current technical content is.
Jason: Okay. Let's find... people. Did I get it wrong? Here you are. Okay. Go, hit that out. Check it out. And that is all the time we have today, everybody. Jennifer, thank you so much for hanging out with us today. This was an absolute blast. Chat, as always, thank you for giving us some time. We're going to find somebody to raid. We'll see you all next time.