تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Basic Tabs With Alpine0:00

Let's do another one. This time, we'll create a tabs component. But as you'll find, if you want it to be reusable and flexible, it's a bit more tricky than you might think. So I will show you this in two steps, the easy route and the slightly more complex route. Okay. So yes, if you want simple tabs, well, if you're using something like Alpine, you can create a scoped component here. And of course, you need a section for the tab headings. So maybe we have one called first. And yeah, the basic idea is we need to store which tab should be displayed to the user. So I could say the activeTab is called first. And when you click on it, record what the activeTab should be. Okay, so now if we do it again, let's see, this would be the second tab. And this would be the third tab. All right, makes sense. So now we know which tab should be displayed, which means down here, we could

Blade Tabs Components Setup1:33

tabbing system here. The only problem is, we have all the functionality coded into the tabs. So if on another page, I wanted tabs, I'm basically doing a copy and paste. And the truth is, if you only have one or two, then fine, keep it simple. But maybe we can find a more flexible approach. So if we're using Blade components, if I want tabs, let's call it tabs. And then well, here's one tab, the heading for it will be first, and then first content goes here. All right, let's do another tab. second, and then one more. third. This, I think, would be ideal. But of course, if we try it now, it's going to blow up because we haven't created those tabs. Okay, let's get started. So in my components directory, we're going to add two. The first one is tabs. And for now, we'll declare an Alpine instance there, or a component, and we'll just spit out the default slot. Okay,

directory, we're going to add two. The first one is tabs. And for now, we'll declare an Alpine instance there, or a component, and we'll just spit out the default slot. Okay, so if I reload it, now it's failing because there's no tab component. So we'll create another one for an individual tab. Now I'm going to do the exact same thing here. But real quick, don't forget that for a tab, we're passing in this name prop. So this should be the name of the heading, the button that you click to switch to this particular tab. So with that in mind, let's declare the prop name, and then once again, declare a component instance. Now here's the cool thing. Sometimes you want to pass your php code to your JavaScript, and it ends up being really easy with this approach. So for example, if I want Alpine to know what the tab name is, I could do something like this, and then just echo out our php.

and it ends up being really easy with this approach. So for example, if I want Alpine to know what the tab name is, I could do something like this, and then just echo out our php. Okay, so let's come back to Firefox, refresh, and there we go. Now in this case, we don't yet see the headings. We'll have to figure that out. But I do see the body for each respective tab. So it sounds like for a single tab, we need some way to declare if it should be shown, right? So I could say x-show, and of course, if I set it to false, we're not going to show any of the tabs. But yeah, that of course should be state. So why don't we do it here. By default, we're not going to show the tab, and we'll bind that to the prop. Okay, so once again, give it a refresh, and we don't see anything. However, I'll show you a little tip. If I open up our inspector here, let's see if we can find it within a single section. Yeah, here are the three tabs, right?

and we don't see anything. However, I'll show you a little tip. If I open up our inspector here, let's see if we can find it within a single section. Yeah, here are the three tabs, right? So I'm going to select this first one here. And in Firefox or Chrome, I should be able to access it with $0. Now I have access to that DOM node. So sometimes you'll want to programmatically access a component instance. And you can do that in Alpine by accessing this __x property. So now notice this will give me our component instance. So if I want to figure out what the current data is, I could do this. A bit more low level, but it works. Notice here's the name and whether it's being shown. So once again, let's figure out the name of that particular tab. And it's first to go to the next one. Let's do the exact same thing again. You get the idea. Now here's the cool thing. If I were to change show to true, Alpine is going to

Discover Child Tabs5:42

tabs component, how do we access the name for each respective tab? Ask yourself that. And pause if you want. The answer, you have a couple choices. I'll create a split tab here. Now one option, you could do something like x-init, and then dispatch an event to notify the parent that you have a new tab. But don't go that path. You're going to end up with all of these different events being fired, and you're listening for it on the parent, and it just gets super messy for something so basic. Instead, what if we did something like this? After the parent tabs component initializes, let's run a function here. Now I want to show you something. If I were to grab the root element, I can use this $el magic variable. So that's basically this right here. And I could say, give me all of the children. And if you think about it, back in our welcome view, the children are this, each respective tab. So if I were to console.log this,

