Full Stack Web App using Vue.js & Express.js - Part 4

Creating a Full-Stack App with Music Lyrics: Part 4

As we continue our journey through creating a full-stack app, we're now working on integrating music lyrics into our application. We've created a basic structure for our app, including a database to store song information and a frontend to display the data. In this part of the tutorial, we'll focus on adding a view button that allows users to navigate to individual songs.

To achieve this, we need to add some functionality to our frontend code. We'll start by modifying our existing code to include a "Let's See Song Title" section, which will display the title, artist, and genre of each song. To do this, we'll use the `song.title`, `song.artist`, and `song.genre` properties to access the data stored in our database.

On one side of the screen, we'll create a "Left Side" section that includes a view button. This button will navigate users to the individual song details page when clicked. To achieve this, we need to add some JavaScript code that binds the `song.id` property to a URL parameter when the button is clicked.

For example, our HTML code might look like this:

```html

{{ song.title }} by {{ song.artist }} ({{ song.genre }})

```

And our JavaScript code might look like this:

```javascript

class ViewButton extends React.Component {

constructor(props) {

super(props);

this.state = {};

this.onClick = this.onClick.bind(this);

}

onClick(event) {

// navigate to individual song details page

navigateTo(`/song/${this.props.song.id}`);

}

render() {

return (

);

}

}

export default ViewButton;

```

In this code, we've created a `ViewButton` component that includes an `onClick` event handler. When the button is clicked, this handler navigates to the individual song details page using the `/song/${this.props.song.id}` URL parameter.

We'll also need to add a new route for navigating to individual songs. We can do this by adding a new file to our project's routing configuration. For example:

```javascript

import { Route } from 'react-router-dom';

const routes = [

{

path: '/',

component: Home,

},

{

path: '/song/:id',

component: SongDetails,

},

];

export default routes;

```

In this code, we've added a new route that listens for the `/song/:id` URL parameter. When this route is matched, it renders the `SongDetails` component.

Finally, we can implement the individual song details page by creating a new file called `SongDetails.js`. This file will display the title, artist, and genre of the selected song.

Here's an example implementation:

```javascript

import React from 'react';

import { navigate } from 'react-router-dom';

class SongDetails extends React.Component {

constructor(props) {

super(props);

this.state = {};

}

componentDidMount() {

// fetch individual song data from database

const id = this.props.match.params.id;

fetch(`/song/${id}`)

.then(response => response.json())

.then(data => this.setState({ song: data }));

}

render() {

return (

{this.state.song.title}

By {this.state.song.artist} ({this.state.song.genre})

{/* display other song details here */}

);

}

}

export default SongDetails;

```

In this code, we've created a `SongDetails` component that fetches the individual song data from our database using the `/song/${id}` URL parameter. We then render the title, artist, and genre of the selected song.

That's it for Part 4 of our full-stack app tutorial! We've added a view button that navigates users to individual songs, as well as implemented the individual song details page. Stay tuned for the next part, where we'll continue building out our application.

