• Meteor
  • Tutorial

Building Reusable Controls

The past couple of weeks I've been working on the next version of Evented Mind. So I've been doing a lot of code refactoring and working a lot with the user interface. In this episode I'd like to share with you a pattern that I've been using to organize reusable controls in my project. For instance, in this example, I have a form with a bunch of inputs. And I've wrapped the form in a block helper called LoginForm. And what this LoginForm control will do is attach the right event handlers to the form, and then allow me to do something with the resulting values of the form.

So, one note before we get started, Meteor is working on its own version of Controls and Components and so I'm not sure exactly when that's going to come out, but I needed to have this functionality sooner so I just created a very lightweight Controls library that we'll use for this episode. And when Meteor does finish up the Controls work that they've been doing. I'll work to integrate the library properly. So with that, let's get started.

So in this episode, I'm going to start from scratch. I'm going to create a new Meteor application by calling meteor create, and we'll say building reusable controls. And the next thing I want to do is I'm going to use Meteorite to install this package. And the latest version of Meteorite properly installs packages into the local packages directory here, it symlinks them, in the local packages directory.

So we want to make sure we have the latest version of Meteorite. And to do that I'm going to do an npm update global Meteorite. Now I just did this earlier so it should be quick. And then what I'm going to do is to mrt install controls. I'm sorry it's mrt add controls. OK, great, now if I look at my project directory I should now a packages folder. And if I look at the content of the packages folder, I now have this Controls File which is a symlink to the package itself, which Meteorite put in this folder here.

OK, next, I'm only going to be doing client work for this example, so I'm going to make a directory called Client. And then I'm going to copy, or move, all of my building reusable stuff into the Client directory. And that will clean up my root directory a little bit. And then we'll just change into the client directory and start up our Editor.

And we'll jump over to the HTML. And let's recreate our Login Form, and render that template. And then like we had before I want to wrap this HTML in a control called LoginForm, which we'll create in a second. And then inside here, I'll put my form HTML. So the important thing to note here is that I don't really want this control to dictate to me what the HTML looks like. I just want it to add behaviors and give me the ability to respond to events and things like that.

And so inside here what I might do is just create my different inputs. And the way that the form control works is it uses the name property, the name attribute, of inputs. And so what we'll do here is we'll give this a name of email, and we'll give it a placeholder email as well. And then I'll just create another one for password. And then, finally, we'll just create a submission button. OK, great.

So now that we have our HTML. And what we want to do is to jump over to the JavaScript and actually create this LoginForm control. So the first thing I'll do is just blow away the boilerplate in here. And I don't need to do the if is Meteor is client block here because I'm in the client directory of my project. And so what we'll do is we're going to create this form control and the way we'll do that is by calling control.create.

And the first parameter to that method will be the name of the control. So I'm going to call this LoginForm. And the second parameter will be an object that has the prototype methods and one key word that we can use for the control. So that keyword is called Extend. And Extend says that I'm going to inherit this control from another control.

And so the control that I want to inherit from is Form. So inheritance is a useful pattern here because what Form does is Form actually has all the behavior that we need to respond to the form event handler of the form submit event and parse out the values of the input. So the only thing I really want my login form to do differently is what it actually does with those values.

And so the form control has a method that I can override here called onSubmit. And the onSubmit method gives me the fields from the form as the first parameter and as the second the form itself, so I can do something with that. So, for example, I might reset the form once I've saved values. So for now, why don't we just print out the values of the field so we get a sense of what that object looks like?

OK, I started up the Meteor server for my project and opened up the browser. And so let me type in a value into the first field, and then a password, and then I'll click the Login button. And what we can see down below is that our onSubmit function got an object with a bunch of fields in it. So we have the email value and the password value. And what's neat about this is is that the form control actually works with radios and with checkboxes and handles those properly as well.

So to quickly recap what we've done, I created a control called LoginForm. And that control inherits from the form control itself. And by doing this we get a bunch of behavior like getting those fields automatically when I submit the form. And also just handling the Submit event. And then automatically all I need to do is add this one method called onSubmit. And this method will automatically get called with the fields and the form every time I submit it. And then I can do whatever custom thing I want in here.

So I found it this is a useful way to reuse behaviors across templates in my project. And in another episode I can go over the design of the control class itself. One last note, if the concept of inheritance is new to you or still confusing drop a line in comments or shoot me an email and let me know. And I'd be happy to do an episode that focuses completely on that. Thanks.