We recently kicked off our "Kendo UI DevChat" series on web development. If you missed it, check out the replay as we answer questions we couldn't get to live.
This week saw the first installation of our "Kendo UI DevChat" series aimed at tackling important topics around web development with a hands-on, code-only, presentation style. This first webinar was a session on best practices around building user-friendly forms with Angular. While focusing specifically on Google's Angular framework, all of these best practices can be implemented in any web form and could work across server-side (ASP.NET Ajax, ASP.NET MVC, JSP, etc.) and client-side implementations (jQuery, ReactJS, VueJS, EmberJS, Aurelia, etc.) alike. I wanted to summarize the event in a blog post to not only share the recording and project we created but also answer some questions that came through.
If you were unable to join me for the live webinar, or just wanted to see it all again (who wouldn't!?) we have the recording right here on our YouTube channel. For those of you who prefer to read instead of watch, we've also included a transcript below.
As for the sample project, you can find it right here on GitHub.
There were a ton of questions asked during the webinar but I wanted to highlight a few of them here since I think anyone that has watched the webinar will find them useful.
Which version of Angular and Angular Forms was this?
This particular webinar used Angular 4.2.2. The package.json for the solution has set up the Angular reference as "^4.0.0" so it should remain within 4.x.
Will this work with reactive forms?
First off, in case you're not familiar with Angular's reactive forms, here's a quick link to the Angular documentation. While what we did during the webinar was an example of a template-driven form, all of the best practices we brought up in the webinar will work for any type of approach to creating forms. So, with some tweaks to the approach (to make it reactive) we can still re-use most of the code from the webinar.
Are there best practices for what to do once a form is submitted? E.g. going to a new screen, popup message, etc.
We did just take a look at the form portion during the webinar and the answer becomes "it depends." This form could have already been in a popup, or maybe it was just a sign-up form. What to do next pretty much depends on the application requirements, but I would say that transitioning to the next screen is probably the most logical. If you want to have a success message I encourage that to be under the button area with green text stating success, then moving on to the next screen. A popup to declare success is too distracting.
What is your approach for nested forms validation using Template Forms you used?
Nested forms would most likely involve another Angular component rather than having a single overly-complicated component. We can then do validation within each of the components independently. Also, since we are doing validation on a field-by-field basis (rather than the full model upon submit) this also reduces complexity of validation in this case. Absolute worst-case scenario, if you need to communicate between two components, you can set something up in your service layer to deal with the communication.
If this would be a child component. How would you respond back to the parent component? What's the best practice to use this within another component?
The above question is pretty much related here. For any communication between Component A and Component B in Angular one should work with the service layer to push information back and forth. Rather than passing information from parent to child (or vice versa) I would suggest having the parent send information to the service layer and have the child pull data from there. You can of course pass data between components directly if need be. This documentation article in the official Angular docs dives more into this topic.
What is the best practice to set fixed height for validation (error) message? So that it doesn't move all elements below it.
This is something that I did not do in the webinar, but it's a great idea and I wish I had included it! Yes, not making the form elements move around is also a great practice in forms. Any kind of movement or shift in elements placement can be distracting to the user.
Are there other k-classes for laying out labels to the left?
Yes! Instead of using "k-form" we can use "k-form-inline." There's even more classes to use for forms so I recommend reading over the Kendo UI for Angular Form documentation section for more information.
How heavy this application becomes at the end with all those libraries loaded?
While yes, I did leverage Kendo UI for styling for my form elements, I did only include two actual widgets, the DatePicker and the Switch. For everything else I was merely using CSS classes to help improve the look and feel—even with the form layout! So, we're not really adding any bloat to the project since we're working with CSS classes to spruce things up a bit.
What IDE you are using and how we can leverage the Kendo UI components in this IDE
For this demo, I was using Atom, but you can use just about any IDE out there to work with Angular and Kendo UI. Visual Studio, Visual Studio Code, Sublime; really any text editor can work with these technologies.
Prefer to read instead of watch? Here is a transcript of the webinar.
00:00 Carl Bergenhem: Folks join in, but welcome today to this Kendo UI DevChat, the first of it's kind. And today we're going to be talking about building user friendly forms with Angular. And I definitely appreciate everybody taking the time today, whether it's in the morning, whether it's right before lunch, maybe it's in the afternoon, to join me today as I walk through some best practices around building user friendly forms with Angular. Just as a quick note in terms of who I am and what brings me here today. My name is Carl Bergenhem and I head up the sales engineering team here at Progress/Telerik. And I've been working with Kendo UI since it's inception and been actively involved in a lot of web development throughout my entire career.
00:39 CB: And the reason I'm here today is specifically to talk about not just, of course, Angular itself, but how we can start building some user friendly forms. I think I have at least a little bit of an idea of how to build these forms as a couple of the applications I've built tend to have a lot of forms in them. If you want to go ahead and find me on Twitter, you can find me at @carlbergenhem. You can feel free to tweet me, talk with me, whatever it might be, and I'll definitely be able to respond back. Or, you can just follow me to have some potentially interesting nonsense to be thrown your way. That being said, this is all that I had planned for slides.
01:15 CB: I want to jump straight ahead into what we actually have to work with today. I'll go ahead and open up a couple of my windows that I have here. What we'll be seeing here today, and this is the main environment that I'm going to be working with, is that I have an application that's actually been setup with the Angular CLI. And then on the left hand side here, thanks to hot reload, we'll see that for example, if I just remove this form here, let's see that if I save that, will automatically refresh. For those of you that aren't too familiar with what that process looks like, just for the folks that might not have actually installed the Angular CLI in the past, everything's done through NPM, so you just do NPM install, if I can spell. And then do the add Angular CLI, and then you're off to the races, you do an NG new, whatever the project might be. And then this is the project that you're served with.
02:12 CB: Now I have done a couple of things ahead of time. What we'll see first of all is that if I go into the application folder here, we'll see that I have a shared folder where I have a user.ts. This is going to be my main model that I'm working with throughout the project. It's simple but we have to keep it a little bit on the more simple side in order to be able to make sure that we can cover everything in the time allotted here. We have an ID, and we have a name, date of birth, address, which is just going to be essentially a street address, ZIP code, newsletter and gender. Now, I know that some models might be a little bit more advanced, but this is to showcase some best practices when building a form, and not necessarily, how can we create the most exact real world replica of a form that we might have in the real world, right.
02:56 CB: Now, alongside with that user.ts in my main app, that component, I've done a couple of things. I've imported said user, we'll see here that we have import user. And then I also have setup just within the constructor, just as soon as we go ahead and kick off this component. I've added this stuff for a model and I've just set that up as a public variable that I can access very easily when working with the demo. Right now, this is all set to essentially null, or zero, or whatever it might be. And, then I also just have an onsubmit which we'll use at the end. I'll go ahead and not actually post this back to the server, but I'll go ahead and actually do something just for a quick console.log. And, that's really the main two bits that I'm going to be working with.
03:41 CB: Now, I'll be doing some coding, and also some copying and pasting. To get everybody ready for that, what I'm going to go ahead and do is, pop over to my other screen here and just copy and paste in some code. Now the reason that I pasted this in is that these are just regular input elements. Where we see we have a regular input for the full name, we have an input here for the radio. We'll see that we have female and male, because I have gender. For date of birth, right now, we also have an input element, and then same thing for address, ZIP code. And as the last piece here, we have a check box which is going to be essentially a "billing address is the same as the shipping address" kind of a check box for us here.
04:23 CB: Now, what we have here looks a little bit plain. And, additionally, something that we'll see is that this isn't really taking advantage of any kind of best practices in terms of layout or look and feel. And in order to be able to cut down on some time, I'm actually going to import a solution in order to help us to create more interesting looking forms and interesting looking UI elements. And, the way I'll do that is actually working with a client side library called Kendo UI, specifically, Kendo UI for Angular. And the main reason for this is just I don't have the time to style individual input elements and go through and create interesting text boxes, etcetera. And Kendo UI provides a lot of that out of the box. Now as we can see if I just take a look at the list of UI components here, we have some buttons, we have some drop downs, we have some date inputs, some regular input elements. And that's what I'm just going to take advantage of today, in order to be able to make sure that the form comes through and looks pretty interesting for everybody.
05:21 CB: If I minimize this we'll see that if I pop into my IDE here again and go into app.module. I've actually included a lot of what we want to work with. So I have a date input module, input module, button label module, all imported from the Kendo UI library. And this can all be done by going to that main page. If you're interested in learning a little bit more about Kendo UI, find that main page and then each individual input element that I used actually has instructions for how you can install it. And that's all just going to be done through NPM install each individual libraries. So date input, inputs module, button module, label module. Just so you know, that's where some of the, I guess, the smoke and mirrors can come from, it's just the fact that I'm using this library in order to be able to help enhance some of the look and feel. As we were talking about the best practices, I'll still be able to, of course, make something pretty come out from this.
06:14 CB: With that being said, let's start maybe applying some styles to this. The first thing that I'm going to do is actually apply a quick style here to my first text box. We'll see here that this full name text box actually changes into something that's a little bit more interesting to take a look at, right. I'm already seeing some improvements here, and I'm actually going to copy and paste that into these other text boxes, as well. Going to go ahead and save that.
06:46 CB: And what we'll also notice here is that right now these get a little bit improved in the styling, but right now this radio box that we have here and the check box, they're still the same plain Jane boring scenario. So, what I'm going to go ahead and do is, for this particular case, Kendo UI actually provides me with a way to be able to style radio buttons and check boxes, as well. I'll just go ahead and provide a class here, k-radio. And then for the label itself I'm going to go ahead and provide a K radio label. And what we'll see here, of course, as we go through here today is you might see me stopping for some things because we are doing this live, so hopefully the demo gods are happy with my sacrifices this morning, and we'll be able to go through this demo without too many hiccups.
07:40 CB: I'll do that for both the male and female radio buttons here, so we'll see now that this is getting a little bit more styled. And then finally for the check box, I'm going to go ahead and just do a couple of things here. I'll give it an ID, I'll go ahead and also give it a class. Also set checked, to checked, and I'll also provide a label for this, so I'll do class equals A. Find the four, and then billing address is same as shipping, let's say. All right. Now, that we have that setup here, we'll see that all these elements are a little bit more styled, and we have something that looks a little bit better. We're still constrained to having everything in a column, nothing's really laid out for an overall form, but at least we have the elements input here, and we can start working with this a little bit.
08:49 CB: Now, one thing that I'll pop in here and take this opportunity to talk a little bit about some best practices, is that what we'll see in these inputs here right now is that, eventually we'll have labels for these, but right now for the input elements we might not necessarily just want to have what we'll have for the labels. So, full name, date of birth, ZIP code, address, these will all be labels that we apply to input elements. And a best practice for the user experience for form is to maybe come up with, not necessarily just a copy and paste of the label, but some information. Or, maybe a hint around what you want to be able to do in this particular input element, what you want to input. So, for example, instead of full name, we can write John Smith, if I can spell Smith. Instead of, for example, address we can do 123 Sample Street and then ZIP code, we can do 01234. Go ahead and save that. And, date of birth, we're going to actually make that something completely different in a bit here. But, for all these other elements, this helps out our users to understand not just from what the label is providing us, but also get an understanding of, okay, what is this form looking for?
10:03 CB: Additionally, you'll notice that right now I had the intention of working with a full name rather than providing first name and last name. And this is also something that's important to do when we're dealing with user friendly forms. We don't want to inundate the user with having a ton of different form elements that they want to go through or have to go through in order to be able to fill out. So, we want to be able to maybe as developers take off that burden from them, and maybe do some additional coding on the behind the scenes in order to be able to extract that information. If we have a database that requires first name and last name, we can still provide a full name and be able to then later extract that, using some potential regular expressions or whatever it might be, to come out and actually pull out that information.
10:46 CB: Same thing actually with what we have here for the address field. Instead of having 123 Sample Street and just trusting that the user is plugging in their information, we could potentially use something like Google Maps. That way you can actually type in the address and it auto completes the address for you. That means you can even forgo the ZIP code field, and you can have a single input element for your address. In this particular case I'm not going to do that just for the sake of the time here, but that's one way to reduce the overall elements that you might have for shipping and billing, for example. Same thing with this check box. If we have automatically take the basic scenario and the most common scenario, that the user's billing address is the same as their shipping address, we're already saving our form elements. But for this particular case you could also just do the ZIP code, because the ZIP code, you can very easily extract the city from that, so you don't have to necessarily provide the city field.
11:35 CB: Everything that we do, we need to start thinking about, okay, how can we potentially make the lives of the user a little bit easier, because that will help us with overall completion rates. And that's a really big important thing when it comes to forms, especially if this is for a public facing website, not necessarily something that's internal, we want to be able to make sure that we can pull that out.
11:56 CB: All right. With that being said... Oh, one more thing actually. We see here that we have male and female. I want to make sure that you come across this webinar and you say, okay, when I have three or less, one, two, three, or less items, I always want to have a radio box or a radio group, instead of having a dropdown list. Drop down lists should not be used for two elements, should not be used for three choices. Four and above, that's when we can start looking at drop down lists, or maybe multi select forms, whatever it might be. But, if we just have one single choice that we have to make from three or less choices, we should always use some sort of radio button here.
12:35 CB: Now, also for date of birth, right now I have an input element that I could actually write just about anything into. But, I think a little bit easier for users to handle dates would be to, maybe either have a dropdown that allows you to select the date or maybe a calendar. In this particular case we can actually do both by providing a datepicker. And, the way this works is that Kendo UI happens to have a datepicker out of the box, so I'm just going to go ahead and use that here. You can see I'm just using a simple tag here for Kendo datepicker and I need to close the tag, as well. There we go. And, now we see that that input element actually transforms into something that provides us with a little drop down here that opens up a calendar. And, I can now go back and say someone was born on the 10th of January this year. I can go ahead and have that be the date of birth here. So, instead of having three different drop downs, one for the day, one for the month, and one for the year, and having them cascade, maybe do year, month, day. I now have one single element that just has a nice and easy to use interface that folks can click around in, and just makes it easier for them to be able to modify. If I want to, of course, I can still potentially type through here and go into 2016. So it gives users the ability to type as well as select an item.
13:56 CB: All right. The form is starting to take place a little bit here but it's not 100% necessarily where we want it to be, because right now, again, we're looking at having just everything laid out here, multiple columns. We're not really doing anything for styling the form, and this is something that we really should take a look at. Because, when you're dealing with forms, the most ideal way to provide a form is to be able to do it from top to bottom, a single column. You have the element, and then the label for the element, and that's it, you just stack them on top of each other. The reason for this is... A couple of reasons. First of all, it's easier for the user to just scan from top to bottom, it also... And then it actually, what we're doing here, where we have a limited amount of real estate, for mobile devices, this is also the ideal form. So, if you think about any other mobile applications that you tinkered around with and you've actually registered for or signed in, all those fields are going top to bottom, very rarely do you have to scroll left to right, and we should start thinking about that as well within our application.
14:56 CB: Now traditionally, this is set up by working with an unordered list. And, for each one of these items we do an unordered list. And then we do an LI for each input element. And, then we provide a label. And, then we do some custom styling within CSS in order to be able to remove all the styling that comes with an unordered list. But, I can actually make something happen with this even easier. And, again, because we're using Kendo UI, there's a bunch of helper CSS classes that we can use. So, if I go to my form element here, new class equals k-form, and go ahead and hit save. We'll see now that immediately these items are laid out top to bottom. We start already seeing that single column look and feel across my entire form. If we inspect an element here, we'll see that this input right here and this next input, and all these labels and everything like that, they're not in an unordered list. This is just Kendo UI taking care of a couple of things for us behind the scenes so we can have a top to bottom column look here. We also have a couple of other different form classes that you can use, but I want to do a single column, top to bottom, because that's what we want to, of course, work with here.
16:13 CB: Now, let's talk about some more best practices for what we see here. So, we have a single column, and we have something that looks a little bit better. We have reduced the total number of fields to something that at least could be useful information for us on the back end. What else can we do? Well, first of all, it makes a lot of sense that when we have more than just user name and password, so if you're just trying to register a user, that we start organizing these items into potential categories. So, if we have two or more inputs that we can group together, we should go ahead and do that. Now, this can actually be accomplished using fieldsets, which is something that has existed within form elements for a while. So, I can just write fieldset here, I can go ahead and close the fieldset, and within each fieldset you provide a legend. So, for this one it'll be personal information. Go ahead and close that, and without doing anything else, we'll see here that we now get this nice little tag up here that says personal information.
17:14 CB: I can go ahead and do another one, so you can see what that looks like. And I'll go ahead and call this address. There we go. If I save this again, now you'll notice that we get this nice little label here and this little dash that goes across the board. And, this will honestly happen in some way shape or form, even without having Kendo UI apply any styles to this. But, automatically because these are in this class k-form, this capitalization of the information and this layout automatically will happen for us, which is, of course, great to use.
17:58 CB: Now, for each one of these, if we want to be able to say, "Okay, I want to have this input element, and I want to be able to do something with that to lay that out in individual fields." What we go ahead and do is, for each item, we'll create a label and we'll provide a class for that label that is k-form-field, and I'll go ahead and close that label. And then within each one of these labels that we're wrapping around in this, we'll provide a span which will be the actual label that we'll use. We'll call this name. And then we can go ahead and actually just copy and paste this input element in here. Now go ahead and save that. We'll see now that we get name, John Smith, and we see that the labels there are applied for us, and the field is there. And if I go ahead and actually just cheat a little bit and copy and paste and do this for everything that we have here, we'll see now that we have the forms with the field sets.
19:00 CB: We have these labels that we've applied, and the span, same thing like we did with the name before. We'll do the same thing with the gender here and date of birth, and then we scroll down. And we see that now everything is laid out with this label, input element label, whatever element it is here, same thing going down. The last thing that I've add in, is sign me up for the newsletter. And this is just a Kendo UI switch that gives me a little nice interactive way to turn something on or off. But instead of going through and coding each and every piece out here, we'll just keep in mind that for each element that we want to be able to list out. For what traditionally would be a list item, we'll go ahead and just do the label with class k-form-field, and then go ahead and provide the span for the actual label here, and then go ahead and work with the datepicker.
19:48 CB: Now something to keep in mind with the labels that we have is, that they should be as short as possible. For example, if you remember Amazon a couple years ago had, "Please provide your full name," when you signed up for your account. That can be cumbersome for the users to go through, again we need to keep things as short as possible to keep the attention of the user. So keep your labels short, that's a very good thing to keep in mind here. Also, something that we want to be able to think about is label placement. Right now, these labels are at the top here and the reason for that is that you can think about left aligned or top aligned labels as the go to label that you might want to use in a form. Both are completely okay, but each have a different use case. In this particular case, why I like to keep the labels up top here, is because, first of all, it's the easiest thing for users to be able to follow. If they go through and they see, okay, personal information, name, boom, gender, boom, date of birth. Then it's easy to just say, okay, this is what it is, next item, next item. It keeps this all organized from top to bottom, and they never have to divert their eyes over to the left, it's just straight top to bottom.
21:00 CB: An additional thing that is good about this, is that this also great for multiple language forms. If we didn't want to have a simple span here, if we want to have some globalization and we want to account for a couple different languages, this means that I have this entire space right now to fill in this label. If I happen to have a couple of labels that might actually be pretty long in a different language, I don't have to worry about that as much as if they are left aligned, and sitting on the left of my field and taking up precious width, especially when we start dealing with mobile devices. Another thing is that research has shown that this kind of setup for forms has the highest completion rate. If you go through... And there's a lot of different studies that have been made, but if you search online you'll see that this is the best way to ensure that your form gets completely filled out.
21:48 CB: Now, a negative thing is that this does of course add to the height of the overall form, so depending on what you're looking to achieve, maybe you have a super long form, this is when we can start looking to having labels in some other areas. And maybe we don't have to think as much about mobile devices at that point because the label, and the whole overall scheme might call for something else. You could also, if you have a long field, do a wizard component, where you can go back and forward and ensure that you're only displaying five, six fields at a time, and then going back and forth until everything has been completed. I would personally recommend against that, try to keep things as small as possible to ensure that, and as simple as possible, to ensure that you go through here and you don't have to worry too much about exactly what your users are mainly trying to focus on here.
22:38 CB: So, let's think about what else we can do here before we go ahead and actually start working potentially with some validation, which I know that folks are very interested in. A couple other things we could do here is that for any required field, so name, date of birth, street address, and ZIP code, I'm going to define them as required eventually. It is good to indicate to the users that these are required some way, generally next to the label. Now how we can approach this... And I think everybody's seen this, is with that red little asterisk next to the label and make that easy to setup. In this particular case we can actually jump into the labels, and so we have this span right here. I'll go ahead and define another span, and I'll define this as k-required. And, then I'll just type in an asterisk and go ahead and save that. We'll now see, while that's rendering, I'll go ahead and copy and paste this so that we get this little asterisk next to the label. It continues to do that on date of birth, for example. I'll go ahead and just throw that in. And then we had it on address, as well. And, we'll see that I'm just this a little easier to read by separating out the span elements here a little bit so everybody can go through this. And then ZIP code, as well. So, I can save.
24:03 CB: All right. Now ZIP code, street address and name, all have this little asterisk next to them, and date of birth, as well, of course. But, what about the fields that are optional? This is actually something that we should also indicate to the users. We shouldn't just say, okay, these are required, and then leave the other fields as, ah. We want to indicate to the users that these are optional, and the nice and easy way to do that is just by doing parentheses optional next to the label. And, we can continue to do that by, for example, let's go up to gender here. Go ahead and enter the span that represents our label, and we can do span, class equals k-field-info. And go ahead and just type in "optional". When it's saved we'll now see that we get this gray little text next to gender here to indicate that it's optional. We'll go ahead and copy and paste this. Also, for example, signing you up for the newsletter here at the bottom.
25:11 CB: If we look at this field now, it's very easy, first of all, to process it, right. We know the pieces of information that we want to be able to collect, we've organized it in a way that makes sense to the user. It is important to make sure that this makes sense to the user. For example, we could even maybe take this gender and put it under date of birth. It depends a little bit on what we think is the most natural way for the user to fill this out. We should not have top to bottom, a full representation of our data model, because, while yes, we as developers want to be able to collect that data. How our columns are structured or how those fields are laid out within our model might not necessarily be intuitive to the user. What we'll do is, we'll lay everything out for a simple way for the user to be able to go through it, and then behind the scenes we'll make sure that we organize this correctly.
25:58 CB: If I was a user, I could very easily go through this and start typing things out and be able to fill in some information. We have a great looking form, but what can we now do in order to be able to actually hook this up and start providing some validation on this? Well, if we look back at the app component that we have here. We have this form model that we have as our model for this particular case. And I'm going to start binding this to these input elements in order to be able to start doing some validation against this. What I'll do is, for each field I'll go ahead and provide some information so that we can actually see when this gets wired up, so, "123 Test Street". And for the ZIP code, "1234", maybe. And then gender, we'll say "male". I'll go ahead and save that. And, once we've updated that, we can go into each individual input element that we have here and start coding against this model.
27:00 CB: First of all, I want to go ahead and actually set up required for the input element here, 'cause these are required fields. We want to be able to, of course, work with HTML in order to be able to set that up. And then the next way we'll work with this within Angular in order to be able to bind to this is to use the two-way-binding syntax, or what Angular refers to as the "banana in a box" scenario, so that is a square brackets followed by parentheses. And, then we'll just say NG model and we'll set this equal to. And we put our quotes here, and then we say form-model.name. And then I'll also provide a name. And this is little bit confusing, 'cause this is a named field, but I'll go ahead and set that equal to name. So, when I do that, we'll see now that we get test, which is what we had actually set up and define here within the model.
27:51 CB: The reason that we define name here, is because this is actually required by Angular forms in order to register the control with the form. So, this isn't anything that I'm doing specifically because we have applied a k-textbox to this, that's just a class. This is a regular input element that just happens to use the styling that we provide out of the box here. But, for the actual binding to the model, we go ahead and work with NG model and set up the name. It'll be a similar thing... I'll actually skip the radio buttons for now, just because that a little bit extra code here. But for the datepicker, for example, we can do the same thing, set this to be required, and then go ahead and work with the banana in a box syntax. That's not something that I made up, that is what it says in the documentation for Angular. Go ahead and set up the NG model, I'll do form model again and set up date of birth, and then we'll just give it a name. We'll say, "date of birth". Go ahead and save that.
29:00 CB: And, we'll now see that the input element here now is bound to this, as well. To save sometime, I'm going to go ahead and copy and paste in some code again, because I don't want to go through unnecessarily... Go through and just do all the NG model setup for ourselves there. Actually, I'll remove this at the bottom here, because I got ahead of myself a little bit, go ahead and hit save. And now we'll see that everything is wired up to the actual data that I had, right. So, we had test street, we have the ZIP code. If I see that something's missing here, it would be that we have no button element, and that will eventually be something that we'll want to be able to do, once we make sure that all this is valid, etcetera. At the bottom here, I'll go ahead and define two buttons, one is type submit, and I'll go ahead and define this actually as a Kendo button, with just with the simple attribute, and I will say submit button.
30:00 CB: Close that tag and I'll do another one as well because this tends to happen, Kendo button, then call it cancel. So, I'll go ahead and add these two in. And what we'll notice here is that right now for my user, if I were to go and try to submit this form, of course nothing happens, but what's the difference between submit and cancel? There's not really a lot going on. And again, from a best practice point of view, we want to be able to highlight their difference. Ideally, we shouldn't have a cancel button at all. Ideally, there should be another way, maybe an X in the form, maybe it's in a pop-up, whatever it might be. But having a cancel button in there or a reset button, actually can cause some confusion for users. But if we absolutely need to have submit and cancel, what we can do is, two tricks that we can do.
30:44 CB: One, is to be able to make the style of the submit button a little bit different. I'll go ahead and say that this is the primary button by binding to the primary attribute. Submit now will turn this to this orange color. And then, also, instead of having submit, what we should say is what the actual action of this is. So, instead of submit, I would say, maybe create account. And, this gives a clear indication to the user of what's going to happen when they hit that button right there.
31:16 CB: All right. Now that we have this wired up, and we've set some of these to be required. What we'll see is that, when I go ahead and empty this out, we'll see now that this red little box appears around the input elements. And this is just using, again, styling from Kendo UI in order to be able to provide this. But, an interesting little hot tip that I can provide when you're trying to go through and actually see what is going on within Angular for your input elements, is that you can go ahead and use this... I'll just do a little hashtag spy here, and then a new line, and I'll go ahead and say... Remove this, so I remember that. And this is actually a little thing I took from the documentation of Angular, is that we can now see that for this particular element, that hashtag just gives us a way to be able to define a name for it. We can see that we have NG untouched, NG pristine, and NG valid.
32:11 CB: If I go ahead and just do TE here, and I remove some of these. We'll see here that it's NG valid, NG dirty, NG touched. Actually, if I even refresh the page, we'll see it actually updates as soon as I leave the element. And as soon as I type it and go away, immediately as soon as the last key is pressed it turns red. And what we want to be able to do is that we want to be able to do this validation like we see here. And we can work with this information coming from Angular itself. And we can say, okay, anytime we leave the element or any time this is dirty, whatever it might be, and invalid, we can go in and pop-up with some sort of error message. And this is when we want to do validation. We don't want to do validation when we hit create account and have six different error messages pop-up. Instead, for a best practice point of view, we should go ahead and with each individual element, do the validation against it when we leave the element. When we drop focus from the element, we'll go ahead and do our validation. Now, this can kick off automatically on the model within Angular itself or what we can do is, of course, do some custom validation.
33:21 CB: For the sake of the webinar, don't necessarily have time to do custom validation here, but what we can do is we're gonna, of course, throw in some error message here. What I'll do is under this element, I'll go ahead and provide a div and have a custom class here that's called validation error. And I'll go ahead and type something in here. For example, I'll do, please provide your full name. Go ahead and hit save. We'll see now that this appears actually constantly under this particular element and that is just because in this particular case, I haven't done anything for actually hiding it. But what I will mention is, again, when we're talking about the best practices here, the best thing to do for your error messages is to provide those at the bottom or at the right of form. Because, I've done this thing of going from top to bottom, I personally prefer that, and I see a lot of success with that. I'll continue that trend and post my validation messages and error messages below the particular input that's running into issues. So, no collection of validation messages in a pop-up, or no collection of validation messages on the right or left.
34:33 CB: This is being done on each element, as I leave the element, I want to be able to have some message appear. Additionally, we should try to provide some helpful information in terms of why that failed. For example, let's say we're providing a email input and somebody doesn't provide a valid email. Maybe they forget the @, maybe it's not, @whatever.com, maybe they do a comma instead. We can say, "Hey, it seems like you didn't provide a valid email address," for example. Or, date of birth, is kinda the same thing. "Hey, this isn't a valid date of birth." Or, "This isn't a valid date," whatever it might be. These validation messages should be a little bit more helpful than simply just, "Hey, there's an error," and just a rehash of what the issue is. So, please provide your full name. Names should be pretty easy for the user to go through. But, what we can do is we can maybe have a couple different messages that we can work with and assign here, depending on what the actual message is, what the user's inputted, etcetera. We can be a little bit flexible with that. But, the way to assure that this is not permanently here is to do a little trick that we have. Because we have this hashtag spy and we can see the class name, what we can do is a couple things.
35:49 CB: First, we do have to work within and set up and name this something. I could actually work with what we have here, hashtag spy, if I wanted to in this case, but the spy is just for us to illegitimately do that. We know that we're only accessing that when we're spying. But, I can set this to be NG model here, and that would actually go ahead and provide me with a way to be able to pull out the actual model from this input element. I know then by accessing name dot, whatever it might be, if it's valid, pristine or, whatever it might be. In this case I can access the... And work with hidden and bind to that within this particular text box. Let me go ahead and do this on a new line, so it's easier for everybody to see. I can do hidden and then here I can do name.valid. So, it's hidden if it's valid or also if it's pristine, because pristine just means that it loaded, right. So, if it loaded empty... If we're not pre-filling out information, then it's still okay. We won't be able to submit the form but we want to be able to go ahead and make sure that we're not displaying this error message immediately as soon as the form loads, just because the form is empty. Then I go ahead and save here, we'll see that that disappears, test appears again. And, as soon as I remove that, we see here, please provide your full name. And we're good to go from that perspective.
37:15 CB: All right. So, we can do this now for each individual of the required input elements but for the sake of time, again, do a little copy and paste magic and we'll see here now that I can do the same thing here for all these particular values here. We'll see that goes away. There we go. The auto complete doesn't get in my way, we'll see now that everything's customized here and set up for that. Last thing we want to do is, of course, go ahead and submit this, because now we have a form that's taking advantage of a lot of the best practices that we talked about. It looks nice, at least maybe not when it's all this red. But, from my perspective this is a great form to be able to have within an application that serves either a desktop web or even mobile web, in order to be able to have folks sign up and work with these particular input elements.
38:05 CB: Initially, we want to be able to submit this and as I mentioned, because we're doing this on an individual input element level, I don't want to go ahead and hit create account and then do nothing for the user. I don't want to just say, okay, well there are error messages on the page, clearly you should know that. Instead, I want to actually take away the ability for the user to do anything with the button when this form is invalid. And the way that I can do that, is first I want to go ahead and wire up that something should actually happen with the form itself. When I go and hit submit, I should have something that happens. And the way that I can do this is we can bind to the NG submit event, and this is actually coming out from the form element and then specifically from Angular to be able to have an event that goes out and triggers when we submit this form. And that is going to be my onsubmit function that I defined here. So we do onsubmit. Go ahead and save that.
39:04 CB: All right. And the last thing that we want to be able to do, as well, is that we want to be able to provide a name for this particular form so that we can access that in the button in a bit, and I'll show you why. Let's go ahead and say, user form here is equal to the NG form, so that we now have this variable that we can access that's equal to this whole form element. The reason that I do that... So user form, is because on this one right here, I want to be able to disable it when we know that we can't actually submit the item or when at least I don't want the item to be able to be submitted. And this can be done by saying, disabled, so binding to that property, and say that when the user form, dot form, valid. And because we threw in, of course, the exclamation mark here. We're saying when this form is not valid go ahead and make sure that we cannot actually click this button. If I go ahead and remove an item from here, we'll see that immediately this item gets grayed out and I cannot interact with it at all.
40:05 CB: Now if I go ahead and... Let's just remove this information. Let's not have anything really bound initially, except for the newsletter, we always want the user to sign up for the newsletter. Go ahead and save that. We see now that we have a form with a couple of required and optional elements. We see that we have, create account, and that's now grayed out. I can't click on that, so test, for example, here. I go ahead and do, "123 My Street." And just that as a ZIP code, and as soon as we filled out this information I can hit create account. Or if I go back we see here now that when I fill out the information, okay, I took that away. No, it gets disabled and we get an error message here. I'll go ahead and just fill that out. And then in my console here, when I go ahead and hit create account. We'll see now that we submit and we actually print out this form model here. We can take a look at what that looks like.
41:06 CB: Of course, this is when you can do some additional validation if you wanted to, and then ship this back to the server, or whatever kind of setup you have within your Angular service layer, you can feel free to do so. But, overall I just spent about 45 minutes of your day going from simple input elements and just looking at my model, and really fleshing out and building a very nice, responsive form that I can use, again on desktop web, or mobile web. We can get an understanding of just... Even when I popped open the console, we can see how that behaved fairly well. And if I stretch this out... It will just take advantage of full width here because these input elements are automatically just going to be able to work with whatever width that we provide them. That's the main gist of what I wanted to cover in this webinar. And what you'll see soon on your screen is that a poll will pop-up and this poll will just be there and if you can just quickly answer it. It's just asked if this is something that was irrelevant to you, or if it was something that was relevant, or if you enjoy this kind of content.
42:09 CB: I know that I spent a lot of time coding. I know that I spent a lot of time just in the IDE here and refreshing back and forth. I wanted to get an understanding of, is this something that you find useful and something that you might enjoy in the future to take a look at and see some other hot topics that we have within Angular forms, or really Angular, or Kendo UI, or whatever it might be. As everybody is filling that out, I'm also going to go ahead and just switch back to, if I can find the proper window, to this little screen right here, and go full screen and pop this open and start taking a look at some of the questions that you've asked. Again, there's been a lot of questions that have been asked and I think a couple of my helpers have been answering them, but as I go through here, I'll just see when it comes to some of these questions that popped up here. One of the questions that popped up here is if this is using the Angular 2.0 or above? Yes, it is.
44:24 CB: Oh, that is another good question that popped up here, is what is the best practice to set a fixed height for the validation and error message? When I went through and we have those elements that we typed in, let's say we had that error message that could be the full name. That moved everything below, and I personally like the idea of having a fixed height for an area where the validation messages might pop-up, so it's not necessarily jarring for the user. So it's actually a great comment on something that I could have provided alongside with this webinar is to just set that area as a fixed height because then it's just always going to be there. It was fairly small text so it was not like that would necessarily make that form that much more bloated. That is a great idea for something that's top to bottom here. Somebody asked about what about using a select with a bunch of options? Yes, that is, of course, 100% okay to do. I would just say that in the form that we had, that we didn't have more than two elements to choose from, male or female. And I didn't really have... Having multiple selects and drop downs for selecting a date isn't necessarily that great, 'cause they can get a little bit cumbersome for the user.
45:44 CB: But if you have anything that's four or more, for example, maybe if you wanted to rate this webinar from a one to five, maybe that's not the best but you could still use that as an example. Then yes, using a select element like that is great. Somebody asked if I can post the project, yes, I will. When this webinar is posted online, I'll go ahead and include the link, as well for the GitHub project where this project is posted, so keep an eye out for that. Everybody that joined the webinar will get an email once the webinar has been posted and that will include a link where you can just go ahead and download this overall project, that's no problem at all. Somebody's asking a little bit about if this is a child component, and we want to be able to work with the parent component? This all depends a little bit on the architecture that you set up. I personally believe a lot in not necessarily passing too much information between the parent component and the child component. If anything, maybe just go from the parent down to the child.
46:44 CB: Ideally, when we hit that create user, that will go back to a service layer, and that service layer will then respond to the parent component as well and maybe refreshing that. If I have, let's say, some one way binding within the parent element or again two way binding, if I work with let's say an observable, and work with that in the service layer, it can very easily refresh the parent, as well. Instead of thinking about transferring items from parent to child and child to parent, I would prefer to set up a service layer in order to be able to have that information be passed back and forth. That way you have one single area that is responsible for the data including something as simple as maybe just creating the user, up until a full list of order and purchase history, or whatever it might be. All right. There's a lot of questions in here, you guys absolutely paid attention, that's great. I might not be able to get to all of these but if there are any any additional questions I'll of course be able to get to them off line, as well.
47:47 CB: Now, another question came through if this can work with Visual Studio in a C# environment? Yes, it absolutely can. This was just a basic HTML page using the default Angular CLI setup and using Atom, but you can use Visual Studio Code, of course, or any of your favorite IDEs. Visual Studio also has some templates specifically to get started with Angular. I would check out just a basic project of getting started with Angular. They essentially have a Visual Studio wrapper around the Angular getting started setup. And from there you can see if there maybe some other templates to maybe help setup the server side. Especially, if you work with dotNet Core or anything like that, to be able to setup controllers that you can communicate with on the backend. There's a lot of templates that you can work with from that. And then based on setting that up, you can go through and do the same NPM install. You can then also go ahead and work with the exact same code, even copy and paste it in because you're working with the separate client side and server side, as well.
48:48 CB: Another question came up, if we can use these libraries with an ASP.NET server control, as well? That takes us out of the Angular world, but there definitely are libraries out there to help create some better looking forms in the ASP.NET world. So some of the more server side control libraries that exist out there, for example, we have our own for ASP.NET Ajax. And within those traditional server side controls there's data form elements that you can take use of and classes you can work with, as well. This did specifically target Angular. And yes I included Kendo UI, but honestly it's just to make sure that I didn't necessarily have that many custom CSS classes to work with, I just had everything there for me so that we can finish in 45 minutes, and which actually worked. I came in under time so that was perfect. But you don't necessarily need to, or course, rely on a library just to take advantage of the best practices that we just talked about here.
49:43 CB: Another question popped up around how to customize the select and option element? Yes, that's definitely something that we potentially could have taken a look at styling. Kendo UI actually does have a drop down that helps, that is essentially just a select element with options and some style on top of that. And of course, additional functionalities, so we could have used that. Styling elements, that can take quite awhile, so I think taking a look at some of these elements and custom styling them with just me going through and either working with my own classes or include the other ones can take a little bit of time. But absolutely, that is a good topic to think about and just for the sake of time was unable to fill that in here.
50:32 CB: All right. Well, there are still some questions laying around here but they are a little bit specific. What I'll go ahead and do is, I'll wrap up for now, and then I'll follow up and potentially provide a blog post to some of the big questions to some of these other questions to be able to lay them out here. I know everybody's been listening to me now for 50 minutes or anything like that. But I'll go ahead and follow up privately or potentially in that blog post in order to be able to help out with any of the remaining questions. I want to thank everybody again for attending today's webinar. Thank you, so many of you, for completing the poll, there was actually a large majority of you that went through and completed it, so I appreciate that. It allows me to get some insight into if this is a useful session or not, for the folks out there, and see what else we can come up with. So again, thank you. I'll give you a couple of minutes of your day back here with the whole meeting invite. And I definitely appreciate you taking the time and joining today. Bye, everybody.
Subscribe to be the first to get our expert-written articles and tutorials for developers!