Mastering the Art of Forms

0 0

[Music] how's it going good cool so thank you all for coming to see me I know forms is not the most exciting piece of UI it's something that I've had to do a little bit not a little bit actually a lot in my current job so that's why I'm here to share with all of you yeah so let's get started so a little bit about me oh wait I forgot this is the slide URL if anyone wants to follow along I also posted in the in a slack channel so for those of you that would like to follow along anyway so a little bit about me my name is Danielle this is my twitter handle I'm a software engineer from New York I love animals so last week I was in Australia and I got to meet and pet a kangaroo so it was like the single best day of my life I also work at a company called blue apron and so for those of you that think that blue apron is just a podcast sponsorship company we do something else too we also sell food to our customers and so I work on the warehouse side of things and so what that means is that I build tools for our warehouse associates to to do their jobs and so there's a lot of data that goes into what happens in our warehouses and so there's a lot of pieces from tracking labor and work order units to tracking inventory and different things having to do with incoming raw date or raw inventory and whatnot so that's what I'm going to talk about all the lessons that I've learned having to build a lot of forms so forums are everywhere a forum might be the first thing that your user sees once it's the first impression of your product and so it really might determine whether they convert they become a customer or they enter any sort of conversion funnel so they're also how we connect with our with our friends and our family on Twitter and Facebook whatever else people use for social media and then they're also used for really basic utility this is a Google Calendar screenshot and so you can see there's a lot of input fields here all that needs to be understood and intuitive for the user so why is it the developers if forms are so important hate building for him so much everyone that I told I was telling the stock they had like it's just like a wince look initially and it's true it that's how a lot of people feel this was me a year ago I made the sweet I put it out into the Twitter universe and I got a response from someone on ember core they were like do you want to talk about it so so I outed myself and we had a really good conversation I don't I don't actually member who it was because the the conversation went away eventually but there were a couple people that I talked to and after I realized that it makes no sense to complain I decided that okay I'm gonna kind of zero in on all these patterns that I've come to see and use repeatedly and I'm gonna make some decisions that's going to make building fourarms better for me and better for my coworkers so there's two core pieces of this I would say that really good design patterns or is one and then managing your data is another one and that kind of builds the foundation of what you need to build efficient and scalable forms and then so with those two Theory aliy clears the path for a great user experience and also building an accessible web accessible website so component patterns let's talk about those so first off this is our example form it's just a sign up page sign up page that I created it has two basic inputs radio buttons and then if you could see there there's a disabled third input that it has a dependency on that radio button grouping so this is an example of for a form component that could be used and so we have we've we've basically just used some handlebars input helpers and then some label tags we've used a couple different types in the input and so this is pretty easy to read you know it's there it's not necessarily reusable but it gets the job done so considering what the code is that we would need to use for to create this component what were the design pattern or what are the design questions that we would ask before we would actually make something that is more modularized and reusable by other developers so first of all we want to look at what types of input we're using so as we saw there we had a couple we had a text input and a numbers input we were using a radio box not a checkbox and so these are questions that we want to think about also are we using a password versus email are we using phone numbers instead of email so start thinking about those things is this a required field it's self-explanatory is it dependent on another component so like I said before we had one component that had had a bound property to the radio buttons and so we want to see what is dependent on each other and then also do these components to apply functionality for other components so for example we want to think of our components is having an input and an output we wanted to think about it functionally and so we have an input and so an input would be a number of object or model or a boolean or something and then our output is our HTML element so they the HTML element that is being outputted is that a custom div is that an element that is just another form item what are we actually outputting so this is the first snippet of code that I'd like to iterate over and on over it's pretty simple just to highlight what we have obviously we can we can look at this and see that okay there's some common patterns we have the label the label tags that we're using we're using that twice we have the ID tags we're not ID tags the input helpers we're using that twice and then the input that we are passing into the knot the input the attributes that we're passing into the input helper that's all pretty much the same so we could probably take this and make a component out of it so we could do something like this we have in the scope of our application an input text field and so it's kind of customized to our application and we build our own API so that the application knows how to handle this type of element so this is what the our input text field example would look like and so what we've done is we've taken those label tags and the input helper and we've created our kind of this dynamic element and so we have we're using the translation library the eye 18n for ember and so we've created a pattern that can cats a string that creates an input label and then we're using our input ID in three different places because we're basically just using the same string path to to to create these HTML elements so we pass in the required attribute the value and yeah so what is the benefits of doing this we don't save a lot of line space but and somewhere to actually argue that being explicit in the parent component is actually better I understand that argument but there are as far as the benefits go for doing it this way we're standardizing our API so of the form element in the scope of the application and among the codes components so we have the same input the we're using for all of our text fields and so we're not giving anyone so we've said okay we're going to use label tags and we're not going to use divs or paragraph tags we're using label tags and then we're going to use the input helper until we standardize the API the next part is that we're standardizing the UI so we want to make sure that from the users perspective we also have a similar look across the application so we don't want to say this is my user name input is blue but my I don't know my first name input is red or something because then that's an inconsistent UI and in the user side they think okay well I'm supposed to do one thing in this place and this other thing in this place and they might not understand that it's just a text field just type in to your valid input okay so this is the part of the talk I know it's late afternoon I want to give everyone an opportunity to get up and stretch if they need to or like clap or snap or wake up your neighbor I'm gonna keep talking but you guys can don't feel like you just need to sit there and stare and listen at me go ahead go okay all right cool okay so the next part is we have this form the form example that we had before so we're taking the snippet of code as we saw before we have a label tag and then a couple input tags two of which are radio buttons and then one of which is using a number a number input so so on this last night here we have an attribute binding that depends on the the values from the radio buttons and so we want to group this logic together so that a it's organized and B it's reusable but also so that we're not completely constrained to what the delay out of the elements so what might this look like so so this is something that I would do I like using elements or using component to yield more components I think it's a really great way to create dynamic like dynamic components so that it's not bound to the UI of the parent component so we have an input of just a model and then we have an output of a couple elements so this is what that form group component might look like and so we're just yielding we're using a yield helper which is using hash helper and then the hash has a couple a couple key value pairs so we have a question text and then we have two components that it's yielding out to the parent component so as we said here we're using the translation helper again and then we're using the component hopper which takes a the name of the component and then also some attributes they go with it and so this is for those to be a little more visual this is this is the what the structure would look like from like the component tree so we have the parent component which is the signup form and then we have the two inputs so we have first name last name and those are rendered by that sign up form component and then we have and then we have that parent input group component which yields our radio buttons and our lucky number input so this is different from the first one you can see we kind of switched around some of the input so that pattern that I just suggested would that work with this so let's say we had for example just to give some context if we had a sign-up page and we wanted to use it the same elements for an account page but for whatever reason our design designer product manager said well I want to switch everything around or put them next to each other how could we handle this so yielding those components with the groupings would actually work and so we could that's what's great about yielding these components when we have these groupings because then we can kind of move them around the way that we need to and apply classes to them as we see fit and so when we do yield components we have the same benefits as we did from root the first refactor but then also with these form groups we have like I said before we have this they're reusable without being bound to their initial layout and so like I said before we can yield these child components and move them around as we see fit the poly classes to them and add more component or add more elements into the block that's being yielded so this is what our refactored code would look like and so this is kind of inspired that this is how I like to think about components it also kind of inspired the like UI or whatever on this talk so component should fit together like a game Tetris plan ahead how component fits into the larger application components might not cleanly stack on top of each other but just make sure that they all work together even if you do have a couple holes so now let's talk about data okay so it's another activity to or false all data should be loaded once the application completes a transition into a route may be true or false true false this isn't a trick question it's fine so that's boss so data isn't required by the view should not be holding up the page when it's rendering so I think that because of the conventions and ember it's really easy to kind of get held up by okay staying okay everything gets loaded in the route we can use a an array or whatever all settled promise or a promise hash and we could just got all our data on the route and then the user has everything they need well it's not the best user experience and I will explain why so we have switched our example we took out the radio buttons and we now have a state drop-down so state I guess we'll just call stay US states or whatever yeah US states until it's an optional drop-down and so we don't have that information localized so we need to make an API call since it is optional we don't want it to hold up rendering the component but we also want to make sure that we're fetching it efficiently and we're also handling the error because if somebody does decide that they want to populate that field we want to make sure that it's it works oh this is everyone can stretch again if they need to okay so we're gonna go through a couple questions now to figure out if we need to should we load it in the component or should we load it in the route so is it as central when the user lands on the page nope okay moving on is it important in the scope of the route if it's not cool is it a concern of the component yes and so because we have all these states that are concerned with this component which is responsible for creating this drop-down when it's expanded for the user to interact with it probably belongs in the component so this is an example of how you could load the data so we have this will render hook really any lifestyle go hook for the component could be useful here just using will render so that it happens before the component is rendered and then also will render isn't blocking so if something if the promise is hasn't resolved by the time the page wants to load this isn't a blocking call and so oh yeah so we're using we'll render we set the options once the promise has resolved and then we can use just a global service like error handling service to send an error if for some reason the error the API call does not come back successfully or it comes back with an error so this is a little bit adds a little bit more complexity I would also recommend handling retries in the component I'm okay American currencies is a good library to use for this so we use the same will render Huck and we can perform a task once the when will render is being called we can count AG use v is just trying five times and if it doesn't work after five times and we say okay this is a failed API call or maybe our services down or whatever but if it first whatever reason it failed after two times then then we have our options so the benefits of this is that user is able to interact with the application sooner which is what we want and then also relative data is handled within the scope of the component and that just means that it's easier to use the component across the application rather than having the data load in the route okay true or false every model should always reflect the backend that persist them true false great okay not always the data store can be used to represent client-side state so use that to applications advantage so TLDR just because we have user models and what other models do we have animal models and addresses it doesn't mean that that entire database schema has to match what's going on in the ember application or any application really so let's say we have our form that we've been building and we can create a model out of that so we have input input input all these inputs are updating our form we've now simplified the in let's stay behind that form though we have a couple different pieces that of a server-side model that need to be kind of consolidated for one API call and so this might get a little hairy but if we have this model layer we're able to take advantage of ember datas model state and so it's easily available in ember inspector and we can remove it and do all everything that we need and so this design pattern is otherwise known as if facade it's basically just taking everything taking a couple layers of complexity simplifying them for for us to use okay true or false data should be validated at the model or server level true false there's no quick trick questions guys nope okay I will tell you why data can be validated everywhere so hear me out so first let's think about how how we would make this decision this design decision it's a validation specific to the input type is it if we have a text box and we want to validate email address with a regex match can we do that look at passwords is the password long enough does it have all the characters that we want can we do that so if yes move on is the error messaging generic enough to reuse can't be blank I'll see Matt that's super generic message so yes then that means it could probably be validated at the component level so I really like using ember CP validations it's a very low level validation library and it's really easy to use it creates this extension on any emperor object and it works with ever computed properties to watch any computer property in any object and say okay this is valid this is not valid based on the way that the the validation has been set up I think it's the last one true or false never use two-way binding true boss okay okay so two-way binding is not that bad I know that we've I always tried to avoid it for the longest time you know it's like Oh Dan down action up and so that's not always the case though when it comes to forms and those of you that do not agree just hear me out so so again we start thinking about what questions we have is element an input if it is then you could probably use two-way binding hear me out okay so we have so let's take the sign up for our model that we were discussing before and we have all these inputs that are bound to be model this model that we have the model has state so we can control that from the application level we can still validate it at the application level it doesn't need to be moved to another object to be validated and we can also debug it it's great because every inspector has all of our models right there and we don't even have to dig through the rendering tree to see what's available and but I will say the one caveat is trying to handle data from that's coming down from a server object and so if you do have a form and it already should be populated you the one difficult thing is making sure that the in the form is read only that going up the forum does not update the original data source and so I can give an example of one way that I would solve that with an asterisk that doesn't solve all problems but this is just one way to do it so we have a form like we mentioned before and so we were using a sign up for model and this kind of extracts the this application level or the front-end level code that we want and so the sign for makes an API call and then we can actually because of Emer data we can unload that model and then we have and we can update them model up string and so now we have this everything kind of goes up and then once the API call is resolved then it updates everything and it unloads the sign up for model that doesn't really have anything to do with the persisted data so another tip I have just kind of concluding that section is to simplify until everything makes sense be thoughtful in your code design patterns and there's rarely always cases that hold up except for observers never used some servers okay so I think this is our last stretching moment if anyone wants to stand up and stretch I'm just still gonna keep talking and so this last part I'm just going to talk about how these different patterns the design patterns and our data management can help us with user experience and web accessibility so I'm not gonna read this whole thing because I think everyone here knows what web accessibility is but the one thing I want to highlight is that it's not it doesn't just it's not just about for people with excessive or with disabilities it's also about people that are in other geographical locations that might have access only to mobile phones or slow internet connection so we want to make sure that we are designing for those people as well not everyone has you know a great Wi-Fi speed or whatever so things to remember in on those two topics make sure you're labeling all of your inputs or use Aria so again I won't read this but Aria is just another four it's for all web or all HTML elements to make accessibility better luckily with forms we have label tags so we don't always need Aria but yeah so this is just an example we have our label tag and we have our input field and then so we're using the the four attribute in our label tag needs to match to our ID attribute in our input and then that's how those interpreters can know okay this is the label for this input okay so indicate required fields and make sure the browser is doing what is expected so so this is an example of something that came out of that this is a Google yeah there's a Google Chrome and so at some point Google Chrome just kind of did an update and so the API for their inputs started showing these required tags which isn't bad it's it's fine but it was unexpected for some users and for some developers and so just make sure that you know the difference between requiring presenting an error message but then also requiring an HTML element in a browser because that API might be different or it might change and it might do something different just another example this is a required field on on Firefox if you just open the browser and it already has a red thing around it so it looks like there's already an error when really the user hasn't done anything wrong so use logical tapping I don't know about you guys but I hate when I tab something or I type something in and then I tab it and I start typing and then I'm here I'm like why wait hold on where what's happening usually this happens when developers have implemented some sort of form and there's like jQuery and they intercept the the key events and then you've got tab and it goes over here and then it goes down here and so make sure that you're using logical tagging because that can be really confusing for for a user yeah what the heck and then use Thoreau and success and error messaging so users if they don't receive any feedback it could just be button mashing we know that from the warehouse because we're have-we have applications on iPhones and before when we were first prototyping stuff and letting people use them you just have it and if something doesn't happen it's just boom boom boom and then so we weren't blocking ourselves from multiple requests and that's an issue so make sure you're you are as a developer interpreting what a user could do and so this is also called idempotency and so we want to make sure is that any input that is given to in the event of a restful service anything that's sent to the server we want to make sure that it is if we send the exact same response multiple times that it is also not making multiple requests I got this from Wikipedia and so just back to the user feedback part this is an example of blueprint calm and how you can you have a modal that pops up and a user can probably change something and then we could just save it and close the modal but blue apron does like a toaster or message so that it says ok we already saved it so you don't need to update this again so I hope that you will join me in thinking that forums aren't that bad there's actually some interesting stuff that you could do with them and there's actually this is just the tip of the iceberg I know that's a really cliche phrase to use but I there's just I could yeah there's just so much more that to know about the different patterns that make it easier for your application and for you and so if you have resources this is just a couple resources that I have these are two really good passed and Berger comp talks the Mozilla web doc and if you are if you want to tweet someone can send a random tweet out into the Ember ecosystems someone will respond to you and ask you why and yeah that's it thank you feel free to tweet me if you have any questions [Music] [Music]