- Use ng-repeat to iterate over data
- Use ng-if & ng-hide/ng-show to hide & show elements
- Use form to build forms
- Research other Angular directives that are included in Angular's library
- Set up a basic Angular app
- Create a basic controller with hardcoded data
Directives are additional DOM nodes – think custom attributes on HTML tags – that Angular uses to apply behaviors to HTML elements. Angular comes with a bunch of different directives for different behaviors and gives you the ability to create your own.
There are a few you'll be using all the time that we're gonna walk through together, today. There are also a few you've already used – ng-app
and ng-controller
. You added them onto HTML tags to tell your Angular app what module we were using and what controller we wanted to ask for data from. Those are two examples of specific behaviors so let's see a few more.
Our end goal for this lesson is to build ourselves a simple little todo app. Shocking, it's true, but it'll be a great way to demonstrate both directives and interacting with controllers.
Note: Show students the finished app from the solution code folder.
We have a lot to get through – we'll have to list an array of todos, demonstrate some simple hiding & showing mechanisms, and bind some changing data via a form.
Since you guys are killers at setting up Angular apps from yesterday, take five minutes to make empty JS and CSS folders, make an app.js
and a todosController.js
and get set up. Don't forget an index, with sourced JS files! Make those files, go go go!
Let's start filling in our todosController
a little bit - add in some initial seed data:
angular
.module("todoApp")
.controller("TodosController", TodosController);
function TodosController(){
// this is our hardcoded seed data
this.all = [
{task: "build an awesome todo list", done: false},
{task: "get super good at Angular", done: false},
{task: "party on code", done: false},
{task: "tackle the bonus challenges for this lesson", done: false},
{task: "take a nap", done: false}
];
}
This is great - we've got an array of simple objects. Granted, .all
is whatever we want it to be, but calling it that makes it feel almost 'ActiveRecordy', doesn't it? Totally your choice, though.
Now, let's start filling out the view with this data; head over to index.html
.
<body>
<header>
<h1>Angular Todo App</h1>
<h3>You have {{}} todos to do!</h3>
</header>
</body>
Now, how do we get the data our controller has access to?
<body ng-controller="TodosController as todos">
<header>
<h1>Angular Todo App</h1>
<h3>You have {{todos.all.length}} todos to do!</h3>
</header>
</body>
Beautiful! But we need more. How do we actually list out our todos? ng-repeat
.
<ul id='todos'>
<li ng-repeat="todo in todos.all">
{{todo.task}}
</li>
</ul>
Let's walk through that. First, hello ng-repeat
! This is used for iterating over repeating elements. Rather than our old-fashioned for
loop, Angular uses ng-repeat
on the element we want to iterate over. Sort of like Ruby (or JavaScript's forEach), we say:
"For each item in
todos.all
, call the one we're ontodo
."
Then, inside that element, we have access to {{todo.whateverAttributesTodoHas}}
.
Now, let's see how data binding works by adding to our list! We'll need a form.
<form id='add-todo'>
<input type="text" placeholder='I need to...'>
</form>
Super simple - this does nothing, yet, but we need it to add to our list when we hit enter and submit it. On the controller side, how would we write a function that adds a new item to our array?
Maybe something like:
//this will add our new function as a property on our controller, so we can use it in the view
this.add = addTodo;
// this just adds a new object to our array, with defaults for now
function addTodo(){
this.all.push({task: "something", done: false});
}
By including the this.addTodo = addTodo;
line, we now can use that function in our view, when we want to. So check out this other useful form directive:
<form id='add-todo' ng-submit="todos.add()">
<input type="text" placeholder='I need to...'>
</form>
Now, it'll be adding fake todos, but I can't resist – try it! You'll see why Angular is so exciting. As soon as you press enter, it auto-updates the list and the count above, without any extra work. That's data binding, it's watching for changes to our data in the controller and updating the view for us.
Obviously we don't want to only use dummy data. How do we keep an eye on what's in the input and send that to our addTodo
function? You guessed it, another directive!
But first, let's think of it like this: we're going to be adding a new todo to our list of existing todos and that todo will be an object just like our others. Something like:
{task: 'whatever we type', done: false}
So maybe let's make a newTodo
object in our controller:
this.newTodo = {task: '', done: false};
Now we know that in both the controller, and now, the view, if we access the .newTodo
, we can share data. This is where another awesome directive comes into play – ng-model
.
In index.html
:
<form id='add-todo' ng-submit="todos.add()">
<input type="text" placeholder='I need to...' ng-model="todos.newTodo.task">
</form>
What does ng-model
do? It binds the data not just from the controller to the view like we saw earlier but the other way around, too. As we type in our input, the actual object of newTodo
changes, specifically the task
attribute inside that object.
Don't believe me? Let's watch it happen.
<form id='add-todo' ng-submit="todos.add()">
<input type="text" placeholder='I need to...' ng-model="todos.newTodo.task">
</form>
<p>About to add todo: <strong>{{todos.newTodo.task}}</strong></p>
You can see, it keeps the data synced, nearly in realtime. That's powerful.
The last step is update our todos.add()
function to utilize this new knowledge. Just like in the view, how do you think we access that newTodo in our controller?
function addTodo(){
this.all.push({task: this.newTodo.task, done: false});
// this last piece isn't necessary, but nicely resets the task to an empty string, which will clear the textbox because the view is bound to the data
this.newTodo.task = '';
}
We're pretty much at capacity for now, but there's one other awesome useful directive you might want to try.
As an example, let's say we think the paragraph that says "About to add todo: blah blah" only should show when newTodo
isn't empty. Normally, we'd use some sort of if/else statement...
<form id='add-todo' ng-submit="todos.add()">
<input type="text" placeholder='I need to...' ng-model="todos.newTodo.task">
</form>
<p ng-if='todos.newTodo.task'>About to add todo: <strong>{{todos.newTodo.task}}</strong></p>
Boom. Beautiful. Play with it, watch it go!
Now, in the next lab, you're going to practice this and hopefully, learn a few extra included directives along the way.
- How do we add a function to a controller?
- How do we iterate over an array of items?
- How do we submit a form?
All content is licensed under a CCBYNCSA 4.0 license. All software code is licensed under GNU GPLv3. For commercial use or alternative licensing, please contact legal@ga.co.