Project Goal Overview0:00
Today's question comes from Philip on Twitter, and he wants to know how to display the tags on his site sorted by the letter, kind of like this. So this will give us a good opportunity to review a number of things, like CSS columns and some gotchas associated with that. Of course, grouping results. We will use the Bulma CSS framework for fun. Lots of cool stuff here. So let's get started. I have a fresh install of Laravel, and I'm going to say, when the user visits tags, we're basically going to fetch all tags, something like that.
Create Tags Model0:23
I have a fresh install of Laravel, and I'm going to say, when the user visits tags, we're basically going to fetch all tags, something like that. Okay? So let's do this. In my .env file, use sqlite, I've done this a million times in videos. I will create that, touch database/database.sqlite, and then I'm going to say, php artisan make:model Tag -m, create tags table, and we can make this as complex as we want, but I'm going to keep it very simple and say, the tags table has a column for the name. You might have another one for the slug.
a column for the name. You might have another one for the slug. You might have a convenience column for the count, any of that stuff. But I think this is fine. So I'm going to go ahead and migrate my database, and we now have a tags table. But we need some tags to display. So we're going to do that by setting up a factory for a tag. So App\Tag, and yeah, we just have a name, right? And that can be a word. But we do want that to be a unique word.
And that can be a word. But we do want that to be a unique word. And actually on that node, I need to go back, create tags table, name does need to be unique. We don't want two rows with the exact same tag name. So php artisan migrate:rollback, and then php artisan migrate. Okay. So if we want this to be a unique word, we can prefix it with the unique method call. And I think there's like 175 unique words. So if you go over that number, you might have a problem, and you might want to randomize it or include a number or something.
Seed Tags Data1:52
So if you go over that number, you might have a problem, and you might want to randomize it or include a number or something. But for anything less than that, this will be okay. So if I now say php artisan tinker, I can say, give me a factory for a Tag, and I want 150 of them, and persist those to the database. Okay. So 150 unique Tags. That means back in our routes/web.php file, and by the way, I am using Laravel 5.3 here. If we visit this URI, it'll fetch all Tags and return them as JSON. So let's try it out.
If we visit this URI, it'll fetch all tags and return them as JSON. So let's try it out. Tags by letter lesson.dev. And here we go. So go to /tags, and we get our JSON. And I'll close out the demo here. But now in this case, we really just care about the name of the tag. Like I said, you might have more fields, in which case the rules would be different. But for our purposes, we just want the name of the tag. So you can always use pluck for that.
Build Tags Index View2:45
But for our purposes, we just want the name of the tag. So you can always use pluck for that. You can say pluck the name, and that way we're not fetching timestamps if they're not relevant for this particular query. So now we get, in alphabetical order, a collection of all of the tags. Great. So we're going to flesh this out and group them. But for now, let's just save it to $tags, and then load a view called tags. How about tags.index, and yeah, just pass through the $tags. Okay.
How about tags.index, and yeah, just pass through the tags. Okay. Resources, views, tags/index.blade.php. And forgive me, I'm not going to deal with the layout file. We'll just paste in a big block of HTML. And yeah, basically we're going to say for each tags as tag, well, within a list item, echo out the tag, right? So if I were to come back to Chrome and give that a refresh, there's our tags. But let's format it a little better. So lately I've been using the Bulma CSS framework.
And now we'll take all of this, paste it in, and then wrap it within an unordered list. Okay. Give that a refresh. Okay. We have pulled that in through the CDN. But why don't we give ourselves a little banner heading? We can do that with Bulma by using a hero class, which is kind of cool. So a section just gives you some spacing and padding. But if you also add the hero class, think of it as a big block banner. So for example, I could say the hero body.
But if you also add the hero class, think of it as a big block banner. So for example, I could say the hero body. Within it, we're going to have a container that centers it, sets the maximum width. And then we'll have an H1 with a class of title called tags, and then a paragraph for the subtitle, and I don't know, every tag on the site. Okay. So if I come back and give this a refresh, we have some spacing there, but we might want to give it a color. So I could say is-primary or is-success or is-info, anything like that. Looks good.
Style With Bulma Columns4:53
So I could say is primary or is success or is info, anything like that. Looks good. And next, in terms of displaying this, I think CSS three columns would be a good use case. So for example, let's select this and say column-count is going to be 3. And you see you get columns there, then you can set the gap, you can set the rule to be 1px solid gray. Once again, column-gap is 70px around, center all of it, you know, you can get kind of a nice quick effect there. So let's copy that. And now I'm going to go back to Sublime Text.
So let's copy that. And now I'm going to go back to Sublime Text. We'll go to our app.scss file that Laravel provides. And we're not using Bootstrap. So in fact, let's get rid of all of that. Now if we want to designate that this section right here has columns, well, one convention I've been using a lot lately is things like this, hasColumns. So you describe how it should be presented. It hasColumns. And yeah, Bulma uses this exact same thing.
It has columns. And yeah, Bulma uses this exact same thing. Like here is primary or info. Now you get a different color. Or you could say isBold and you get kind of a cool gradient there that corresponds to whichever one you select, isInfo, isSuccess. But yeah, I kind of like that convention of is-. It'll make your CSS a lot cleaner. Anyways, I'm going to use hasColumns here. So I will create that.
Anyways, I'm going to use hasMany here. So I will create that. And we'll say columnCounts. And actually we saved that, didn't we? So I can paste that in. Let's change this to E3E3. And we do need to compile this all down. So let's make sure that we install all of our dependencies. That'll pull in sass, that'll pull in laravel-elixir, and a lot of that stuff. And now in our gulpfile.js, no webpack, just sass for now.
That'll pull in sass, that'll pull in laravel-elixir, and a lot of that stuff. And now in our gulpfile.js, no webpack, just sass for now. Now actually that's going to take a second to do its thing. So another thing I do in my personal projects is I use the .sass syntax. So if you rename this file to app.sass, you can use a different syntax where the braces are optional and the semicolons are optional. And then further for things like mixins, like maybe you have a mobile mixin that you use, like include mobile, and behind the scenes that'll set a media query with a maximum width. Then you can say display: none or something like that. If you use .sass, you can change all of this to .mobile.
Then you can say display: none or something like that. If you use .sass, you can change all of this to .mobile. And then once again, get rid of the braces and get rid of the semicolon. So you could say for mobile, we don't want to see it. For tablet, we're going to set column-count to 2. You know, of course you would need to create those mixins. Our, by the way, Bulma includes that if you install it through NPM. Just a little tip there to consider. So anyways, that's done now. I can go ahead and boot up gulp watch.
So anyways, that's done now. I can go ahead and boot up gulp watch. Ah, and it can't find our file, and that's because we changed it. So back in our gulpfile.js, I'll update the extension and then run it again. gulp watch. Cool. So that's going to compile down now. We can go up to our head and then import that. And then this section right here is never necessary, so you can remove it. Okay, so let's go back to Chrome.
Group Tags By Letter8:51
But next, we still haven't solved the situation of organizing these by letter. Yes, it is in alphabetical order, but I want specific sections for every single letter. So I want the A letter, the B letter, the O letter. And I think that'll be easier for folks to scan. So here's what we're going to do. In our routes file, we know that we want all tags no matter what. A lot of people will try to figure out how to perform the grouping on the database end, on the SQL end. But I don't know, for anything more than the simplest of groupings, it can sometimes get a little tricky.
But I don't know, for anything more than the simplest of groupings, it can sometimes get a little tricky. So if we know we do want all tags no matter what, we can do the grouping on the PHP side where we have that much more control and familiarity. So let's do this. Let's bring it back to all tags and return them. And if I view this in the browser, yeah, here's our collection. But now, let's say group by the name. Okay, so take note at what that's going to do. We give it a refresh, you'll see that the key for each item in our collection is associated.
Okay, so take note at what that's going to do. We give it a refresh, you'll see that the key for each item in our collection is associated with a new collection that includes all items that have that name. So in this case, we don't, that's kind of superfluous, right? We have a key and exactly one item because we know it's unique. So that's not overly useful. But what is useful is if we could use the first letter of the tag alone. Here's how we can do that. You can pass a closure here that will accept your tag. And now whatever you return here will be the basis for how your items are grouped.
You can pass a closure here that will accept your tag. And now whatever you return here will be the basis for how your items are grouped. So if I want to grab the first letter, yeah, we could just say, give me the very first letter. Start at the beginning, take one letter. Ah, in this case, yeah, now we're back to the situation where tag is an object. So we do want to group the name of the tag. Okay, sorry about that. But anyways, now you'll see that, yeah, we have one key for E and it is equal to a collection of all of our tags that begin with the letter E.
But anyways, now you'll see that, yeah, we have one key for E and it is equal to a collection of all of our tags that begin with the letter E. Here's another one for L or P or M. And if we go down to the very bottom, we'll see T and H. But notice it's not in alphabetical order. Let's fix that. Let's make sure that we order by the name. The default will be ascending order. And we'll switch that out for get because we have to. Okay, so now if we refresh, we start at A and we get all the A's and then we go to C, D and you get the idea.
So what we now have is a collection of sub-collections, basically. So what we really want to say here is something like this. For each tags as, well, we know that the key is the letter, right? And then the value will be the collection of tags for that letter. So for each one of those, we're going to surround them. So maybe we'll do like a div with a class of letter-group, anything we want here. Within it, we'll have a title that looks like a h1 and maybe I'll also give it a class of letter just in case we need to style it later. And then we'll spit out the letter. Okay, so come back and give this a refresh and now we have each of the letters.
And then we'll spit out the letter. Okay, so come back and give this a refresh and now we have each of the letters. So again, does that make sense, right? Return the tags, we are able to grab the letter because we grouped them by the letter. So we filtered through our collection and we set for each one as letter and then tag collection. So now this is stored in the variable letter, which means we can fetch it right here. Next, we want to spit out the list of tags in this single collection. Okay, once again, for each tag collection as tag, then within a list item and you know what, we can just grab all of this right here and save ourselves some time.
So if I quickly want to see anything related to the letter T, I can quickly scroll there and browse. Of course, we don't have an endpoint for that, but you can set that up. So now for fun, let's just do a touch of styling and we'll call it a day. The first thing I want to do, I'll switch back real quick, is style each section here and we called them letterGroup. We need some spacing, right? So at that sass and we'll say letterGroup, we're going to have margins of 2em on the top, 0 on the left and right and 4em on the bottom. So we are running gulp watch, so that will compile it down.
top, zero on the left and right and four ms on the bottom. So we are running gulp watch, so that will compile it down. And if I give that a refresh, yeah, you see we get a little more spacing here. But now notice that this one incorrectly has some margin-top. I really don't want the very first one to have that. So what you can do, you can always apply classes. So you could say like a class of first will have a margin-top of zero. You know, we used to do that quite a bit. And then you could determine that by using the loop object in Laravel 5.3. So for example, right here, you could say if this is the first iteration of the loop,
And then you could determine that by using the loop object in Laravel 5.3. So for example, right here, you could say if this is the first iteration of the loop, then add a class. Yeah, you could do that. We can also just do this with simple CSS. So you could say right here, the first child should have no margin top and the last child should have no margin bottom. Okay, so give that a refresh and that should jump up. Next, why don't we give a background color to the letter itself? Maybe like this.
You have a lot of options there. Finally, you learned about using columns and you learned about this nice convention where you say hasColumns to add behavior. So like maybe you don't always want to align the text to the center for a column. Give that a refresh. Maybe that's an optional thing. So maybe you can say if it also has a class of has-text-centered, then you would align the text to the center. Or Bulma already has a utility class for that. So you can just add that here.
