Section 8 (Lesson 6/10): In this lesson, we’ll improve some functionality of our workplace app. First, we’ll simplify how we upload and save user avatars and company logos. Then we’ll cover how to delete these avatars and logos from the server to make sure that we save some app capacity.
You’ll learn about:
Bookmarking: Creating a way for users to bookmark jobs that they’re interested in.
Custom events: How to force a workflow to run in a certain order by using a custom event.
Workflow optimizations: How to improve some existing functionality to simply some of our logic.
Resources folder: ➡ https://e6387a14ba6d0bf3e823090f8d959...
Bubble editor: ➡ https://bubble.io/page?type=page&name...
Transcript
So in this lesson, we have a few bugs to fix. There are a few app optimizations I want to make, and I also want to basically improve on certain functionality. Let's dive in!
So the first thing I'd like to do is this. Open up your Navbar reusable element, and then open up your Popup Mobile nav. Now, obviously, the "Log out" button and all of these pertain to a logged-in user. If I close this nav, we also need a logged-out view. Now, the only difference is the logged-in view has the dashboard link plus the "Log out" button, and the logged-out view has "Log in," "Sign up," plus these existing links.
Okay, so let's do the following. First of all, this dashboard, let's right-click on the Group Navlink (Dashboard) and click "Edit properties," bring up the Property Editor and on the Conditional tab, we're going to define another condition that says only when the Current User is logged in, that's when it's visible, and it's not visible on page load. So on the Layout tab, uncheck "This element is visible on page load," and of course, we need to collapse it when hidden. Because these three links are visible when a user is not logged in, and they're visible when a user is logged in. So these can just stay where they are.
So on the Log out button we'll do the same. Conditional tab, when the Current User is logged in, that's when this element is visible, and on the Layout tab, it's not visible on page load. And it's collapsed when hidden.
In the Elements Tree, I'm just going to click on the "i" icon and bring it back because we need some more buttons. Now we need "Log in" and "Sign up". What we're going to do is this. We're just going to refactor. Let's close the Popup. Let's head over to Group Buttons, and, in actual fact, this should really be called Group Links, so this is a bug. We're going to copy this using your keyboard shortcut, we're going to open up Popup Mobile nav and we're going to paste it in (Command+V), Group Links. Now we want this to be a column on the Layout tab, set it to Column. Then add some row gap. Let's try about 12 px here and then I'm going to highlight both of these links, right-click, and uncheck fit with to content.
Now on Group Links, I want to move it one up over there. Let's collapse when hidden, not visible on page load, but, we are going to bring it back. We're going to remove this condition, create a new one that says when the Current User is logged out, that's when it's visible.
Just need to check why this is not collapsing. Not visible on page load, sorry, collapsed when hidden. Okay, now I'm going to hide it. Yeah, there you go.
Okay, so Group Links you can only see when a user is logged out. These links will take you to the respective pages: log-in, sign-up, we've got the workflow for Text Close. This is what the logged-out view looks like and then the logged-in view will have this Button Log out comes back, and we hide that, and what else comes back? This dashboard view. Okay, so there's one thing I wanted to deal with.
The other one is on the search page, we need to deal with this this bookmark functionality down here, which we have yet to do. So Candidates will be able to check this bookmark icon to basically be able to save this particular Job.
So let's click "Start/Edit workflow". Let's "Click here to add an action," let's go down to Data (Things) and Make changes to thing. So we'll be making changes to the Current User. We're going to save bookmarked jobs on the Current User, so let's create a new field. Let's call this "Bookmarked jobs" and this will basically be a list of Jobs. Simple as that.
When that is clicked, because it's a list, we've got these dropdown operators, we're going to choose "add", and it's just the Parent group's Job. Don't forget, we need add and remove! Let us click back on this event and change the color to green and say that only when "Current User's Bookmarked job's doesn't contain Parent group's Job," that's when we add. So if that Parent group's Job is not in a user's Bookmarked jobs, then we make changes to the User and add it.
Let's copy and paste this for the removal of a bookmarked job. I'm going to deal with the one on the right. I'm going to change that to orange to indicate the removal. We're going to change Current user's Bookmarked job's doesn't contain- and instead, choose, "contains" in the only when condition. Okay, we've done this a few times now. For this one, for step 1, we simply remove.
Okay, and how do we give feedback to a user that this job is in their Bookmarked jobs? Well, on the icon, we go to the Conditional tab that if the Current User's Bookmarked jobs contains Parent group's Job, that's when we change the icon. Let's choose this little checkmark icon to the left, and let's change the color. Change it to green. Okay, so pretty standard stuff.
We're not going to go through the detail of how to then filter by Bookmarked jobs because we have already done that functionality on the company page when a user shortlists a particular job application. It will be the same process.
Okay, now let's head over to the company page. Let's open up Group Container in your Elements Tree and then open up Group setting. Now, just thinking about optimization. Currently, we have, in terms of image uploads, we're using a bunch of states, and then on the Save button, we are making changes to a User and we're saving the state. And that's fine! That's a particular way to do it, but there are multiple ways to do things in Bubble, and if I think about app optimizations, I think we can actually improve and simplify this particular workflow.
So we're going to do this on our image uploaders across the app, so for the image Avatar and the Company logo on the company page, and then on the Candidate page, we'll do the Avatar as well. And what we're going to do is actually just upload the image and save it in a single action, and this is a quite common practice that I see. And again, what we've done so far is not wrong, it's just one way of doing and I want to actually simplify it now.
So at the moment we're uploading, we're setting a state, and then we're saving the state on this button. Instead of doing that, we're rather just going to save an image once it has been uploaded straight away.
Let's go to the Workflow tab, and let's go find in the bottom, it should be in your bottom row, you should have a PictureUploader Avatar's value is changed event. Let's have a look at this. Currently we are setting a state, there it is there, and then we're resetting relevant inputs to change the data source. Let's delete both of these steps and let's simplify this.
Let's say that when the PictureUploader Avatar's value is changed, we are literally going to make changes to the Current User straight away, and we're going to save this straight to the Avatar field: Avatar = This PictureUploader's value. We're going to deal with deletion shortly.
Let's go back to the Design tab and let's change the data source now. Instead of company's Avatar, it's going to be the Current User's Avatar, because company's Avatar was a state, this is now referencing the database.
Now for this Delete button, the first thing we're going to do, and actually what we didn't do, is on the Layout tab, I want to actually hide this on page load. We're actually going to hide it when a Current User's Avatar is empty because it doesn't make sense to see a button to delete if there is no image to begin with. So this is just a bit of UX cleanup. So if the Current User's Avatar is not empty, that's when it's visible. So we won't see it at first. As soon as it's saved, we will see this.
So how do we delete this? Let's edit the workflow, and currently, we are resetting states, we're going to actually remove this step. So much like the file uploading experience where a file is saved to the server and that link is then saved to the file's field that we can see in the database, we need to do the same for the image.
The first thing we actually need to do is actually use the "Delete an uploaded file" action found in Data (Things). Okay, and this is part of the reason why we're changing the workflow here, just to simplify this process. And the file is hosted at - or the link to the file - is hosted at the Current User's Avatar. And you will be able to find the Current User's Avatar or all of these uploaded avatars in your File manager. And that will have a link, and then that link is saved to the Avatar field under the User data type. Okay, if we just go back to the Data tab and App data sub-tab, and I look at mine, this is simply a link to a hosted file which is actually hosted elsewhere and the link is saved.
We're deleting an uploaded file, and then what we have to do is "Make changes to thing" in step 2 and change the Current User and then delete the link to the Avatar field. So we just set Avatar equal to nothing and that removes the link. And then what we also need to do is reset data as a last step just in the parent group of where the picture uploader is situated.
So let's just go back and have a look at the name of this group. So the group, if we delete data of this group, it's going to actually reset the image in here, which needs to be done. So I'm going to rename this to "Group Column avatar". Then we can go back to the Workflow tab and now just reset data of Group Column avatar. Okay, so these are the steps required to firstly delete the uploaded file, then clear out what's in the Avatar field, and then reset data.
Now, a little problem with this workflow is that, as I explained in previous lessons, that Bubble actually runs workflows in parallel when they can, so sometimes you don't need to wait for data in step 1 to run step 7. They can just run in parallel. And the problem with that in this particular workflow, if we go back to the Editor, is that Bubble only runs workflows sequentially that need to be run sequentially, such as if step 2 is waiting for the result of step 1, then it will be executed as step 1 first, step 2 second, step 3 third.
That's not going to be the case here, and we have to find a way to force the order, so these will probably want to run in parallel, and if they do, if step 2 runs before step 1 or finishes before step 1, then we can't delete an uploaded file because we have removed the link from the Avatar field! This is called a race condition.
So we just simply need to move these into a custom event because in a custom event, workflow steps run sequentially. Outside of a custom event, they do not unless we are waiting for data from a previous step and explicitly referring to data from a previous step, such as the result of step 1.
Okay, so we're going to click here to add an event. This is going to be a custom event. This will be called "Delete avatar". I'm going to change the event color to purple and let's go back to that "Button Delete is clicked" event, and we're going to go to step 4 down to Custom events --> Trigger a custom event, and Bubble has chosen "Delete avatar" for us. Now we're going to simply cut and paste these three workflow steps into the Delete avatar custom event. So we're going to cut, paste, cut, paste, and lastly, cut and paste. Now we have a custom event and these will run in order. So when the Delete Button is clicked, we are triggering that custom event.
Okay, before we test this, let's just clean up a few other things here. So currently on the Save button, we can edit the workflow and on the Make changes to a User step, we can delete this now (the Avatar updating field) because we are saving instantly, not on the Save button.
So when Group Navlink (Settings) is clicked, let's edit the workflow. When settings is clicked, we can just delete the settings of the states here because we're not using states anymore. So we just have a single step, v equals "settings".
Okay, let's test this out! So let's go to the log-in page and press "Preview". So it didn't run as Hana because that company page will redirect if there is no company data in the URL, (/orbit), so I'm just going to actually log in as Hana so the company page loads correctly.
Okay, so here we are at Settings, there is no image and we can't see the delete button. Exactly what we wanted!
So let's go ahead and upload this image. Head over to your resources folder, find Hana's image. Okay, so here's the image here, and it's saved to Hana's User record, and we know that because we now have this image.
Let's jump back into your Editor for a second, please. Then go into your Data tab, refresh your data on the User's data type. Okay, there's Hana's image and if we go to File manager, here is Hana's image that I've just uploaded.
So what we want to do is now delete Hana's image and make sure that it's removed from both the File manager and from this Avatar field, and from this picture uploader, because we have those three steps. Delete an uploaded file, then we are removing the avatar URL, and then we are resetting data. Those three steps are required to take us back to the beginning.
Let's click the "Delete" button. Okay, let's go check the data! I'm going to refresh my data. We can see that this image field is not populated anymore. On the File manager, if I just refresh this data again, you can see that Hana's image has disappeared which means it's been deleted from the server. Okay, so those are the steps required, folks, so let's go ahead and do the same for the company logo.
Back on the Workflow tab, we're going to open up the workflows and let's quickly get through this. Okay, so we know what we need to do here. So PictureUploader Logo's value, we're going to delete these two steps. Instead, we're going to say "Make changes to thing..." and the thing will be the Current page's Company. Uploading the logo to the Current page's Company. Here is the Logo field, and we're going to populate the Logo field with This PictureUploader's value.
Let's head over to Group Container and then Group setting. Let's change the data source of the uploaded logo from company's Logo to Current page's Company's Logo. We need a conditional on this Delete button. On the Layout tab, uncheck visible on page load and collapse when hidden. We can only see this delete button when the Current page's Company's Logo is not empty. That's when it's visible. Okay, that's step 1!
On the Save button, we're going to edit the workflow, and we're just going to remove the logo being saved via the state. Now for the deletion part, so if I click on the Delete button, edit the workflow, I'm going to delete the step 1 and we're going to recreate this. And basically, let's just... well, let's create a new one here, a new custom event. So Custom --> Create a custom event. Let's call this "Delete logo". Let's change this color to purple. Our new step 1 will be "Delete an uploaded file". Bubble is saying, where is this file? Well, we've just saved it to the Current page's Company's Logo field, so Current page's Company's Logo. That's step 1.
Step 2: "Make changes to thing". Remember, we're running a custom event to run these sequentially in order! Current page's Company is the thing to change. Then we select the Logo field and we leave the value blank. And then we need to reset data of that picture uploader, of which I don't know what it's called. Group Column, let's change it to Group Column logo. Once you've done that, simply reset data under Element Actions, and the element will be Group Column logo.
Okay, so two custom events: one is "Delete avatar," one is "Delete logo". And then we have to on the Delete button and you could just go back to the frontend and run the workflow on the delete, we are going to choose as the first action Custom Events --> Trigger a custom event, and that custom event is called "Delete logo".
So that, I think, is done on the company page. So we've dealt with uploading straight away, we've got the dynamic image pointed to the database, we've got the conditional on the delete, we've just created the custom event, and we've removed the state saving on the Save button. Great!
Let's head over to the candidate page and just do the same thing. This is really good practice. Let's just get through this one as well. This is going to be Group Account. All right, so let's do the same thing here. Instead of the "candidate's Avatar", it's going to be the "Current User's Avatar".
On the delete button, we need to hide it by default and on the Conditional tab, we're going to only show it when the Current User's Avatar is not empty. Okay, check the name of this Group because we need to refer to this Group soon, so Group Column avatar. Let's just remove the state saving on the Save button, so click "Edit workflow". Here it is down here, the last field "Avatar," we remove that.
Let's just see what else is going on here. So Page is loaded, Set state Avatar, set state Preferences. When the page is loaded, we don't need to set state on the Avatar anymore, but we do need the Preferences. We just need to delete this Preferences and move it to the top. There's no way to physically move it now, so let's change this custom state "Avatar" to "Preferences," and the value is "Current User's Work preferences". Optimizing here, this is good! We are creating simplicity.
Okay, so here is the last step, is the PictureUploader Avatar's value has changed event. We're going to delete step two. We're going to delete step 1, and we're going to say, when the PictureUploader Avatar's value has changed, we're going to make changes to thing. That thing will be Current User, and we're going to save the avatar image from this picture uploader's as value: Avatar = This PictureUploader's value.
Let's deal with the delete now. So head back to the frontend and then edit the workflow on the Delete button. Remove step 1 and instead we're going to add a trigger here but we first need to add our custom event so the workflow will run sequentially. This custom event will be called "Delete avatar". Change the workflow color to purple.
Let's say that we are going to delete an uploaded file and we can find the link from the Current User's Avatar. The next step is to just make sure that we are clearing out the link as well, so we're making changes to the Current User's Avatar field. And then the last step is to reset data of the Group Column avatar.
Okay, really, really like this particular app optimization, and as I said, the first way we did it is not incorrect, but I felt like as we went on with the course, I thought that we can just improve certain functionality.
Okay, really nice set of optimizations there, and I think we're ready to move on and talk about SEO in the next lesson! I'll see you then.