give me all of the children. And if you think about it, back in our welcome view, the children are this, each respective tab. So if I were to console.log this, and come back to Firefox, give it a refresh, we get an HTML collection of the three individual tabs. Now I can right-click here and say store as global variable. And yeah, if I get the first one, there's our first component. And once again, we can use that trick here, where we get the data and we show it programmatically. Or we can fetch the name. So why don't we grab all of the children and pluck the name from each? And I have no problem. Normally, you might want to be a little bit careful. But in this case, the tabs parent component and a tab child component are forever linked. There's no scenario where those aren't connected. So I'm fine if they have awareness of each other, so to speak. Now I would love to be able to do something like for our HTML collection

linked. There's no scenario where those aren't connected. So I'm fine if they have awareness of each other, so to speak. Now I would love to be able to do something like for our HTML collection do something like forEach, but it's going to say undefined here. And that's because I'm not dealing with an array, I'm dealing with an HTML collection. So a little tip here, if I want to cast it to an array, let's just destructure it like so. And now we have an array of those items, at which point I can call forEach. Okay, so let's grab the names. I'm going to not forEach, you could do it if you want, but map is more appropriate here. map over each of the tabs, and I'm going to return the tab, grab the component instance, the data, and the name. Okay, so now we have an array of the tab headings we want. And this is how we allow for it. Let's grab that, come back to phpStorm. And yeah, we can start by saying the tab headings,

Okay, so now we have an array of the tab headings we want. And this is how we allow for it. Let's grab that, come back to phpStorm. And yeah, we can start by saying the tab headings, and let's go ahead and store that here, that'll be an array, that will be equal to this, l.children, that we want to convert to a standard array, like so. All right, come back to Firefox one more time. We'll take a look at the parent here. Find the component, find the data, and then grab the tab headings. And there they are. All right, let's get started. We're going to add the headings up here. Yeah, now we immediately have a new problem. Think about it. Right up here, we were saying get the children of the root element. But now we're adding a new one here. So all of the children would be the headings and each individual tab. So it sounds like these really need to be wrapped.

Render Tab Headings8:53

get the children of the root element. But now we're adding a new one here. So all of the children would be the headings and each individual tab. So it sounds like these really need to be wrapped within their own div. And then we grab the children of that wrapper. So with Alpine, I can give that a reference. And we'll just call it tabs. And then right up here, we're going to say I don't want the root element anymore. I want the ref called tabs, and then get me the children of that div. That solves the problem. Okay, but anyways, here, let's iterate over our tab headings. So I'll say for tab in our tabHeadings. And now as a general good practice, we should always key them. So I'll just key it by the index. And that helps Alpine keep track of it. And then yeah, let's just create a button and set its text to the tab itself. And we'll give that a shot. If I come back to Firefox, there you go, you have your tab headings.

track of it. And then yeah, let's just create a button and set its text to the tab itself. And we'll give that a shot. If I come back to Firefox, there you go, you have your tab headings. So now let's switch back and say, well, when you click on this button, let's change the activeTab. And I said activeTab there. So why don't we store it up here, activeTab, blank. And actually, let's put these on their own line. All right, now when you click on a heading, the activeTab will be equal to the heading of the tab that should be visible. Alright, so that's good. We're tracking the activeTab. But what about the default active tab? Well, let's go back to welcome. Maybe we should declare it here, the activeTab. And why don't we say second. So this would represent the heading of the tab that should currently be selected, the activeTab. Alright, so we're going to accept a new prop up here, props, active. And yeah, here's a cool thing. We can very easily

Sync Active Tab State10:28

heading of the tab that should currently be selected, the active tab. Alright, so we're going to accept a new prop up here, props, active. And yeah, here's a cool thing. We can very easily pass PHP code to our JavaScript as simple as this. Let's have a look. Give it another refresh. And then once again, let's select the parent there. And the active tab is set to second. Okay, so the next step, this gets a little bit tricky. We need some way to inform the child tab components that the selected tab, the active one, has in fact changed. And they need to toggle their display based upon which tab was chosen. So a couple options to consider. One would be to dispatch an event. But the only issue here is you're firing a global event. And if you plan to have more than one set of tabs on a page, maybe you have multiple sections, each with their own sets of tabs. Well, if you don't name space it properly, and if you're not careful, all of those tabs will pick up

