Making Content Editable0:00
If you're a developer who is also running a website, then you have the ability to push code and add any content you want. Say for example you wanted to add some sort of announcement to the top of each page, you can just go into your Blade views and update the code accordingly. However, if you built the app for someone else and they want the ability to add content, you're going to have to identify what content you want to be editable, push that to the database, and create a UI that allows for updating. Sometimes you also want to add some sort of WYSIWYG editor, so they have some options for formatting text. So let's take a look at how we can do that in this video.
Adding Announcement Banner0:31
for formatting text. So let's take a look at how we can do that in this video. So let's add some sort of announcement banner to the top of each page. So let's go into our code, let's go into our app layout. And right here above our nav, we can add that banner. So we can say bg-purple-800, or whatever color you want, text-white. So let's just add some text in here to make sure it's in the right place. Okay, save that. And this banner should appear on every page now. And it does.
Creating Announcement Page1:20
So let's create that view as well. So here's the anchor tag. Let's make a new route called announcement. And that will have the announcement details. So let's go into our routes file. Let's add that new route and name it announcement. And let's also make a new view named announcement. Let's go ahead and create that view, I'm just going to duplicate home. And let's say announcement. Okay, let's just update this.
And let's say Announcement. Okay, let's just update this. And let's give that a try. I forgot to save the routes file. Save that. Refresh. And here is our announcement page. Again, I'm going to paste in some markup here so it looks a bit nicer. Okay, so I pasted in some content here. Let's go ahead and save this and take a look at it in the browser.
Okay, so I pasted in some content here. Let's go ahead and save this and take a look at it in the browser. So again, just details about the announcement can go here. So like I said earlier, as developers, we have complete control over this content. For example, we can bold, we can underline, we can add different colors and paragraphs, and so on and so forth. But now if we want to make this content editable, we have to extract certain parts to the database. For example, we can have an Announcement model with certain fields; it can have a field for the promoTitle up here, maybe we can allow the background to be editable as well. There's another title here with another background.
Building Announcement Model2:35
the promo title up here, maybe we can allow the background to be editable as well. There's another title here with another background. This is our content. And for this, we can make use of some sort of WYSIWYG editor, which we'll do later on. And we have a call to action, which has button text, a link, and also a button color. Let's start off by creating a new model named Announcement and also a new migration. So php artisan make:model Announcement. It's also adding migration. Okay, let's go into that migration. So create, actually, let's go into the model first.
Okay, let's go into that migration. So create, actually, let's go into the model first. So Announcement. And I'm just going to put a carded clause here. I have a snippet. And let's go to our migration. So create announcements table. And now like I said, we want to put all of the editable fields within here. So I'll just paste that in and we'll go through them. So isActive is a Boolean that determines whether the announcement is on or off.
So I'll just paste that in and we'll go through them. So isActive is a Boolean that determines whether the announcement is on or off. You can even make this more dynamic by adding a startDate and an endDate. But for now a Boolean is fine. We have bannerText and bannerColor, which will correspond to the bannerText up here. We have titleText and titleColor, which will correspond to this title and this color or backgroundColor. And for this demo, the textColor is not editable. So the background they choose has to be on the darker side. But if you want, you can make the textColor editable as well.
But since that's required, I'm just going to add it directly within the up method here. So let me just paste that in. I'm just creating some defaults for all of these fields here. And let's make sure to import Announcement. And if you don't like this approach, you can go ahead and put this in a seeder instead. But I think it's fine. Let's go ahead and save that. And let's migrate our database. So php artisan migrate. Okay, so now we have the announcements table.
So php artisan migrate. Okay, so now we have the announcements table. So let's start using this instead of hard coding everything. So we'll start with this page here. So we have to grab that first row from our routes file. So that would be this page here. So let's make a variable for that. Let's say $announcement equals Announcement::first(). Make sure to import Announcement. And let's pass that through here.
Make sure to import announcement. And let's pass that through here. So announcement is this variable. So let's save that. Let's go into our announcement. And we can make use of these variables or this announcement variable. So let's start with the title. This will be announcement.title text is what I named it. Let me just copy this.
Title text is what I named it. Let me just copy this. Now all of this can be replaced with the content. So let me delete all of this. And let's say announcementContent is what I named it. And for our call to action button, we have a buttonLink. So let's add this. We have a buttonTitle. And we have a buttonColor. So we can override this style by adding an inline style here.
Cool. And I think I named this something else. I think it's buttonText. Okay. Let's also make sure that we're pulling from the database for this banner up here. So this is within the app layout. So app layout. So to pass data into here, we can make use of view composers. So we can go to our AppServiceProvider, or you can have a dedicated service provider for view composers.
So we can go to our AppServiceProvider, or you can have a dedicated service provider for view composers. But since we only have one, this is fine for now. Let's go to our boot method. And let's make use of view composers. So we can say view()->composer. And we want to pass data to our layouts.app. So that's within layouts, app layout. And the second parameter is a callback, takes in the $view. And from within here, we can pass data to this $view.
And the second parameter is a callback, takes in the view. And from within here, we can pass data to this view. So let's say, view with, and we can provide an array here. So we need the bannerText. And let's just put a string in here for now. We need the bannerColor. And we need the isActive Boolean. So let's grab the announcement and pass it through here. So we can grab what we did in rotsweb. Let's grab the first announcement.
So we can grab what we did in rotsweb. Let's grab the first announcement. Let's use that up here, make sure to import that. And now we can pass it through here. If you want, you can also pass the entire announcement in, but this is fine. So we can say announcement, bannerText, this one's bannerColor, and this one is isActive. Okay, let's save that. We should be able to use these variables within our appLayout now. If you want, you can also extract this to a Blade component to make it a bit more cleaner, but I'll just leave it in here for now.
If you want, you can also extract this to a Blade component to make it a bit more cleaner, but I'll just leave it in here for now. So let's add the $bannerText variable for banner text. For the banner color, we can override this style here with whatever is in the database. So let's give it an inline style, background is $bannerColor. Okay, let's save that. Let's see if this works. And it is pulling from those values. So we also want to only show this if the $isActive variable is set to true. So we can wrap this whole thing in a conditional.
So we also want to only show this if the isActive variable is set to true. So we can wrap this whole thing in a conditional. So let's say if isActive, then go ahead and render all of this stuff. But if it's not isActive, then it won't render anything. So let's save that. I believe it is on right now. So it still shows. But if I were to turn it off manually, so let's go into our database. Let's refresh this. There's our announcements table isActive.
Let's refresh this. There's our announcements table is active. Let's set this to false. Let's save that. And let's give that a try. Okay, let's also make it so we can't go to this page if the announcement is off. So let's add a card within our routes/web.php right here. So I'll use the abortIf helper. So we can do it in one line. So abortIf the condition is if the announcement is not active.
So we can do it in one line. So abort if the condition is if the announcement is not active. So announcement is active. And return a 404 or whatever response. So it's off right now. So we should get that 404. And we do. So let me turn it back on. And it should render now. Okay, now let's create a form that allows these fields to be updated.
Creating Edit Form9:56
And it should render now. Okay, now let's create a form that allows these fields to be updated. So I'm not going to do any authorization here as that's out of the scope of this lesson. But if this were a real app, you want to make sure this is behind some sort of admin login. So let's go ahead and add a route for that form. Let's duplicate this. I'll name it editAnnouncement. And we don't need this. Let's make a new view named editAnnouncement as well. So again, I'll just duplicate the home.blade.php, duplicate and editAnnouncement.
Let's make a new view named edit-announcement as well. So again, I'll just duplicate the home.blade.php, duplicate and edit announcement. Let's update this. Edit page, save this, let's save our routes/web.php file as well. And we have to add this to our menu. So that will be in our app.blade.php layout. So our menu is right below here. Let's add a new one for editing announcements. So let's say edit announcement. And same for this one.
So let's say edit announcement. And same for this one. Let's save that. Let's go to our browser. Let's test this out. Okay. So again, I'm just going to paste in some repetitive form code here. And then we'll work on updating the announcement together. Okay, so I pasted in some form code here. Let's take a look at this in the browser.
Okay, so I pasted in some form code here. Let's take a look at this in the browser. Okay, so I've added all of the fields in our database. And now let's work on showing the correct data for the Announcement in this form. So we already have access to the announcement since we passed it in from our routes file right here. So now we can add the values, for example, the bannerText here, we can put a value. So let's say value equals, and this one will be $announcement->bannerText. Okay, let's save that. And I'll do the same for the radio buttons here for the isActive field.
Okay, let's save that. And I'll do the same for the radio buttons here for the isActive field. And then I'll just paste in the rest. So we can make use of the checked directive, which was introduced in Laravel 9. So we can say @checked. And we want this to be checked if the announcement is active in this case. So let's say announcement->isActive. And the same for the other case, but announcement is not active. So let me just paste that in here. Let's change it to not.
This is just a simple explanation with no code.
Okay, so I'll just add the values for the rest of the fields here as they're all just text boxes and one text area for the content here. Okay, so I added the values for all of our fields here. Let's save that and take a look. Okay, and everything looks good. But for our colors here, for example, our banner color, we can actually change this to an input type="color" so the user can select the color. And the selected color should have this pound symbol in front of it. So that should work out as the correct value. So let's change the banner color here.
So that should work out as the correct value. So let's change the bannerColor here. bannerColor. Let's change it to input type="color". And we no longer need our class here. So let's get rid of this. Let's take a look at that. And you can see you can select colors now. Cool. So let me just do the same for the other two colors here.
Cool. So let me just do the same for the other two colors here. Okay, so I added the colors for the other two fields here. And now let's work on updating the actual content. So let's go back to our form here. And let's define a new endpoint for updating our fields. So we'll name it /announcement/update. Usually I use route names, but in these examples, I'm not. So announcement.update. We have our CSRF field, but I also want to make this a PATCH method.
So announcement update. We have our CSRF field, but I also want to make this a PATCH method. So we can say method="patch" or put will work as well for updating content. And let's go ahead and make that route. So back to our routes/web.php, let's duplicate this one. Let's make it a PATCH request for updating. Actually, I want to update this endpoint here to announcement/edit to make it a bit more restful. So let's change this to announcement/edit. And usually you would have the model ID within here,
So let's change this to announcement/edit. And usually you would have the model ID within here, but since we're only working with this one row, then we don't need to add that. So let me update this within the nav. So that would be in our app/layout. This would be announcement/update or edit, I mean. And let's make sure that still works. So let's go up here back to home, edit announcement, and it still works. Cool. Okay, back to our routes file.
Cool. Okay, back to our routes file. The endpoint is now announcementUpdate. So let's grab this. Let's update this. announcementUpdate. It's a PATCH request. We need the request variables coming in. Make sure to import request. And when we're done, we can redirect back with a success message.
Make sure to import request. And when we're done, we can redirect back with a success message. So let me just remove this, paste in the redirect here. And now we just want to update the announcement with the fields coming in from the request. So we have the announcement. We can use the update method, and we can provide all of the fields here. But I'm going to do some basic validation. And if that validation passes, it will return an array of fields, and we can pass it through to this update method.
And if that validation passes, it will return an array of fields, and we can pass it through to this update method. So let me just paste in the validation here. So we're seeing request validate, all of these fields here. And most of them are just required by default. But for the buttonLink, I also have a URL as a rule. And if this validation passes, it actually returns an array of fields here, which we can make use of to update the announcement. So let's say fields here.
use of to update the announcement. So let's say fields here. And we can pass this through to our update method. And hopefully, that should work. So let me save this. And let me add the flash message for when it's successful. So that would be an editAnnouncement, because we're going back to this page. And I'm just going to paste in the code for that here. So it checks the session for a success message and if there is, just output it.
So it checks the session for a success message and if there is, just output it. So let's save that. And hopefully, I did this correctly. So let me refresh this. Let's change all of these fields here. Actually, we'll try one for now, just to see if it works. So change. So that would correspond to this up here. And let's go ahead and update this.
Adding Quill Editor17:59
OK, let's convert this text area to a rich text editor. So there are a bunch of popular packages. I'm going to make use of Quill, but there's also Trix and TinyMCE, to name a few. So let's get started with Quill here. Pretty straightforward. We need a CSS file, which we can grab from a CDN. Let's grab this. Let's put it in our app layout. So let's put it up here, and I'll put it right here.
Let's put it in our app layout. So let's put it up here, and I'll put it right here for our styles. OK, what's next? We have to add this element with an ID of editor, and the children of that would be the content of the editor itself. So let's grab this. We'll put it underneath our text area in our edit announcement. So let's look for the text area.
We'll put it underneath our text area in our editAnnouncement. So let's look for the text area. Let's put it right underneath. And I'll leave the text area for now. Let's save that. OK. Now let's include Quill from the CDN and initialize it here. So we can grab all of this. So I do have a stack for our scripts. So let's look for stack here.
So I do have a stack for our scripts. So let's look for stack here. So we can push to that stack within the edit announcements blade. So I'll do that down here, right before the end of the app.layout. Let's push to our scripts. And let's paste that in. So let me save this. So there are a ton of options for Quill,
But we do want it to be HTML. So let's go to our textarea. Instead of this, we can add our announcement content, like we have in our textarea. So let's grab this. Let's paste that in here. And let's save this. Let's see if it's getting content from our database. And it is, cool. So now we can make use of the formatting options.
with the HTML of this. And then just submit that. That's one approach to solving it, which we'll take here. Or you can just make use of JavaScript to send all of the data using an AJAX request. And that would work as well. So back to our code, let's go to the JavaScript here. So underneath this, I'm just going to grab the form here. So I need to add updateAnnouncement as an ID on the form.
So I need to add updateAnnouncement as an ID on the form. So let's look for the form here. Let's add that ID. So ID equals that. OK, so now we have access to that form. And now let's listen for the submit event. So form.addEventListener. It's the submit event we're interested in. And let's provide a callback here for when that happens.
It's the submit event we're interested in. And let's provide a callback here for when that happens. Let's grab the event. Let's prevent the default. And then let's do some stuff here. And then after that, we can submit the form normally. OK, so let's grab the Quill Editor. So there's an ID of Editor. So let's say const quillEditor equals document.querySelector('#Editor'). It's named Editor. And just like I showed you a second ago,
It's named Editor. And just like I showed you a second ago, the content of this is going to be the children of this QuillEditor. So we can say const HTML equals QuillEditor.children. So the first index. And we can grab it using innerHTML. And how about we don't submit the form so you can see what I'm doing first. And now we're going to set the text area. So document.querySelector. And I'll name it ID content.
So let's save that. And let's see what we get here. So again, as we submit this form, the HTML of this is going to populate this. And the HTML in here will be saved to the database. So let me just refresh this. Again, let me add some HTML in here. So let's add a bold here. Let's add another paragraph. Another paragraph. OK, that should be fine for now.
We can actually hide this text area now. So let's go to our text area. Let's give it a class of hidden, which is displayed on Intel Wind. OK, that should be hidden now. But it's still going to be submitted. OK. And now let me put the form submit back in our JavaScript so we can actually submit the form. Let's save that. Let's refresh this.
Let's save that. Let's refresh this. Let's bold this. Add a paragraph. And let's submit the form. OK, let's take a look at the text area here. And you can see it's not rendering correctly because we are escaping the content. So back to our Quill editor. We actually want to render the HTML here, so let's use exclamation marks here.
So back to our Quill editor. We actually want to render the HTML here, so let's use exclamation marks here. Just make sure you're careful when you do this and you trust where this is coming from. In this case, it's coming from the admin of the site, so we shouldn't have to worry too much about cross-site scripting. But if you don't trust where this is coming from, then you'd have to do some extra steps to sanitize your HTML. But this should be fine. Let's save this.
But this should be fine. Let's save this. Let's go back to the browser and see if that renders. And now it does. And we also have to do this within our actual announcement page. Again, by default, it's escaping the content, so let's change that. Let's grab this. Let's go to our announcement.blade.php. And for the content, let's just paste that in. I'm also going to wrap this in a div with an ID of content. And let's see if that renders.
Let's just link to Veritas. Let's save that. Okay, let's update the announcement. And it renders fine in here, but if we go to the actual announcement page, this is actually a link, but the styling is not there because Tailwind resets it. So you just have to make sure that you have appropriate styles for those elements. For example, link tags and unordered lists.
Save that. And let's give that another try. And now the styles are back. So yeah, that was an example of how to make your content editable. Do it manually first, then identify which sections you want to be editable. Push that to the database. Create a form that allows you to edit that data. And if you want to give the users the ability
Create a form that allows you to edit that data. And if you want to give the users the ability to do some light formatting, provide them with some sort of WYSIWYG editor. In this case, we're using Quill. And now your content should be editable. So let's go ahead and make a commit here. Say git add, git commit. This is episode four. Let's call it making content editable.
This is episode four. Let's call it making content editable.