"WEBVTTKind: captionsLanguage: enhey everyone i'm cody and welcome to part four of building a full stack web application using vue.js and express.js so if you remember in part three we built this login panel and we built that login endpoint in the backend we also brought in view x to kind of manage some of the shared state of our application such as the token or the user or this boolean is user logged in and we used it to hide and show different things in this header so another thing i'm going to do are i guess what we can start doing now is let's add a log out button and okay so to do that we should be familiar by now as how to add a button to that header so if i go to the header in my components tab i could easily just copy and paste that copy pasta and then go ahead and say display it if the user is is logged in right so i'll just say log out what we could do is when the user clicks this we could just say log out and then down here under methods we could just go ahead and add a log out method which is going to do a couple of things the first thing it's going to do is dispatch so i do this.store.dispatch it's going to set the token equal to null and then we also want to set the user equal to null and because we're calling set token of null remember in our store it should set is user logged in to false not sure if this is the best way to do it but hey it works for now um and then finally i think we could probably go here and just do it to do redirect to home page or something in fact i'll just i'll just do that now right so i'll do router.push and then i'll say go to my root so go ahead and save that header file and if i go back here i have a log out button if i click it it logged me out you saw that it did set token and it also did a site user and now in our final state of our app we have token is null users null and is logged in is also equal to false and then of course up here login and sign up are displayed now because we are logged out right so go ahead and log back in so i think the next step is we can actually start working on that whole browse button that i added earlier in part three so if i go back to the header i have this to do implement me comment i'll go ahead and uncomment that stuff and what we want to do actually let me go over here let's go ahead and copy this button you know this button's got some good styles so go here and say if the user is actually i don't need to do an if just always display the browse because you want users to be able to access your tabs regardless of if they're logged in or logged out so what we can do here is we'll say when you click on this browse button it's going to take you to the songs route so then of course we don't have a songs route so if i were to go back to my router and i add a songs into my routes array and then here i'll just go ahead and add a songs component which again we do not have yet so i'll go ahead and say songs.view and i should probably find some type of like generator that makes these blank files for me i guarantee you vs code has it but i just haven't really taken the time to look at it so anyway that's going to be our bare bones file in fact i'll just do blank dot view here just put a blank template there so i can use that in the future all right so we have a link called browse and when we click it it takes us to that songs url and the first thing that we want to do is we want to have a panel which displays all of the songs so starting off we could have a panel called um let me just clean this up a little bit go to the register page i'm going to grab all of this all that goodies and go ahead and just paste it right there so that now we have a blank register tab which we don't really care about so i can just say songs and in here we can just go ahead and clear that out all right so we have a blank panel which we can put all of our songs or you know song renders here and so one thing you might notice now is that we have all these different pages which have this like this panel and i'm copying pasting code throughout a majority of my application right so if you notice that you have the same component which is being shared throughout your application by just sharing code what you can do is create a new component so i'll say panel.view and then inside this panel i'll go into blank put in the panel cool beans we actually want to just go ahead and create that same type of panel structure so if we go back to the register and find the div where we declare that panel so i think it's starting here boom all right so we have a panel now and we want to make this a very generic component so it's a panel that you can change the title as needed so i'm going to change that to curly brace curly brace which is a binding a one-way binding in view so basically if title is defined in my data so down here remember we have data or if it's defined in your props which we'll cover in a second so here i can say title is equal to hello world so if title is defining your data which it is on line 40 it's going to render whatever the value is right there and then something else we want to do is just go ahead and add a slot here and i will show you what a slot does in one second so i'll go ahead and remove all this extra jazz that we don't need and go ahead and save this file so again this should make sense we just made a new view component called panel and it's just going to display that white panel with the top cyan toolbar and then it has the content here with some padding and then a slot so if i were to go back to let's say that songs page i can go ahead and import that so i'll say import panel from component slash panel make sure to capitalize that right and then here i can say i want to be able to access that components so i'll say i want to be able to access the panel and then here remember that same code that was copy and pasted throughout those three different pages we could just say panel and close that off and now if i were to save this file we get hello world no slot content defined all right so that's that should make sense we're just making a sub component and displaying it inside another component and we're including it here on line 13 to be able to access it on line four and there's a little bit of magic behind how this panel gets named basically if your panel is named like my awesome panel this is going to be converted to my awesome panel just like that so it's a little bit of magic on going on behind the scenes that you kind of have to know going off of what i was going to talk about for slot basically if inside a parent component you want to pass down something so let's say here i want to pass down a something special like an h3 yo yo yo and then maybe like a paragraph tag and this is the one thing i sometimes hate about autocomplete maybe i just don't know how to use it correctly huh all right so now when i save this you see yoyoyo hello there i'm a paragraph tag we inspect this element you can see oh wow we have an h3 and a p that was kind of passed down into that panel slot so if you remember here we have a slot and basically what this is going to do is we're going to take when you do this when you declare some type of content inside panel you're basically just copying and pasting it over there so whenever this panel subcomponent renders it just takes whatever is declared inside panel and puts it directly into wherever you had that panel or wherever you had that slot defined and you can also name slots i think you can do like name equals like hello and then i could say like slot name musical to hello and this time if this doesn't work i'm going to go ahead and look up the docs all right so this is going to be put in the slot hello and then if i do buy five five five a little bit of backstreet boys now anyone okay so if i go here and do is that in sync don't even know man let's do electronica so now if i add a buy name slot i think this should you know what i don't know what i'm doing so let me look up the docs so you guys can watch me struggle with this just as well so you can do name slots down here inside you can do slot name equals whatever and inside the parent you do the slot equals the name okay so i had this right in the songs or not in the songs in the panel down here i have these two slots with different names hello and bye and then if i were to do i already forgot what i was looking at oh if i do slot equals by instead of what i have there and go back i think i actually need to like change this to uh div there we go okay so again i haven't really messed too much around with slots or name slots but it's just good to know that you can name the slots and kind of insert html from a parent component down into a sub component like whichever way you like but since we've kind of already covered what slots are we can just go ahead and get rid of all that since you should understand or at least kind of understand what i was trying to achieve there so again go ahead change that up now we want to make this sub component panel a little bit more modular so something useful is we want to be able to pass in a title so let's say we want to pass in something called songs instead of having data title defined here instead we can have props defined and just define title like that and we can actually get rid of data because we're not even using data in that case so now if i go back we see that probably didn't save something one second there we go yeah sometimes the uh hot reload doesn't reload you have to do a hard refresh probably have to look into that but now we can easily just pass in whatever we want inside of an attribute so you saw i just added hello and it got passed down to my my panel and that's because we're saying this panel has the ability to be passed in a title prop and then we're using that title prop here so very cool very cool if we wanted to let's say go back and refactor so let's go ahead and just go back to those other pages like register go ahead and import panel now it's kind of a pain that you have to declare and import in every single one and i'm pretty sure you can do a global include in view but honestly i think it makes more sense to not even use globals because then when you try to copy and paste stuff from one app to the other you're not really sure what the heck like why did it fail it's like oh because you have like 15 globals it's trying to access of course it's going to fail but if you just have it like explicit that this requires a panel component and that's it it makes it much easier to understand like how everything is working so for the register and login pages we went ahead and included the panel and up here i could just say panel titles equal to register and i'm going to go ahead and just get rid of all that stuff uh i think it was just like that template layout flex panel typically i'll flex panel i don't think i need that all right let's see if the register page is working so i go to sign up and a hard refresh just in case and yep it's still working so that's awesome and then i go to the login page again we can just say a panel is going to be called login and get rid of all that extra fluff and then get rid of that and say that could be a panel and unindent all that stuff so now we go to login page hard refresh just in case it's also working just as fine as the other panel instance cool so again should all make sense recap i made a panel sub component which takes a title as a prop and you can pass that in and now in my register login in songs page we simply simply just call panel pass it whatever title we want and it will render that panel for us all right so now at this point we have the songs panel and we want to display a list of songs right or tabs in this case we're calling songs and if you dive into a song it's a tab but anyway so if we go to the songs panel we can first assume that we have an array or collection that's going to be returned from the back end and we need to loop over it and render it x amount of times right so in vue.js you can do a v4 like this so basically this is a for loop so i can say for song and songs we want to go ahead and render something so if i were to go to make a data thing and return songs as an array uh actually i'll say um float on modest mouse album good news for people who hate or love bad news i think that's the album i don't know so first i need to wrap that in an object oh i think i'm just forgetting to bind a key nice okay so the issue there is anytime you do a v4 and in the error like if i go back to the error it was actually telling me exactly what was wrong i just wasn't reading it so it says elements in iteration e or iteration expect to have a v bind colon key directive so what that means is we need to pass it a key directive saying okay the title will be the unique identifier for the song so now if we were to go back to here we see that it's printing out float on modest mouse good news for people who love bad news and if i were to add just little hyphens in between there we see let's bring that out and just kind of show you what the 4 or v4 is doing if i were to copy and paste this like a lot and save it we see that it's rendering let's see five times and that's because i have five objects inside this songs array so at this point it should make sense as to how and why the v4 is working so it just loops over the songs array for each one we have access to that song object we're just telling it to print out the title the artist the album and then we also need to pass in a key and that's being passed down into the slot of the panel and then rendered here so what we want to do at this point is we need to dynamically load songs in from a back-end right so if i were to instead just set that equal to an empty array and i'll just go ahead and delete all that actually i think if i set that to null let's see what happens okay so i'll just set it to an off right now but what we want this component to do is the moment it's mounted onto the page we want to go ahead and do a request to the back end for all the songs um so at this point you remember how to make services so if we were to copy and paste authentication service and we can rename it to songservice.js and in here we could just say make a index call it's a get request to slash songs doesn't require any credentials or anything so basically we have a song service which will make a get request to the songs in point and that should return some amount of songs to us and you can name this whatever you want like it could be called get all songs um but if you use like ruby on rails i think index is typically used for just like slash songs show is used for like songs of id so i like to keep it consistent and you'll see me using these same like paradigms uh in the back end most of the times for like your crud methods but again you're welcome to name this whatever you like to make it make more sense to you in your web app so anyway we have a services a songservice.js file and we can now use that so i'll go ahead and do import song service from services song service and then inside the mounted function we can just say song service dot index and i guess who const or actually this dot songs is equal to await song service index and of course if we're doing a wait we need to make sure we have async here and this is going to do a get request the moment the page is mounted or the moment the song's view component is mounted on the page so if i save this and go back go to the network tab and refresh the page with a hard refresh we see that it makes a get request here to the songs endpoint of course you get a 404 not found because we haven't yet implemented a song's endpoint so with that being said let's go ahead and implement the songs endpoint in the server so i'm going to go ahead and just minimize clients go to the server i'm going to first go to routes and we need to get a songs in point so i'll do an app.get meaning listen for get request on the slash songs in point i'm going to go ahead and just pretend like we have a songs controller here and pretend like it's already defined and we can just do an index call on it and save that and now at this point we don't have a songs controller so let's go ahead and just copy and paste this one name it songs controller dot js and then it's pretty much gutted out we don't need json web tokens we don't need config and we don't need any of this stuff so i'll just remove pretty much all this stuff and just change this one to an index keep the try catch because it's going to be useful so we have a songs controller now with an index function and what do we want to do well first of all we don't have a song model defined right so if we wanted to keep track of all the songs that are in our database we're going to have a song model so i'm going to do a song.js file and again just copy and paste existing code and get rid of that you might as well just keep that format in case i need to do something special don't need to worry about hashing it don't need to worry about any of that okay so what exactly would go into a song so if we think about it we would have a title and that's just going to be a string we're going to need an artist we're going to need a genre we're going to need an album we're going to do an album image which is just going to be a string that points to some freely hosted i don't like image girl or something image title or image album art we're going to need a youtube id because we want to kind of link or display an embedded youtube player for whatever tab we're trying to learn it'd be nice to keep track of lyrics and of course most importantly we need the tab for the song so this shouldn't be foreign to you at this point we're just declaring a new sequel eyes model called song it just has these attributes here and they're all going to be strings actually this should be text because typically string and sqlize i think is a 255 var care so 255 character limit so hopefully the images the image url doesn't bypass that i'll go ahead and rename it to image url um then youtube id is only like what eight characters or something so work should be good lyrics and tabs could be a lot of characters which is why i'm setting them as text so we have a songs model we have that songs controller at this point we can go into our songs controller and say we want to create the song using cons song is equal to song dot create rec dot body and that's going to call our sequel eyes object pass it direct.body whatever we pass in it'll create us a song object and then we can of course just send that back like so and actually i am creating the wrong method i'm actually creating the post so sorry about that but anyway we're going to need a method to create songs so i'm just going to go ahead and create a post method here and then above that i'm going to create an index method so again apologize for jumping around but so assuming we have an index method here we can actually do a find and then we can pass it where and just pass it an empty where clause so that will return us every single song and in fact i don't even think actually i think we need to find all here so instead i'll just do find all limit of let's say just give us back 10 songs because i don't want the ui to be overloaded with you know potentially a million songs change out the songs change that to songs okay so now we have two endpoints in the controller we have this index method which is going to find all the songs in the database and limit it to 10 and return that back in the payload and of course if there is an error we can just say an error has occurred trying to fetch the songs and for posting i can say an error has occurred trying to create the song all righty and then lastly i think we need to add a post method for the songs so if i do a post request to slash songs that's going to call the songs controller.postmethod which is again what we accidentally created and we also intentionally created our index method and at this point i think everything should be okay knock on wood what we can do now is let's go ahead and create a new endpoint to try to test with let me rename this to songs and i'm going to change that to a get request change it to songs save that if we hit it it should return an empty array let's see is fulfilled is rejected oh duh all right so i haven't actually restarted my database yet so let me just create these anyway so i say create song get all songs i just say get songs and then for this one it's going to be a post request to these songs in point and it's going to contain all the necessary data which you see here in fact let me just make this a little bit easier that's weird you can't do that in visual studios huh good thing i have adam opened all right so we need to be able to easily create new songs here so if i try this i think this should crash as well because obviously we don't have that defined in fact now i'm looking at this why is this returning a 200 is fulfilled equals false is rejected equals false because i'm pretty sure we should be getting this catch let me just i'm just going to try something out really quick well this must be crashing at a earlier point must not be at this point maybe it is bear with me just one second it's always fun looking into why stuff's working and why stuff isn't working yeah so i guess if your database table doesn't actually exist sqlize will not throw an exception when you do song.create oh i know why so this is the one pain that i've noticed with using async and wait is that for some reason if you forget to put that keyword await bad things happen because you'd expect that exception to be caught here and then thrown down here right but for some reason it wasn't so now when i change it to a weight an error has occurred when trying to create your song and we're actually catching that exception here right so async weight is also something that i'm trying to learn i've i've been using promises since the beginning since i started working so since es6 is allowed async and await i'm starting to try to use that more but i haven't really used it much in node but yeah just remember do not forget you're await if you're trying to make a promise call like this all right so now that we're done trying to fix that bug if i go back to app.js and i say force true remember we can kind of clear the database using that and save the file it should have restarted and dropped all the tables which it did and i'll go ahead and set that back to false save it and we get those tables recreated so now at this point okay take a breather that was a lot of work nice nice fun debugging we can now start posting songs so if i wanted to say float on artist is modest mouse genre is alternative rock or something album blah blah blah i'm actually going to find real album urls so we can actually start playing around with this so i'll say mod is mouse go to images this one looks good go to view image copy image address youtube id so now i can go to see modest mouse youtube oh hey float on number one it's probably just my history so put that in the youtube id and i'm actually going to do real data because it makes it a lot easier to design and see what your app looks like with real data but for lyrics and tabs maybe i should not worry about doing that because it's going to be a lot so anyway if i were to save this and just send it to the endpoint it's going to create that song and send it back to us and now if we were to go to get songs hit that end point it returns us an array of all those songs so if you remember now in the ui we are already set up to fetch from that songs in point so when i refresh the page it's hitting songs over here which is going to return us that one song inside of an array and the reason it's rendering these is because we need to update the key so if i go back to the client and go to songs and go to the key what i actually want to do is probably set it to the id that's the unique identifier for the song so i say id go back over here that's why i keep forgetting it's not i need to do um the response that data so it should be that is actually what i'm looking for there we go all right so i'll make a mental note to just always remember to do dot data because that's how axios returns us our data cool so just i'm probably going to jump around again to a a way to create songs mainly because that was very painful to do it in a ui at least we have an end point here that we can just quickly create songs if needed but it makes it easier in my opinion to be able to create and fetch songs from a ui so i think the next step is let's go ahead and work on creating a song by having like songs create endpoint all right so to create that create songs view or whatever i can say i'll just say create songs dot view create song dot view okay go to my blank paste that in and then of course go to our router and we need to put in that new view so here i could do song slash add and i could say or she'll say create since you know songs hyphen create create song import that create song component that we just created and go ahead and save that and make sure we can hit song create up here and we can so what would be useful is we need to have the same amount of input boxes for all those attributes that we have for our song model so if i were to go here and just say data and then return that array remember we have all those different attributes let's see if i can find them really quick go to songs go here alright so we have all the same attributes which are on our songs model so at this point we need to create an input field or text field for all of them so the first thing we can do if again we're probably going to wrap it in a panel just because it looks nicer so i'm going to say import panel from components panel and then down here i'll say components panel which gives us access to that custom panel thing that we created and i'm going to say panel title is equal to song metadata and inside the metadata panel we can go ahead and create a text field for all the metadata related stuff so if i go to v text field in fact i much rather just copy and paste this from like our login controller so go ahead and copy this go back to create song and put that in right there and the label here is going to be title and it's going to be a type of i guess text i could just type off i think but basically v model is going to be text or title so if i save this go over here we have a title thing awesome and we want to do the same for all the other stuff so we need one for artists we're gonna need one for genre we need one for album we need one for album image url so i'll just go ahead and copy this what is left lyrics in tab oh and youtube id and for the other ones i'm actually going to be using a multi-line text field so to start off let's go ahead and just um save this make sure this seems like it creates all the necessary metadata inputs which it does cool go ahead and just minimize this a little bit so we can see it all and what i want to do here is on the left i want to have the metadata and on the right i want to have a much larger view of the lyrics in the tab so what we can do is using that whole v layout thing so let's see be layout and then here we can say v flex and i want to flex it of a six and just put all that stuff that was defined in the panel inside that v flex save that and we see that it makes it a swift of six in fact that's a little bit too big let's make it a four or five maybe just a four but then underneath this we can just go ahead and make another v flex that's going to be a width of i think the opposite of that so 8 9 10 11 12 columns out of the 12 in this beautify framework and what we want to do now is for the other ones which would be of course tab and lyric tab and lyrics we want to go ahead actually update the label as well we can add a multi-line attribute to v-text field and that's going to basically make it multiple lines so you see here we can do new lines and stuff like that and you notice here i completely forgot to put that in a panel so i'll put panel here i'll do title and i'll do song structure maybe there's a better name for that but that's what we're going to do for right now save that we're given a panel that says song structure and i want to give a little bit of padding or margin to that so i could say class margin left of four maybe two we'll see what that looks like i guess two is okay it's really small space but that's good enough all right so we have now two panels and all of these are going to be updating the song data down here and we also finally want to add a button to create so if i were to go down here and just say v button in fact i'm not going to do this off my head anymore too much to remember to put that here and i'll say create song and on click it'll call create we don't have a create method so again let's go down here and say methods create and then call api cool so we have a button called create song which will hopefully send all this stuff to the back end so at this point if you remember under services we have a song service has an index call what we want to do is add that post call and we could just pass it whatever song data here make it do a post request to the songs in point and pass the song so here i can say import song service from services song service go here and say post and this dot song and at this point song is not defined so let me just wrap all that stuff inside something called song indent that one and then anywhere we have b model i'm just going to say song dot and again wrap this in a try catch just in case for whatever reason this errors out for right now we don't really need to display a message to the user we may want to say like hey like this stuff has to be required or defined and we can actually do that in one second but first of all let's make sure that this is working as intended so if i were to go here and say abc 123 and just fill in with some blank data and click create let me go to network tab first and clear it and hit create song we see that it does a request to slash songs with a post we got back at 200 okay we got a response back with all the song information and right now it just kind of stays on the page which is not that great what i'd rather do is just redirect us to the song it created but since we don't have a way to view the song we just created let's go ahead and just go back to this dot router.push let's go back to songs so i'll save that do some more stuff here and now when we click create song we should go back to our songs page and look it's creating the songs from that's create songs endpoint that we've been using all right so that's pretty cool um maybe we could add a button here to be able to dive into that create songs uh whatever it's called view so to do that if we go to where are we doing that so in our songs panel here again what i'm trying to do here is i just want to add a fab button here so it looks like a plus sign with a circle when i click it it'll navigate me to that song that i'm trying to get to so i think what we can do is i think we may need an additional slot so if i go back to panel this is how you do this in beautify basically you just have a v button here and also do a v icon and give it an ad icon i'm not sure if the icons work yet let me just see if something shows up yeah i don't think icons work yet because i haven't even included the style sheet for the material design icons so i think that's an easy change let me just go to the index html file really quick go ahead and add that in and then hopefully that will refresh and have a plus sign yes okay so another thing that forgot the setup as you just saw let me just i'm getting overwhelmed there's too many tabs open so the icon is another view thing that you can do and just pass in the name of the icon and there's a bunch of material icons so if i were to go to material io icons any of these can be displayed so if i want to change it to circ check circle like say check circle save that go back to my page it's a check circle but we want to add so let's go ahead and keep it at add but originally we wanted a fab icon right so in order to achieve that there's a couple of attributes you need to add to your button so the first one is of course add fab so if we save that i think the button will become round awesome and then if we do class uh cyan accent 2 just to give it some color maybe i'll just do green you know green for add i don't know i'm not a designer but yeah i'll do what i had before it probably looks better all right so really light cyan add button we want uh let's see if we add light it makes the color oh yeah i'll keep light if you don't know if you saw that but the the font color is darker when you do light i can say i want it to be a medium button you could also do something like large here so if you do large it's going to be much larger but i'll keep it at medium i want it to be absolute positioning so you see how that changes to be directly in the center and then i want it to be on the right and i want it to be in the middle so the reason why this is over there is because i do believe this is supposed to be in the toolbar so if i were to cut this out and put that in the toolbar instead it gets added right there and so what i was going with or going at originally is we need to have another slot so i'll say slot name is action i guess we just name it action for now and we want to be able to let's see if they don't have it defined we don't want to do anything so i'll do this i'm going to cut this out and we actually want that to be configurable and passed in from our panel because we don't want every single panel to have that action button necessarily so what we can do is we can say div slot is equal to action and i'll paste that code there save that and our button will show up over here in the top right in fact i think we could just add it to this if we wanted to and that might make it go back to where it was yes cool so basically by adding slot equal action we're passing that down to the panel and rendering it right there in the correct position that we need and so what we can also do is i'm going to use a router link in this instance where i can say if someone were to click this go ahead and go to the name songs create i think that's what we named it all right so let's see how this looks if we were to instead make this a slot so position got jacked up a little bit but hey it's still working as intended good thing to do when your program is just mess around with stuff like see see what happens if you change around stuff or you can go to the docs and re re-read the docs but again since router link seemed to has messed up the positioning of that plus sign instead i am just going to go here and say add a click listener and say navigate to and i'm going to say name is songs create instead of using router link and again if you have a better way of doing that like if there's an already a directive where i can just say like navigate to let me know maybe i should actually read the docs after this make sure it's called songs create and inside methods we need to create that navigate to method i'll say route say this dot router dot push route cool so easily navigating through all of our pages that's all working we can go to this page and add our new random song and it gets added to our songs list and again this obviously looks pretty horrendous right now so we can kind of style this in a second uh but i think one thing would be nice to do is i want to make sure that all these are required i don't want people uploading bad data to my app so what we can do is if we were to go back to that create song view or component an interesting thing you can add to all these is required so if i were to add required the title we see here that a star appears next to it and then if i fail to actually add something in it doesn't turn red yet because i haven't defined any rules so first i'm going to add required to it and then second we can add a list of rules so if we pretend like we have a rules object with some required stuff attached to it we can go down to the data so i'll say data here and i'm going to add some rules which is going to be an object and basically the rule is we're going to say make the required thing make sure the value is actually defined so basically this is going to pass that rules dot required and it's going to make sure that the value is defined for that in fact i don't know if i need that rules i can just say required so up here i can just say rules is required go back here and see how it turns red and then it prints out required if you fail to fill it in pretty awesome so now i could just go ahead and do that for everything cool now they're all required now the only thing is we need to also check that everything has been filled in before we try to create and there might be a better way to do this but what i'm going to do here is simply just say are all fields filled in and i'm going to just loop over all the keys of my song and verify that every single value of those keys so i can say key so make sure that every single value using that key is defined because that's kind of what we we care about and then if for whatever reason you did not fill that in so if that's false we can say this area is please fill in all the required fields and then return and of course we don't have an error saying so i say error null and then up here we need to actually display it above the button i'll just say span class is equal to error and only display it if error is defined and what we could do here is say is that error is equal to null to kind of set it back to a default state every time you click the button this needs to be this dot song i think yeah alright so please fill in all the required fields let's actually make that a div and not a span and it's also super ugly as to why it's like that so i think beautify has a built-in error class so maybe instead i'm just gonna add a red alert or maybe danger alert so if i go back to view over here and just do danger alert color red and then go back here cool it's red now and we should not be able to fill in anything let me just refresh the page to make sure that goes away so we should not be able to fill in anything or create the song until we filled out every single field and i did and it added the song okay so for the last thing i'm going to do in this part of the video is just try to style these songs so if i were to just start with a blank slate and go to the songs panel it would be nice that for um to have these actually have like a nice style to them so with that being said let's go ahead and try to create a simplified layout here so if i were to go here and basically for a super simple layout we can just do v layouts v layout and then inside the speed layout is going to be so we're going to have a row here and inside the row we want to kind of split it up actually i think what we could do panel has songs v layout yeah let's just go with this and see what happens but basically we want a left and a right side so i'm going to do a v flex of six and then another one of six so we have a left and a right side and on the left side let's just go ahead and do a let's see song title so you do song.title here and i could do the other ones song artist and song genre so get rid of these and then on the right side we want to include an image i'll say class album image and we want to point that so in in a view if you do the colon i think it's the same as doing b bind so basically we want to bind that source attribute to whatever the song album image url is so hopefully if we save this let's see what happens all right so one thing we'll notice is that this image is expanded to its complete size so which is why we added this class album image here so if we go down to the scoped we can say album image is equal to width of 100 so it looks a little bit better there even so i think that's a little bit too big then we also want to center it so i'll do that all right so that looks a little bit better and for the title the artist in the genre we can say song title song artist song genre look at this font size of 18 pixels i'll give this one a font size of 24 pixels and then i'll give this one a font size of 30 pixels all right so that looks a little bit better now and then let's go ahead and just wrap all this into a song so i'll say give it a padding of 20 let's say height of 330 pixels overflow hidden because we don't want anything overflowing and then up here where we're doing that for loop i'll just say class of song cool so all the songs other than these that are missing the images are being displayed in such a way so it looks a little bit better still not that great but hey it it's a start and then what we want to probably add is a way to if i were to say like a view button here so i can easily go in and view the tabs of that song so we should know how to do that if we want to add it to the left column here we of course have to go here and say the button and again let's just go ahead and find a v button um let's see how about the create song button that's the great thing as after your app starts becoming larger you have a lot more copying and pasting resources so here i can say navigate to i'll say name song prams song id of song dot id and it's always nice to make sure you format your objects so they're very easy to change and read all right so now we have a view button which if we click it it calls navigate to which will go down to the songs or it will go to the song view and then it will pass a parameter called song id which will grab from the song so again right now we don't really have a song route so let's go ahead and add one and then we can implement that later in the next part so if i were to do song id here so path is slash song slash id what this does is it allows us to put in variables inside the url parameter or your url query or whatever you want to call it and so change that to shh song and i'll change this to just view song which means we have to come up here and say view song and over here components we have to say view song view and i'll go ahead and just create it from a blank all right so if we go back we now have a view button and if we were to click it it takes us to song one and the one is coming from the song id so remember in the database every time we create a new record it's going to assign it a unique id an auto incrementing unique id so then again if you think about the future we could just have this page load in that song information and display it so i think that's a good stopping point for this part 4 of the full stack tutorial again be sure to subscribe to my twitter it's in the description link if you want to get updates for when i paste the latest part 5 video and again feel free to leave me comments or give me suggestions or feedback as to how to make these tutorials better or if you have maybe a different way that you think i should be doing something in view because again this is more of a learning um effort on my approach it's not me trying to say i'm an expert i'm trying to teach you it's more of hey let's try to reinforce what i have learned from view and make sure i can teach it well all right so again thanks for watching and stay tuned for the next part that should be coming soonhey everyone i'm cody and welcome to part four of building a full stack web application using vue.js and express.js so if you remember in part three we built this login panel and we built that login endpoint in the backend we also brought in view x to kind of manage some of the shared state of our application such as the token or the user or this boolean is user logged in and we used it to hide and show different things in this header so another thing i'm going to do are i guess what we can start doing now is let's add a log out button and okay so to do that we should be familiar by now as how to add a button to that header so if i go to the header in my components tab i could easily just copy and paste that copy pasta and then go ahead and say display it if the user is is logged in right so i'll just say log out what we could do is when the user clicks this we could just say log out and then down here under methods we could just go ahead and add a log out method which is going to do a couple of things the first thing it's going to do is dispatch so i do this.store.dispatch it's going to set the token equal to null and then we also want to set the user equal to null and because we're calling set token of null remember in our store it should set is user logged in to false not sure if this is the best way to do it but hey it works for now um and then finally i think we could probably go here and just do it to do redirect to home page or something in fact i'll just i'll just do that now right so i'll do router.push and then i'll say go to my root so go ahead and save that header file and if i go back here i have a log out button if i click it it logged me out you saw that it did set token and it also did a site user and now in our final state of our app we have token is null users null and is logged in is also equal to false and then of course up here login and sign up are displayed now because we are logged out right so go ahead and log back in so i think the next step is we can actually start working on that whole browse button that i added earlier in part three so if i go back to the header i have this to do implement me comment i'll go ahead and uncomment that stuff and what we want to do actually let me go over here let's go ahead and copy this button you know this button's got some good styles so go here and say if the user is actually i don't need to do an if just always display the browse because you want users to be able to access your tabs regardless of if they're logged in or logged out so what we can do here is we'll say when you click on this browse button it's going to take you to the songs route so then of course we don't have a songs route so if i were to go back to my router and i add a songs into my routes array and then here i'll just go ahead and add a songs component which again we do not have yet so i'll go ahead and say songs.view and i should probably find some type of like generator that makes these blank files for me i guarantee you vs code has it but i just haven't really taken the time to look at it so anyway that's going to be our bare bones file in fact i'll just do blank dot view here just put a blank template there so i can use that in the future all right so we have a link called browse and when we click it it takes us to that songs url and the first thing that we want to do is we want to have a panel which displays all of the songs so starting off we could have a panel called um let me just clean this up a little bit go to the register page i'm going to grab all of this all that goodies and go ahead and just paste it right there so that now we have a blank register tab which we don't really care about so i can just say songs and in here we can just go ahead and clear that out all right so we have a blank panel which we can put all of our songs or you know song renders here and so one thing you might notice now is that we have all these different pages which have this like this panel and i'm copying pasting code throughout a majority of my application right so if you notice that you have the same component which is being shared throughout your application by just sharing code what you can do is create a new component so i'll say panel.view and then inside this panel i'll go into blank put in the panel cool beans we actually want to just go ahead and create that same type of panel structure so if we go back to the register and find the div where we declare that panel so i think it's starting here boom all right so we have a panel now and we want to make this a very generic component so it's a panel that you can change the title as needed so i'm going to change that to curly brace curly brace which is a binding a one-way binding in view so basically if title is defined in my data so down here remember we have data or if it's defined in your props which we'll cover in a second so here i can say title is equal to hello world so if title is defining your data which it is on line 40 it's going to render whatever the value is right there and then something else we want to do is just go ahead and add a slot here and i will show you what a slot does in one second so i'll go ahead and remove all this extra jazz that we don't need and go ahead and save this file so again this should make sense we just made a new view component called panel and it's just going to display that white panel with the top cyan toolbar and then it has the content here with some padding and then a slot so if i were to go back to let's say that songs page i can go ahead and import that so i'll say import panel from component slash panel make sure to capitalize that right and then here i can say i want to be able to access that components so i'll say i want to be able to access the panel and then here remember that same code that was copy and pasted throughout those three different pages we could just say panel and close that off and now if i were to save this file we get hello world no slot content defined all right so that's that should make sense we're just making a sub component and displaying it inside another component and we're including it here on line 13 to be able to access it on line four and there's a little bit of magic behind how this panel gets named basically if your panel is named like my awesome panel this is going to be converted to my awesome panel just like that so it's a little bit of magic on going on behind the scenes that you kind of have to know going off of what i was going to talk about for slot basically if inside a parent component you want to pass down something so let's say here i want to pass down a something special like an h3 yo yo yo and then maybe like a paragraph tag and this is the one thing i sometimes hate about autocomplete maybe i just don't know how to use it correctly huh all right so now when i save this you see yoyoyo hello there i'm a paragraph tag we inspect this element you can see oh wow we have an h3 and a p that was kind of passed down into that panel slot so if you remember here we have a slot and basically what this is going to do is we're going to take when you do this when you declare some type of content inside panel you're basically just copying and pasting it over there so whenever this panel subcomponent renders it just takes whatever is declared inside panel and puts it directly into wherever you had that panel or wherever you had that slot defined and you can also name slots i think you can do like name equals like hello and then i could say like slot name musical to hello and this time if this doesn't work i'm going to go ahead and look up the docs all right so this is going to be put in the slot hello and then if i do buy five five five a little bit of backstreet boys now anyone okay so if i go here and do is that in sync don't even know man let's do electronica so now if i add a buy name slot i think this should you know what i don't know what i'm doing so let me look up the docs so you guys can watch me struggle with this just as well so you can do name slots down here inside you can do slot name equals whatever and inside the parent you do the slot equals the name okay so i had this right in the songs or not in the songs in the panel down here i have these two slots with different names hello and bye and then if i were to do i already forgot what i was looking at oh if i do slot equals by instead of what i have there and go back i think i actually need to like change this to uh div there we go okay so again i haven't really messed too much around with slots or name slots but it's just good to know that you can name the slots and kind of insert html from a parent component down into a sub component like whichever way you like but since we've kind of already covered what slots are we can just go ahead and get rid of all that since you should understand or at least kind of understand what i was trying to achieve there so again go ahead change that up now we want to make this sub component panel a little bit more modular so something useful is we want to be able to pass in a title so let's say we want to pass in something called songs instead of having data title defined here instead we can have props defined and just define title like that and we can actually get rid of data because we're not even using data in that case so now if i go back we see that probably didn't save something one second there we go yeah sometimes the uh hot reload doesn't reload you have to do a hard refresh probably have to look into that but now we can easily just pass in whatever we want inside of an attribute so you saw i just added hello and it got passed down to my my panel and that's because we're saying this panel has the ability to be passed in a title prop and then we're using that title prop here so very cool very cool if we wanted to let's say go back and refactor so let's go ahead and just go back to those other pages like register go ahead and import panel now it's kind of a pain that you have to declare and import in every single one and i'm pretty sure you can do a global include in view but honestly i think it makes more sense to not even use globals because then when you try to copy and paste stuff from one app to the other you're not really sure what the heck like why did it fail it's like oh because you have like 15 globals it's trying to access of course it's going to fail but if you just have it like explicit that this requires a panel component and that's it it makes it much easier to understand like how everything is working so for the register and login pages we went ahead and included the panel and up here i could just say panel titles equal to register and i'm going to go ahead and just get rid of all that stuff uh i think it was just like that template layout flex panel typically i'll flex panel i don't think i need that all right let's see if the register page is working so i go to sign up and a hard refresh just in case and yep it's still working so that's awesome and then i go to the login page again we can just say a panel is going to be called login and get rid of all that extra fluff and then get rid of that and say that could be a panel and unindent all that stuff so now we go to login page hard refresh just in case it's also working just as fine as the other panel instance cool so again should all make sense recap i made a panel sub component which takes a title as a prop and you can pass that in and now in my register login in songs page we simply simply just call panel pass it whatever title we want and it will render that panel for us all right so now at this point we have the songs panel and we want to display a list of songs right or tabs in this case we're calling songs and if you dive into a song it's a tab but anyway so if we go to the songs panel we can first assume that we have an array or collection that's going to be returned from the back end and we need to loop over it and render it x amount of times right so in vue.js you can do a v4 like this so basically this is a for loop so i can say for song and songs we want to go ahead and render something so if i were to go to make a data thing and return songs as an array uh actually i'll say um float on modest mouse album good news for people who hate or love bad news i think that's the album i don't know so first i need to wrap that in an object oh i think i'm just forgetting to bind a key nice okay so the issue there is anytime you do a v4 and in the error like if i go back to the error it was actually telling me exactly what was wrong i just wasn't reading it so it says elements in iteration e or iteration expect to have a v bind colon key directive so what that means is we need to pass it a key directive saying okay the title will be the unique identifier for the song so now if we were to go back to here we see that it's printing out float on modest mouse good news for people who love bad news and if i were to add just little hyphens in between there we see let's bring that out and just kind of show you what the 4 or v4 is doing if i were to copy and paste this like a lot and save it we see that it's rendering let's see five times and that's because i have five objects inside this songs array so at this point it should make sense as to how and why the v4 is working so it just loops over the songs array for each one we have access to that song object we're just telling it to print out the title the artist the album and then we also need to pass in a key and that's being passed down into the slot of the panel and then rendered here so what we want to do at this point is we need to dynamically load songs in from a back-end right so if i were to instead just set that equal to an empty array and i'll just go ahead and delete all that actually i think if i set that to null let's see what happens okay so i'll just set it to an off right now but what we want this component to do is the moment it's mounted onto the page we want to go ahead and do a request to the back end for all the songs um so at this point you remember how to make services so if we were to copy and paste authentication service and we can rename it to songservice.js and in here we could just say make a index call it's a get request to slash songs doesn't require any credentials or anything so basically we have a song service which will make a get request to the songs in point and that should return some amount of songs to us and you can name this whatever you want like it could be called get all songs um but if you use like ruby on rails i think index is typically used for just like slash songs show is used for like songs of id so i like to keep it consistent and you'll see me using these same like paradigms uh in the back end most of the times for like your crud methods but again you're welcome to name this whatever you like to make it make more sense to you in your web app so anyway we have a services a songservice.js file and we can now use that so i'll go ahead and do import song service from services song service and then inside the mounted function we can just say song service dot index and i guess who const or actually this dot songs is equal to await song service index and of course if we're doing a wait we need to make sure we have async here and this is going to do a get request the moment the page is mounted or the moment the song's view component is mounted on the page so if i save this and go back go to the network tab and refresh the page with a hard refresh we see that it makes a get request here to the songs endpoint of course you get a 404 not found because we haven't yet implemented a song's endpoint so with that being said let's go ahead and implement the songs endpoint in the server so i'm going to go ahead and just minimize clients go to the server i'm going to first go to routes and we need to get a songs in point so i'll do an app.get meaning listen for get request on the slash songs in point i'm going to go ahead and just pretend like we have a songs controller here and pretend like it's already defined and we can just do an index call on it and save that and now at this point we don't have a songs controller so let's go ahead and just copy and paste this one name it songs controller dot js and then it's pretty much gutted out we don't need json web tokens we don't need config and we don't need any of this stuff so i'll just remove pretty much all this stuff and just change this one to an index keep the try catch because it's going to be useful so we have a songs controller now with an index function and what do we want to do well first of all we don't have a song model defined right so if we wanted to keep track of all the songs that are in our database we're going to have a song model so i'm going to do a song.js file and again just copy and paste existing code and get rid of that you might as well just keep that format in case i need to do something special don't need to worry about hashing it don't need to worry about any of that okay so what exactly would go into a song so if we think about it we would have a title and that's just going to be a string we're going to need an artist we're going to need a genre we're going to need an album we're going to do an album image which is just going to be a string that points to some freely hosted i don't like image girl or something image title or image album art we're going to need a youtube id because we want to kind of link or display an embedded youtube player for whatever tab we're trying to learn it'd be nice to keep track of lyrics and of course most importantly we need the tab for the song so this shouldn't be foreign to you at this point we're just declaring a new sequel eyes model called song it just has these attributes here and they're all going to be strings actually this should be text because typically string and sqlize i think is a 255 var care so 255 character limit so hopefully the images the image url doesn't bypass that i'll go ahead and rename it to image url um then youtube id is only like what eight characters or something so work should be good lyrics and tabs could be a lot of characters which is why i'm setting them as text so we have a songs model we have that songs controller at this point we can go into our songs controller and say we want to create the song using cons song is equal to song dot create rec dot body and that's going to call our sequel eyes object pass it direct.body whatever we pass in it'll create us a song object and then we can of course just send that back like so and actually i am creating the wrong method i'm actually creating the post so sorry about that but anyway we're going to need a method to create songs so i'm just going to go ahead and create a post method here and then above that i'm going to create an index method so again apologize for jumping around but so assuming we have an index method here we can actually do a find and then we can pass it where and just pass it an empty where clause so that will return us every single song and in fact i don't even think actually i think we need to find all here so instead i'll just do find all limit of let's say just give us back 10 songs because i don't want the ui to be overloaded with you know potentially a million songs change out the songs change that to songs okay so now we have two endpoints in the controller we have this index method which is going to find all the songs in the database and limit it to 10 and return that back in the payload and of course if there is an error we can just say an error has occurred trying to fetch the songs and for posting i can say an error has occurred trying to create the song all righty and then lastly i think we need to add a post method for the songs so if i do a post request to slash songs that's going to call the songs controller.postmethod which is again what we accidentally created and we also intentionally created our index method and at this point i think everything should be okay knock on wood what we can do now is let's go ahead and create a new endpoint to try to test with let me rename this to songs and i'm going to change that to a get request change it to songs save that if we hit it it should return an empty array let's see is fulfilled is rejected oh duh all right so i haven't actually restarted my database yet so let me just create these anyway so i say create song get all songs i just say get songs and then for this one it's going to be a post request to these songs in point and it's going to contain all the necessary data which you see here in fact let me just make this a little bit easier that's weird you can't do that in visual studios huh good thing i have adam opened all right so we need to be able to easily create new songs here so if i try this i think this should crash as well because obviously we don't have that defined in fact now i'm looking at this why is this returning a 200 is fulfilled equals false is rejected equals false because i'm pretty sure we should be getting this catch let me just i'm just going to try something out really quick well this must be crashing at a earlier point must not be at this point maybe it is bear with me just one second it's always fun looking into why stuff's working and why stuff isn't working yeah so i guess if your database table doesn't actually exist sqlize will not throw an exception when you do song.create oh i know why so this is the one pain that i've noticed with using async and wait is that for some reason if you forget to put that keyword await bad things happen because you'd expect that exception to be caught here and then thrown down here right but for some reason it wasn't so now when i change it to a weight an error has occurred when trying to create your song and we're actually catching that exception here right so async weight is also something that i'm trying to learn i've i've been using promises since the beginning since i started working so since es6 is allowed async and await i'm starting to try to use that more but i haven't really used it much in node but yeah just remember do not forget you're await if you're trying to make a promise call like this all right so now that we're done trying to fix that bug if i go back to app.js and i say force true remember we can kind of clear the database using that and save the file it should have restarted and dropped all the tables which it did and i'll go ahead and set that back to false save it and we get those tables recreated so now at this point okay take a breather that was a lot of work nice nice fun debugging we can now start posting songs so if i wanted to say float on artist is modest mouse genre is alternative rock or something album blah blah blah i'm actually going to find real album urls so we can actually start playing around with this so i'll say mod is mouse go to images this one looks good go to view image copy image address youtube id so now i can go to see modest mouse youtube oh hey float on number one it's probably just my history so put that in the youtube id and i'm actually going to do real data because it makes it a lot easier to design and see what your app looks like with real data but for lyrics and tabs maybe i should not worry about doing that because it's going to be a lot so anyway if i were to save this and just send it to the endpoint it's going to create that song and send it back to us and now if we were to go to get songs hit that end point it returns us an array of all those songs so if you remember now in the ui we are already set up to fetch from that songs in point so when i refresh the page it's hitting songs over here which is going to return us that one song inside of an array and the reason it's rendering these is because we need to update the key so if i go back to the client and go to songs and go to the key what i actually want to do is probably set it to the id that's the unique identifier for the song so i say id go back over here that's why i keep forgetting it's not i need to do um the response that data so it should be that is actually what i'm looking for there we go all right so i'll make a mental note to just always remember to do dot data because that's how axios returns us our data cool so just i'm probably going to jump around again to a a way to create songs mainly because that was very painful to do it in a ui at least we have an end point here that we can just quickly create songs if needed but it makes it easier in my opinion to be able to create and fetch songs from a ui so i think the next step is let's go ahead and work on creating a song by having like songs create endpoint all right so to create that create songs view or whatever i can say i'll just say create songs dot view create song dot view okay go to my blank paste that in and then of course go to our router and we need to put in that new view so here i could do song slash add and i could say or she'll say create since you know songs hyphen create create song import that create song component that we just created and go ahead and save that and make sure we can hit song create up here and we can so what would be useful is we need to have the same amount of input boxes for all those attributes that we have for our song model so if i were to go here and just say data and then return that array remember we have all those different attributes let's see if i can find them really quick go to songs go here alright so we have all the same attributes which are on our songs model so at this point we need to create an input field or text field for all of them so the first thing we can do if again we're probably going to wrap it in a panel just because it looks nicer so i'm going to say import panel from components panel and then down here i'll say components panel which gives us access to that custom panel thing that we created and i'm going to say panel title is equal to song metadata and inside the metadata panel we can go ahead and create a text field for all the metadata related stuff so if i go to v text field in fact i much rather just copy and paste this from like our login controller so go ahead and copy this go back to create song and put that in right there and the label here is going to be title and it's going to be a type of i guess text i could just type off i think but basically v model is going to be text or title so if i save this go over here we have a title thing awesome and we want to do the same for all the other stuff so we need one for artists we're gonna need one for genre we need one for album we need one for album image url so i'll just go ahead and copy this what is left lyrics in tab oh and youtube id and for the other ones i'm actually going to be using a multi-line text field so to start off let's go ahead and just um save this make sure this seems like it creates all the necessary metadata inputs which it does cool go ahead and just minimize this a little bit so we can see it all and what i want to do here is on the left i want to have the metadata and on the right i want to have a much larger view of the lyrics in the tab so what we can do is using that whole v layout thing so let's see be layout and then here we can say v flex and i want to flex it of a six and just put all that stuff that was defined in the panel inside that v flex save that and we see that it makes it a swift of six in fact that's a little bit too big let's make it a four or five maybe just a four but then underneath this we can just go ahead and make another v flex that's going to be a width of i think the opposite of that so 8 9 10 11 12 columns out of the 12 in this beautify framework and what we want to do now is for the other ones which would be of course tab and lyric tab and lyrics we want to go ahead actually update the label as well we can add a multi-line attribute to v-text field and that's going to basically make it multiple lines so you see here we can do new lines and stuff like that and you notice here i completely forgot to put that in a panel so i'll put panel here i'll do title and i'll do song structure maybe there's a better name for that but that's what we're going to do for right now save that we're given a panel that says song structure and i want to give a little bit of padding or margin to that so i could say class margin left of four maybe two we'll see what that looks like i guess two is okay it's really small space but that's good enough all right so we have now two panels and all of these are going to be updating the song data down here and we also finally want to add a button to create so if i were to go down here and just say v button in fact i'm not going to do this off my head anymore too much to remember to put that here and i'll say create song and on click it'll call create we don't have a create method so again let's go down here and say methods create and then call api cool so we have a button called create song which will hopefully send all this stuff to the back end so at this point if you remember under services we have a song service has an index call what we want to do is add that post call and we could just pass it whatever song data here make it do a post request to the songs in point and pass the song so here i can say import song service from services song service go here and say post and this dot song and at this point song is not defined so let me just wrap all that stuff inside something called song indent that one and then anywhere we have b model i'm just going to say song dot and again wrap this in a try catch just in case for whatever reason this errors out for right now we don't really need to display a message to the user we may want to say like hey like this stuff has to be required or defined and we can actually do that in one second but first of all let's make sure that this is working as intended so if i were to go here and say abc 123 and just fill in with some blank data and click create let me go to network tab first and clear it and hit create song we see that it does a request to slash songs with a post we got back at 200 okay we got a response back with all the song information and right now it just kind of stays on the page which is not that great what i'd rather do is just redirect us to the song it created but since we don't have a way to view the song we just created let's go ahead and just go back to this dot router.push let's go back to songs so i'll save that do some more stuff here and now when we click create song we should go back to our songs page and look it's creating the songs from that's create songs endpoint that we've been using all right so that's pretty cool um maybe we could add a button here to be able to dive into that create songs uh whatever it's called view so to do that if we go to where are we doing that so in our songs panel here again what i'm trying to do here is i just want to add a fab button here so it looks like a plus sign with a circle when i click it it'll navigate me to that song that i'm trying to get to so i think what we can do is i think we may need an additional slot so if i go back to panel this is how you do this in beautify basically you just have a v button here and also do a v icon and give it an ad icon i'm not sure if the icons work yet let me just see if something shows up yeah i don't think icons work yet because i haven't even included the style sheet for the material design icons so i think that's an easy change let me just go to the index html file really quick go ahead and add that in and then hopefully that will refresh and have a plus sign yes okay so another thing that forgot the setup as you just saw let me just i'm getting overwhelmed there's too many tabs open so the icon is another view thing that you can do and just pass in the name of the icon and there's a bunch of material icons so if i were to go to material io icons any of these can be displayed so if i want to change it to circ check circle like say check circle save that go back to my page it's a check circle but we want to add so let's go ahead and keep it at add but originally we wanted a fab icon right so in order to achieve that there's a couple of attributes you need to add to your button so the first one is of course add fab so if we save that i think the button will become round awesome and then if we do class uh cyan accent 2 just to give it some color maybe i'll just do green you know green for add i don't know i'm not a designer but yeah i'll do what i had before it probably looks better all right so really light cyan add button we want uh let's see if we add light it makes the color oh yeah i'll keep light if you don't know if you saw that but the the font color is darker when you do light i can say i want it to be a medium button you could also do something like large here so if you do large it's going to be much larger but i'll keep it at medium i want it to be absolute positioning so you see how that changes to be directly in the center and then i want it to be on the right and i want it to be in the middle so the reason why this is over there is because i do believe this is supposed to be in the toolbar so if i were to cut this out and put that in the toolbar instead it gets added right there and so what i was going with or going at originally is we need to have another slot so i'll say slot name is action i guess we just name it action for now and we want to be able to let's see if they don't have it defined we don't want to do anything so i'll do this i'm going to cut this out and we actually want that to be configurable and passed in from our panel because we don't want every single panel to have that action button necessarily so what we can do is we can say div slot is equal to action and i'll paste that code there save that and our button will show up over here in the top right in fact i think we could just add it to this if we wanted to and that might make it go back to where it was yes cool so basically by adding slot equal action we're passing that down to the panel and rendering it right there in the correct position that we need and so what we can also do is i'm going to use a router link in this instance where i can say if someone were to click this go ahead and go to the name songs create i think that's what we named it all right so let's see how this looks if we were to instead make this a slot so position got jacked up a little bit but hey it's still working as intended good thing to do when your program is just mess around with stuff like see see what happens if you change around stuff or you can go to the docs and re re-read the docs but again since router link seemed to has messed up the positioning of that plus sign instead i am just going to go here and say add a click listener and say navigate to and i'm going to say name is songs create instead of using router link and again if you have a better way of doing that like if there's an already a directive where i can just say like navigate to let me know maybe i should actually read the docs after this make sure it's called songs create and inside methods we need to create that navigate to method i'll say route say this dot router dot push route cool so easily navigating through all of our pages that's all working we can go to this page and add our new random song and it gets added to our songs list and again this obviously looks pretty horrendous right now so we can kind of style this in a second uh but i think one thing would be nice to do is i want to make sure that all these are required i don't want people uploading bad data to my app so what we can do is if we were to go back to that create song view or component an interesting thing you can add to all these is required so if i were to add required the title we see here that a star appears next to it and then if i fail to actually add something in it doesn't turn red yet because i haven't defined any rules so first i'm going to add required to it and then second we can add a list of rules so if we pretend like we have a rules object with some required stuff attached to it we can go down to the data so i'll say data here and i'm going to add some rules which is going to be an object and basically the rule is we're going to say make the required thing make sure the value is actually defined so basically this is going to pass that rules dot required and it's going to make sure that the value is defined for that in fact i don't know if i need that rules i can just say required so up here i can just say rules is required go back here and see how it turns red and then it prints out required if you fail to fill it in pretty awesome so now i could just go ahead and do that for everything cool now they're all required now the only thing is we need to also check that everything has been filled in before we try to create and there might be a better way to do this but what i'm going to do here is simply just say are all fields filled in and i'm going to just loop over all the keys of my song and verify that every single value of those keys so i can say key so make sure that every single value using that key is defined because that's kind of what we we care about and then if for whatever reason you did not fill that in so if that's false we can say this area is please fill in all the required fields and then return and of course we don't have an error saying so i say error null and then up here we need to actually display it above the button i'll just say span class is equal to error and only display it if error is defined and what we could do here is say is that error is equal to null to kind of set it back to a default state every time you click the button this needs to be this dot song i think yeah alright so please fill in all the required fields let's actually make that a div and not a span and it's also super ugly as to why it's like that so i think beautify has a built-in error class so maybe instead i'm just gonna add a red alert or maybe danger alert so if i go back to view over here and just do danger alert color red and then go back here cool it's red now and we should not be able to fill in anything let me just refresh the page to make sure that goes away so we should not be able to fill in anything or create the song until we filled out every single field and i did and it added the song okay so for the last thing i'm going to do in this part of the video is just try to style these songs so if i were to just start with a blank slate and go to the songs panel it would be nice that for um to have these actually have like a nice style to them so with that being said let's go ahead and try to create a simplified layout here so if i were to go here and basically for a super simple layout we can just do v layouts v layout and then inside the speed layout is going to be so we're going to have a row here and inside the row we want to kind of split it up actually i think what we could do panel has songs v layout yeah let's just go with this and see what happens but basically we want a left and a right side so i'm going to do a v flex of six and then another one of six so we have a left and a right side and on the left side let's just go ahead and do a let's see song title so you do song.title here and i could do the other ones song artist and song genre so get rid of these and then on the right side we want to include an image i'll say class album image and we want to point that so in in a view if you do the colon i think it's the same as doing b bind so basically we want to bind that source attribute to whatever the song album image url is so hopefully if we save this let's see what happens all right so one thing we'll notice is that this image is expanded to its complete size so which is why we added this class album image here so if we go down to the scoped we can say album image is equal to width of 100 so it looks a little bit better there even so i think that's a little bit too big then we also want to center it so i'll do that all right so that looks a little bit better and for the title the artist in the genre we can say song title song artist song genre look at this font size of 18 pixels i'll give this one a font size of 24 pixels and then i'll give this one a font size of 30 pixels all right so that looks a little bit better now and then let's go ahead and just wrap all this into a song so i'll say give it a padding of 20 let's say height of 330 pixels overflow hidden because we don't want anything overflowing and then up here where we're doing that for loop i'll just say class of song cool so all the songs other than these that are missing the images are being displayed in such a way so it looks a little bit better still not that great but hey it it's a start and then what we want to probably add is a way to if i were to say like a view button here so i can easily go in and view the tabs of that song so we should know how to do that if we want to add it to the left column here we of course have to go here and say the button and again let's just go ahead and find a v button um let's see how about the create song button that's the great thing as after your app starts becoming larger you have a lot more copying and pasting resources so here i can say navigate to i'll say name song prams song id of song dot id and it's always nice to make sure you format your objects so they're very easy to change and read all right so now we have a view button which if we click it it calls navigate to which will go down to the songs or it will go to the song view and then it will pass a parameter called song id which will grab from the song so again right now we don't really have a song route so let's go ahead and add one and then we can implement that later in the next part so if i were to do song id here so path is slash song slash id what this does is it allows us to put in variables inside the url parameter or your url query or whatever you want to call it and so change that to shh song and i'll change this to just view song which means we have to come up here and say view song and over here components we have to say view song view and i'll go ahead and just create it from a blank all right so if we go back we now have a view button and if we were to click it it takes us to song one and the one is coming from the song id so remember in the database every time we create a new record it's going to assign it a unique id an auto incrementing unique id so then again if you think about the future we could just have this page load in that song information and display it so i think that's a good stopping point for this part 4 of the full stack tutorial again be sure to subscribe to my twitter it's in the description link if you want to get updates for when i paste the latest part 5 video and again feel free to leave me comments or give me suggestions or feedback as to how to make these tutorials better or if you have maybe a different way that you think i should be doing something in view because again this is more of a learning um effort on my approach it's not me trying to say i'm an expert i'm trying to teach you it's more of hey let's try to reinforce what i have learned from view and make sure i can teach it well all right so again thanks for watching and stay tuned for the next part that should be coming soon\n"