one set of tabs on a page, maybe you have multiple sections, each with their own sets of tabs. Well, if you don't name space it properly, and if you're not careful, all of those tabs will pick up on this dispatched event. So I'd rather not do that. Because tabs and their children are connected, I'd rather just be a typical parent and make the children do what I want them to. You know what I mean? So let's do this. Let's create a method called toggleTabs. Now here, I want to access all of our tabs. But again, I don't have access to that. So why don't we do this? Let's store the tabs on the component here. And then I could say tabs equals, and then I'm going to grab this right here. Then I can just reference it. Okay, so now within our method, I can access this.tabs. So all we're going to do is iterate over each of those tabs, and then say, like you learned, read the data and update its show property. So we'll set this to whether or not the name of the

So all we're going to do is iterate over each of those tabs, and then say, like you learned, read the data and update its show property. So we'll set this to whether or not the name of the respective tab equals the currently active tab's name. And yeah, I think that'll do the trick. It kind of looks funky, doesn't it? But really, it's just this portion that seems scary. And those are just properties. So for example, if I were to remove this, it's easier to understand. For each of the tabs, set that respective tab's show property, which is the visibility, equal to whether or not the current tab's name is equal to the active tab that we want to see. If those match, then show the tab. If they don't match, then hide the tab. That's all we're doing there. All right, so now we come back to our initialize method. By the way, if you come from something like Vue, this is effectively like your mounted method, just to give you a perspective there.

Style And Refine Tabs13:04

All right, so now we come back to our initialize method. By the way, if you come from something like Vue, this is effectively like your mounted method, just to give you a perspective there. So find all of our children, click out the headings, and then toggle the tabs. Come back, give it a refresh, and it works. The active tab is second, so we see the second tab. If I come back and let's set the active tab to third, then we'll see that one. Okay, but now there's no indication here at all. So why don't we add a little bit of CSS? We'll do it right here on the button. Let me reformat. And yeah, we'll start by saying maybe add a little padding to the button. Maybe some on the top and bottom as well. Maybe use small text. Maybe round the corners. And let's see what we have there. Okay, now maybe when you hover over it, it should have a background color. We'll just stick with blue. All right, hover over it.

And let's see what we have there. Okay, now maybe when you hover over it, it should have a background color. We'll just stick with blue. All right, hover over it. And maybe we should make the text white as well. Try again. First, second, third. Yeah, again, we're not going to win any awards, but we just want something basic in place here. So let's come back. And now we'll say here, I could use an object syntax, but I don't think I need it. We will say, if the current heading is actually the active tab, so I could say if tab equals the activeTab, then it's the current one, right? So let's set the background color to blue and the text to white. Otherwise, do something else. So let's see if that works. And no, it didn't. What's the problem? tab is not defined. tab equals activeTab. Oh, sorry, missing a quote. All right, one more time. And there you go. We have our currently active tab.

we already had this method here to toggle the tabs. So let's just call it again. Let's try it out. Third, second, first. It's so easy once we figure out the basic formula for how to look for the children. Okay, what else? If you want, you could clean this up a little bit. So, for example, we're kind of saying foreach of the tabs, update its show if it's the current tab. So what if we open a single tab, and we'll add a method here. So once again, let's put these on their own line. name can just be like that. Yeah, and now we'll add a method like showIfActive. How about that? And we'll accept the activeTab. And we'll just say this.show equals, and then check if the name for this respective tab equals the one you passed in. And I think that's it. So now if I come back to tabs, we can clean it up slightly. So I can say showIfActive. Is that what we called it? And then we'll pass in the currently active tab.

And I think that's it. So now if I come back to tabs, we can clean it up slightly. So I can say show if active. Is that what we called it? And then we'll pass in the currently active tab. All right, let's see if that still works. No, of course, it doesn't work. activeTab is not. Sorry. One more time, and it works. Third, second, first. So yeah, again, we could have dispatched an event to avoid some of this, but I think it ends up being a little cleaner with this approach, and also easier to understand. So now think about it. If on a different page, or even we add a horizontal rule there, we paste in another instance, and then here, let's just say paddingY, 10, or maybe margin. Anyways, if we come back, yeah, we can browse these tabs exclusive to one another, and they won't interfere with each other. So yeah, now the only remaining step would be to add whatever accessibility links you require. And now usually I can never remember,

getter property, you can do that as well. And I'm sorry. Anyways, I will fill in the rest of those on my own, but here is your completed tabs component.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