Heads up! To view this whole video, sign in with your Courses Plus account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
In this video we learn about Backbone Collections and how they are used to manage sets of data in our application. here.
[?music?]
0:00
[Backbone Collections]
0:02
[Jim Hoskins] So now we have our form in a state
0:06
where it will actually take all the information from the fields and save it into a New Note.
0:09
However, when we do this and we submit it:
0:13
Text Body
0:18
--even though it's saving, it's not quite having the behavior we want.
0:20
When we save it, it seems to submit and has that sort of slide forward form.
0:23
But you remember, the way we actually brought it up was a dialog,
0:28
so how we actually like it to complete
0:32
is to simply puff away much like that.
0:35
So what we need to do is go into our View,
0:40
and here we are inside of our new Views form.
0:43
So after we create the note, what we want to do is two things.
0:47
First we want to tell the browser that we don't want it to submit like a normal form,
0:52
and we can do that by using the event object that's passed
0:56
into our createNote handler and telling it to prevent default,
0:59
which will stop a normal form load.
1:03
The second is we want to stop the propagation of this submit event
1:05
and that's because jQuery Mobile also does some magic
1:09
whenever it sees forms in order to make our app run like a typical iPhone or IOS application.
1:12
That means it intercepts a form submission,
1:18
does some AJAX, and then moves into another page,
1:21
and we don't want jQuery Mobile doing that, either.
1:24
So what we're going to do is we're going to call e.preventDefault();
1:27
and this will stop our browser from submitting the form like normal.
1:30
The second thing we want to do on that event is call e.stopPropagation();
1:34
which will stop jQuery Mobile from intercepting that event
1:38
and doing its AJAX magic.
1:42
Now, in the event handlers, the equivalent of calling e.preventDefault();
1:44
and e.stopPropagation(); would be to simply return false from this handler function,
1:48
but I prefer to do it more explicitly like this.
1:53
So now we've prevented the browser from submitting the form
1:57
and we've prevented jQuery from handling the form and doing its normal animation.
2:00
Now, the last thing we want to do is to close the dialog in its normal way.
2:05
We also want to reset the form fields because we don't want
2:10
the input from the previous one to show up when we start adding a new note.
2:12
So the way that we can close the dialog--
2:16
let me just move this up the screen a little bit--
2:20
and to close the dialog, all we need to do is call this piece of code right here,
2:23
and what this does is it's a jQuery call
2:28
and it uses a selector here
2:31
and it uses the .ui-dialog to capture any dialog that's open;
2:33
in our case, our new form.
2:37
And then, we can call the dialog plugin and pass it the method "close")
2:40
and that's a way you can close whatever open dialog there is
2:45
from anywhere in your application.
2:49
Finally, we want to reset it, and I'm going to delegate this out to a new method,
2:51
so we'll call this.reset();
2:54
and let's go ahead and create our reset function.
2:58
reset: function(){
3:01
Now, one way we could handle this reset is to use the built-in reset functionality
3:07
built into forms, but later on, we're going to run into a problem
3:11
where the toggle switch doesn't recognize that a select field
3:15
has changed state because of a reset request from the browser
3:19
so we're going to do it manually,
3:23
and I'm just going to paste in this code.
3:27
What this code is going to do is it's going to grab all of the inputs and text areas
3:29
from within this view and just set the value to the empty string,
3:33
which will essentially reset it.
3:38
So if we save this out and we refresh our page,
3:40
let's create a new one and we'll just call this Next Test
3:43
and Some Text Here
3:49
and we save it out--cool.
3:51
We got the dialog to pop away just like it popped up.
3:55
If we bring up the New Note, it's all cleared out and ready to go
3:58
for the next one, so it looks like we got our New Note dialog all set up.
4:02
Our next step is we want to make the page that this would link to functional,
4:07
which would display a list of all of the notes.
4:11
So what we're going to do is we're going to start in our HTML file
4:14
and create a new page under the name All.
4:17
So if we go back to our HTML page,
4:23
first, I'm going to collapse our new page here,
4:28
and if we look here, we see that we link to All,
4:31
so what we're going to do is create a new page
4:35
with the id of "#all" that will have a list of all of our notes.
4:37
So I'm also going to just spin that up.
4:41
We'll go ahead and start our next page
4:46
and we'll call this List of Notes.
4:49
All right. I'll paste this in, cut some stuff out.
5:01
Cool. So I'm just going to paste this in and let's just go over it.
5:10
It's a lot like the pages we've created before.
5:14
We start with the id of "all" and we give it a data-role of "page">.
5:17
Then here, we're defining our header, so it has a data-role of "header"
5:22
and its title is All Notes.
5:25
Here we've added a Back button,
5:28
and this is a button that jQuery Mobile adds by default
5:31
when we are navigating around our pages,
5:34
but the reason I add one in manually is because if somebody bookmarks this page
5:36
and loads it fresh and jQuery mobile doesn't know what the previous page would have been,
5:40
this offers us a default Back button which will take us home in all cases.
5:46
So we just did a normal button with the data-role of "button".
5:50
We have our data-icon of arrow left "arrow-l"
5:56
and then, we added this data-rel="back">
5:59
and this tells jQuery Mobile that when we can, just have it act like a Back button
6:02
and just take them back to wherever it was.
6:07
However, if it can't use the normal Back functionality,
6:09
it will take you to Home, which will work for if we load this page from a bookmark.
6:12
So that's our header, and then we have our div for our content.
6:18
Now, what I'm going to do here is just paste in an unordered list
6:24
with the data role of "listview"
6:28
which is what we saw on our homepage,
6:30
but you'll notice I am not having it with data inset true.
6:33
I want this to be an edge-to-edge list because this page is going to be nothing
6:36
but this single list of notes
6:40
and I've given it an id of "all notes">.
6:42
Now what we're going to do is we're going to fill in this list dynamically using Backbone.
6:46
Each list item in this list view
6:52
is actually going to be represented by its own instance of a View
6:55
that we're going to write, and that view is going to be called a NoteList item.
6:58
Besides each of those individual Views inside of it,
7:03
we're also going to create a View that represents this list,
7:06
and that will manage things like adding new items to the list
7:09
or just populating the list by itself.
7:14
So we're going to have two different Views:
7:16
one represents the entire list and will watch for a collection of notes
7:18
and add the list items in and each of those list items itself will be a View
7:24
and those will be concerned with changes to the Title or any other content
7:30
for that particular list item.
7:34
So now, before we start defining our Views, we need to introduce a new concept
7:37
which is very closely related to our model,
7:42
and that's the idea of a collection.
7:44
So while a model represents a single note,
7:51
a collection represents a list of multiple models or multiple notes.
7:55
In Backbone, collections are used for keeping lists of things
7:59
so they can be updated on the server.
8:03
It can be a little bit tricky to understand where to use collections,
8:05
but basically, we want a collection because we're going to be showing a list
8:08
and having that collection object will give our list View
8:13
something to look at and observe
8:17
and the collection can notify our View when a new note is added to the list
8:18
or the new note is removed or anything like that.
8:24
So the collection sits between our database or our localStorage
8:28
as an abstraction of that.
8:32
Our collections are going to be pretty simple--
8:34
they're just going to represent the entire contents of our database or localStorage.
8:36
So we don't interact directly with the localStorage; instead we use these collections
8:42
and they will watch our localStorage and notify us of any changes.
8:47
So I'm going to define a collection here, and we'll call it a NoteList.
8:57
var NoteList
9:02
and we're going to inherit from the Backbone collection class,
9:05
so we'll say Backbone.Collection.extend({.
9:08
What we're going to do here is add some properties and methods
9:16
to customize how our collection works for our notes class.
9:19
The first built-in property we want to specify
9:22
is the model property, and this will tell Backbone
9:25
what type of model we're dealing with.
9:28
In our case, we're dealing with the Note.
9:30
The next thing we want to do is tell it that it's going to utilize localStorage as its data source.
9:34
In order to do that, we just add the localStorage property
9:39
and tell it to use App.stores.notes, which we can remember
9:43
we defined up here, right at the beginning of our code.
9:48
This is exactly the same as our note model here,
9:51
which means that they're using the same database or localStorage database
9:54
when we save a model directly as well as when we try to retrieve a list of models
9:59
from our localStorage.
10:04
So this tells our collection that it's watching localStorage
10:06
and let's add an initializer here.
10:09
initialize: function (){
10:11
and we're actually going to have to make a change to our localStorage code.
10:22
See, the type of application we're creating isn't really the typical use for Backbone.
10:25
A collection is really used to sort of abstract away an endpoint on a web service,
10:30
and the way we're using it now
10:35
is we are going to have multiple collections:
10:39
one collection for sorting by name
10:41
and one location for sorting by geolocation or how close that note is to your current location
10:44
and the way we're saving notes themselves is not actually saving them through a collection
10:50
but just saving them directly, which will store them into localStorage.
10:55
So when we create a New Note and save it into localStorage,
10:58
the collections that we also have hooked up to that same data store
11:02
are not going to be notified of that change.
11:06
So the way we can handle this is we can modify the localStorage code
11:09
to send out an event every time that the data is updated.
11:14
Any collection that's set up to use that data store as its database
11:19
can be set up to watch for that update event and then handle itself accordingly.
11:24
So what we're actually going to do is we're going to open up the Backbone.localStorage.js.
11:30
Now, even though this isn't a library that we wrote,
11:36
unfortunately, I couldn't find an elegant way to get around having to modify
11:38
this library code, so it's worth taking a look.
11:43
It's not too difficult to understand; there's some things here about generating random numbers
11:47
to manage our id, but basically, we're just creating a store.
11:54
It will load the load the store from localStorage.
11:58
And then there's these functions here which are called behind the scene in Backbone
12:01
whenever we save an object.
12:05
So for instance, this save method is just going to call the localStorage.setItem
12:07
and then just sort of stringify its current internal memory,
12:12
and later on, when we restore from it, it'll read from localStorage and deserialize it.
12:18
Now, you can see that create also implicitly calls save,
12:24
update also calls save,
12:28
and destroy calls save,
12:32
so any time our data actually changes, the save function is invoked.
12:34
So if we're going to notify the outside world of any changes to our database,
12:39
we're definitely going to want to do it from inside of this save function.
12:44
Backbone has another class that's really useful to use
12:50
in any situation, and it's called Events. documentcloud.github.com/backbone/#events
12:53
What we can do is we can extend any object or any class
12:58
with Backbone.events, and what that will add is three methods:
13:01
object.bind, which will allow us to watch for a certain type of event
13:04
to be broadcast from this particular object;
13:09
similarly, an unbind method, which will remove any listener from it,
13:13
as well as the trigger.
13:16
Trigger and bind work together, so the object will trigger to create a new event.
13:18
For instance, we can trigger an update event
13:22
and then other parts of our code can bind to that update event
13:25
and every time that save method is called, we can hook our own code into there
13:29
to update, for instance, our collections.
13:34
In order to do that, we need to make sure that store class extends from Backbone.events
13:37
and if we go look at our code,
13:43
we can see that we're already extending Store.prototype with these methods.
13:46
So what we can do is the extend method can take in multiple objects
13:50
that will be all extended to Store.prototype.
13:54
So we'll just type in Backbone.Events, (comma)
13:57
so now our store will also extend from Events
14:03
as well as this custom code, and we can now use bind and trigger on this object.
14:06
So in our save function, when we update our localStorage database
14:15
with the new information, all I'm going to do is call this.trigger
14:19
since now this has a trigger method,
14:24
and let's call our event ("update")
14:27
which will just say that the data inside of our localStorage data store
14:29
has been updated.
14:33
So now, any time our localStorage updates, it's going to broadcast an event
14:36
called update, so inside of our initializer, what we're going to do
14:41
is we're going to grab this.localStorage, which is our data store right here,
14:45
and we're going to use the bind() method and look for the ("update") event.
14:51
So every time our localStorage is updated,
14:57
this function(){ that we're going to define here will be executed.
15:00
What we want to do when the localStorage or the underlying data store is updated
15:05
is to tell this collection to fetch, and what fetch does in a Backbone application
15:10
is it goes to its data source, whether it's localStorage or a remote web service
15:16
and gets that full collection from it.
15:21
So in our case, calling fetch will look at the localStorage and just retrieve
15:24
all of the items in that particular store.
15:28
So all we need to do is call this.fetch; however,
15:31
because we're using a callback function, what this refers to on this particular line
15:34
is no longer our collection, but instead whatever this particular function is bound to.
15:39
So in order to get around that, what we're going to do is set a variable called collection
15:46
var collection and set it = this;
15:51
So now, the current value of this at this scope
15:54
is now assigned to a variable called collection
15:56
and then in here, we can call collection.fetch();.
16:00
which would basically be like calling this.fetch.
16:04
Now, when fetch is called, besides just getting the data from the remote source,
16:12
it'll also set off a bunch of different events that other parts of our code will listen to
16:16
and that change will cascade all the way down to our views
16:20
saying that things have changed.
16:24
So we'll see how this comes into play when we write our next piece of code.
16:26
You need to sign up for Treehouse in order to download course files.
Sign up