1 00:00:00,000 --> 00:00:02,000 [?music?] 2 00:00:02,000 --> 00:00:06,000 [Sorting Collections] 3 00:00:06,000 --> 00:00:10,000 [Jim Hoskins] So you may have noticed we have All Notes here. 4 00:00:10,000 --> 00:00:14,000 Right now they're just sort of sorted in whatever order they were put into here. 5 00:00:14,000 --> 00:00:18,000 What I'd like to do is actually sort these by their title 6 00:00:18,000 --> 00:00:21,000 and later on when we add geolocation, 7 00:00:21,000 --> 00:00:23,000 I'm going to have a different collection that's sorted 8 00:00:23,000 --> 00:00:27,000 by how close to my current location that note is 9 00:00:27,000 --> 00:00:29,000 and we can have all sorts of different sorts. 10 00:00:29,000 --> 00:00:33,000 So here where I have All Notes, I want this to be alphabetically sorted 11 00:00:33,000 --> 00:00:36,000 and we can see that we're not quite there yet. 12 00:00:36,000 --> 00:00:38,000 In fact, you can see when we defined our view for this list, 13 00:00:38,000 --> 00:00:41,000 we actually called this ListView list_alphabetical 14 00:00:41,000 --> 00:00:45,000 and that's because ultimately, I did plan to make sure that this list 15 00:00:45,000 --> 00:00:48,000 was in alphabetical order. 16 00:00:48,000 --> 00:00:51,000 Now, here we have our collection called AllNotes 17 00:00:51,000 --> 00:00:55,000 and this is actually what we want to sort on--we want to sort our collection. 18 00:00:55,000 --> 00:00:58,000 That way, when our view here is displaying them, 19 00:00:58,000 --> 00:01:01,000 they'll just simply be displayed in alphabetical order. 20 00:01:01,000 --> 00:01:05,000 Now, to do that, all we need to do is when we define a collection, 21 00:01:05,000 --> 00:01:09,000 pass it an option called comparator. 22 00:01:09,000 --> 00:01:12,000 comparator: 23 00:01:12,000 --> 00:01:17,000 The comparator is a method that you can pass to a collection 24 00:01:17,000 --> 00:01:21,000 and Backbone will automatically sort the collection every time it is updated 25 00:01:21,000 --> 00:01:23,000 based on that comparator. 26 00:01:23,000 --> 00:01:26,000 So how it works is we pass it a function: 27 00:01:26,000 --> 00:01:28,000 comparator: function(){ 28 00:01:28,000 --> 00:01:33,000 and that function is going to receive an instance; in our case, a (note){. 29 00:01:33,000 --> 00:01:36,000 And so what we want to do here in our comparator function 30 00:01:36,000 --> 00:01:41,000 is return a property that Backbone is ultimately going to sort on, 31 00:01:41,000 --> 00:01:44,000 so if we wanted to sort alphabetically on our title, 32 00:01:44,000 --> 00:01:46,000 we're going to return our title. 33 00:01:46,000 --> 00:01:54,000 So one way we could do that is return note.get("title"); 34 00:01:54,000 --> 00:01:59,000 So now any time Backbone gets the collection, 35 00:01:59,000 --> 00:02:04,000 whether it's fetching or adding a new item, it's going to call its own sort function 36 00:02:04,000 --> 00:02:06,000 which will use comparator to get the title 37 00:02:06,000 --> 00:02:08,000 and ultimately sort on that title. 38 00:02:08,000 --> 00:02:12,000 So let's save this out and go back to our test here in Chrome, 39 00:02:12,000 --> 00:02:15,000 and if we refresh, 40 00:02:15,000 --> 00:02:20,000 we can see that it's not quite working. 41 00:02:20,000 --> 00:02:25,000 That was my mistake--I forgot that the collection constructor 42 00:02:25,000 --> 00:02:29,000 actually takes an argument before this options parameter 43 00:02:29,000 --> 00:02:33,000 and that would be the actual collection of notes we want to start with. 44 00:02:33,000 --> 00:02:35,000 Now, when we instantiate this, 45 00:02:35,000 --> 00:02:38,000 we don't want to actually start with a collection of predefined notes-- 46 00:02:38,000 --> 00:02:40,000 those are going to be defined later-- 47 00:02:40,000 --> 00:02:42,000 so what we can do is pass (null) as the first argument 48 00:02:42,000 --> 00:02:47,000 and the second argument is going to be any optional additional parameters 49 00:02:47,000 --> 00:02:48,000 to our collection. 50 00:02:48,000 --> 00:02:51,000 So now if we save this out and refresh it again, 51 00:02:51,000 --> 00:02:53,000 we can see we now have a sorted list. 52 00:02:53,000 --> 00:02:58,000 We have A, M, N, O, P, S, T, 53 00:02:58,000 --> 00:03:04,000 and that looks good, but there's still one little bug, and let's check it out. 54 00:03:04,000 --> 00:03:11,000 We'll create a new one, and what I'll do is I'll call this a brand new note 55 00:03:11,000 --> 00:03:15,000 and we have some Text here. 56 00:03:15,000 --> 00:03:20,000 So if we save this out and we go to All Notes, 57 00:03:20,000 --> 00:03:24,000 we can see that brand new doesn't appear between A and M like you would expect. 58 00:03:24,000 --> 00:03:29,000 Instead, it appears down here, and this is not because it was just added that way. 59 00:03:29,000 --> 00:03:33,000 Even if we refresh it, we can see that it always sorts to the bottom 60 00:03:33,000 --> 00:03:36,000 and that's because the way it is sorting is on the string 61 00:03:36,000 --> 00:03:38,000 and when we sort a string, 62 00:03:38,000 --> 00:03:43,000 the case of the string actually matters, so the lowercase "b" 63 00:03:43,000 --> 00:03:48,000 actually comes after the uppercase "Z" and a normal string sort. 64 00:03:48,000 --> 00:03:53,000 So what we want to do is for our comparator actually either lowercase everything 65 00:03:53,000 --> 00:03:55,000 or uppercase everything. 66 00:03:55,000 --> 00:03:59,000 That way, everything is sorted with no regard to the actual case that it's in, 67 00:03:59,000 --> 00:04:02,000 and that's easy enough for us to do. 68 00:04:02,000 --> 00:04:08,000 What we could do is just call .toLowerCase(); on our string here, 69 00:04:08,000 --> 00:04:12,000 and that will lowercase the actual title so no matter what the casing is, 70 00:04:12,000 --> 00:04:17,000 when it gets to the comparator, it will always be lowercase and sorted in that manner. 71 00:04:17,000 --> 00:04:20,000 Now, what if the title is null? 72 00:04:20,000 --> 00:04:24,000 Well, it shouldn't be possible for it to be null, but let's be a little bit safe. 73 00:04:24,000 --> 00:04:27,000 If get("title") returns null and we call LowerCase();, 74 00:04:27,000 --> 00:04:30,000 we're going to be thrown an error saying that there's no method 75 00:04:30,000 --> 00:04:34,000 to LowerCase(); on null or some other false object. 76 00:04:34,000 --> 00:04:39,000 So what we want to do is we'll just wrap this in parentheses here, 77 00:04:39,000 --> 00:04:43,000 and inside of these parentheses we'll either return the "title" 78 00:04:43,000 --> 00:04:48,000 or if we get a null or undefined value, we'll use the or operator here 79 00:04:48,000 --> 00:04:51,000 to simply return a string. 80 00:04:51,000 --> 00:04:56,000 That way, we'll always get a string here that lowercase can be called on, 81 00:04:56,000 --> 00:04:58,000 so just a little bit of safety. 82 00:04:58,000 --> 00:05:05,000 So if we go ahead and save our code out and we refresh our page, 83 00:05:05,000 --> 00:05:10,000 now we're sorted insensitive to the actual case of our title. 84 00:05:10,000 --> 00:05:15,000 So now we have our application able to save notes and display notes to our screen. 85 00:05:15,000 --> 00:05:18,000 In the next Master Class, we'll begin adding more features, 86 00:05:18,000 --> 00:05:22,000 including the ability to add geolocation data to each of our notes.