Section 3 (Lesson 6/8): Next, we’re going to focus on the workflows and logic side of the form. This lesson is designed to equip you with the knowledge you need to effectively structure your database, create efficient workflows, and build a notification system for user feedback.
What you'll learn:
Database structuring: We start by laying the groundwork for your application's data management.
Workflows, explained: We'll guide you through the process of transferring data from forms into your database.
Notifications: We’ll build a success notification to feed back to the user upon a successful form submission.
Resources folder: ➡ https://e6387a14ba6d0bf3e823090f8d959...
Bubble editor: ➡ https://bubble.io/page?type=page&name...
Transcript
Three things we'll cover in this lesson. Number one, we need to structure the database to be able to receive this form data. Number two, we're going to look at the workflows. So how do we carry this data from the form into the database? Number three, we'll talk about the user experience, such as, what does the user expect after clicking the Save button? Do they get feedback? What is that? Let's dive in.
One of the quick changes I wanted to make is sometimes inputs are slightly smaller in a dashboard setting, and having a break, having my lunch earlier, then coming back, looking at these inputs that don't have placeholders, I think they're too big. So let's change them all to 40. So I'm going to hold shift to highlight both of the standard inputs, and on the Layout tab, choose a height of 40. I wouldn't go smaller than this. It becomes difficult to work with them. On the Dropdown Location, on the Layout tab, 40. And the Input About height is going to be 80. Okay.
So to be able to receive this data and put it into the database, we need to create these fields: first name, last name, about, and location. Now, if I click into the first name input, I can see that the content format is text. And this is important because we can have multiple content formats. We can have numbers, geographical locations, all sorts. And Bubble does this as a way of creating form validation so we are correctly guiding the user to be able to input the correct data. So when we do get to the database section right now, I am going to make sure that the first name is a type of field that accepts text, and when it gets down to the dropdown, I'll say that it needs to actually be Option Set data because that's what the location is pulling in, a list from an Option Set.
So in the Data tab, on the User, we currently have a User type. Very well. Let's create a new field. Let's call this "Name first." And this is the field type that needs to match the input. So this is type text, okay? Text, create. Do the same for "Name last." That is also type text. And then "About" is a multiline input, which is obviously text. And then the dropdown is linking to an Option Set, and we want to save one of these options, just one of them. So here it is here, providing all the locations, the user is selecting one, and then we're clicking on Save. Okay, so let's head back to data types, User type, and Create a new field. Let's call this "Location." And these field names only we can see as developers, okay? And this field type is under Option Set --> Location. Create. Fantastic.
Let's now hook up our workflow. So back on the Save button, I'm going to add a new workflow. Let's have a look at the options here. So when you click to add an action, we see Data (Things), and now we have the first one is "Create a new thing..." and the second one is "Make changes to thing..." Let's think about this logically. Once we've signed up and we're filling out this form, we are a logged-in user and we exist. So we're not creating a thing because that is basically creating a new row or new record in the database. In this instance, we are a User, but we have some blank fields, so we are updating or making changes to a thing, the "thing" being us.
So click "Make changes to thing..." Who are we making changes to or what are we making changes to? The Current User. Now I'm going to click the shortcut, "Add all fields," and all we do now is reference those inputs. So "About" is the "Input About's value." "Location" is the dropdown - how cool is that? We can just point to the dropdown because the dropdown has a data source, and we're saving the value of the selection ("Dropdown Location's value"). "Name first" is "Input Name first's value" and the same for the last name: "Input Name last's value." And the User Type is already set, we don't need it, I'm going to delete it.
Okay, so that will then save this data to the database, to the Bubble server. And we need a way to then also display a message back to a User that it's been successfully saved or it hasn't been saved. So for that, we need an alert. So let's head back to the Visual Elements on the Design tab and find the Alert element and then just drop it anywhere on the page. We're going to reposition it in a second. We're going to type in "Successfully saved," and I'm going to click to position it at the top. On the Layout tab, it does need to be a fixed width. I'm going to bring this width down, I'm happy with a width of 180.
Let's design this a bit better. Let's make this green, as in it's a successful message. So I've removed the style, I'm going to change the font color to white and I'm going to change the background color to green. Let's have a look at that. That looks pretty good. And I'm going to make it float, okay? We can remove the borders, a roundness of 6 - let's make around us of 8 so it matches our buttons. And then a shadow style, let's add some outset. First of all, just change the box shadow color to our jet black, and then 10%. You can see the design is starting to change on the right-hand side here. Okay, I'm going to increase the blur radius to 8 and I'm going to change the vertical offset to 8 as well. Then I'm going to have another look. Yeah, and that floats really, really nicely. And then I'm going to go ahead and I see we have one already ("Success Alert"), but I'm just going to create a new style and say "Success."
So let's go back to the Save button once you've done that and click "Edit workflow." Now that alert is not visible on page load, we have to show in a workflow step. So that would be an action under "Element Actions" --> "Show message." Bubble has already assigned it a message because we've only created one, and that is "Alert Successfully saved."
Now, this alert can be used throughout this page, and we can actually change the message that we show to a user based on the type of data that they're saving. And to do that, we'll just say, next time, if we want to say, instead of "successfully saved," we want to say "updated" or "edited," we can just check "Change the alert message" in the action and type in a new message. Obviously, we then want to match that with a different type of message, maybe it would be a destructive message or a warning message.
So now we're capturing the data, but we also want to display the data back to a User. And that's called initial content. And initial content, basically, it looks It looks at the current user and then it looks at the database. And if there is a first name in the database, we can display it back to them in this input, which we should be doing. Otherwise, a user thinks it's been saved, but the input's empty. Okay, so that could become confusing.
So on the "Initial content," in the Appearance tab on the Input Name first's Property Editor, we're going to insert dynamic data now. It's dynamic. Brilliant. Means it's coming from the database. This will be the "Current User's Name first." Okay, let's do the same for Input Name last. Insert dynamic data: "Current user's Name last." We can also do this with Input About, where Initial Content can be set to "Current User's About."
And by the way, we can also control whether or not we want this multiline input to grow or not. On the Layout tab, I currently have a fixed height, which means the scroll bar will appear, and I just prefer it that way, I don't want this to grow and grow and grow because the Save button will be pushed too far down. That's not great user experience.
Okay, on a dropdown, we can also show a dynamic value or initial content, but we are calling it a dynamic value in a dropdown. And we can basically scroll down next to "Default value" on the Appearance tab of Dropdown Location, find the Current User, and then find Location. And there we go: "Current User's Location."
Now, an image is a little bit different because on an image, we are not writing in an input or clicking a dropdown. Instead, we are uploading something. So this is a little bit different, this workflow. So stick with me through this because this is the method that I use in my daily building life, and I'm going to teach it to you now!
So you can see that there's no button to run a workflow from this PictureUploader Avatar's Property Editor. That means we have to start in the Workflow tab, and we're going to press "Click here to add an event," and that event is going to be under Elements and is "An input's value is changed." And that becomes true because the picture uploader is an input, and when a user uploads an image, then the input's value has changed. That's when we can do something. Bubble now says, where is the element? And we're going to say it's the PictureUploader Avatar, just the element name.
And this is where the fun begins, because we're uploading an image but we can't save it to the database - we could, but we're not going to. Instead, we're going to save it to a state and then on the Save button, that's when we're going to save the state to the database. And this just enables a bit of user interaction. It enables a person to upload an image, and then change their mind. Have you done that? I literally did it yesterday. I uploaded a profile image, it was the wrong one so then I cleared it out or deleted that image and then re-uploaded it. The nice thing is we're not saving to the database during this process of user interaction; we're allowing a user to become happy with their selection, and then we're only saving to the database on the Save button.
So instead, we're going to set state, folks. We're going to click to add an action and go to "Element Actions" --> "Set state". Bubble is saying: where do you want to set the state? And in the past, I've talked about setting all of your states at page level so you know where they are! So the element will be "company" and for the custom state, we'll click "Create a new custom state..." We're going to call this "Avatar." What is the type? So this looks just like a database field where we're asking for the field name and the field type. Now it's the "State name" and the "State type." So therein lies a clue that whatever we can create in the database in terms of a field type, we can also create that as a state, so then we can match these two things together. So for state type I'm going to scroll down and find "image" and then create.
Okay, Bubble is now saying, what is the value of the state? And this is where we're going to just point to "This PictureUploader's value." Okay, so now the state has been set. In the next step, what I'm going to do is something a bit different. I'm going to reset inputs. I'm going to reset inputs because a picture uploader is an input, and I actually want to clear out the default uploaded image and rather replace it with the state image. Don't worry if you're not getting this because we're going to be doing this another time, and I'm sure by then it will become clear, okay? So all you need to know at the moment, a user has clicked on the picture uploader, that image has been uploaded to the element, and then we've taken that uploaded image and we've set it to a state on the page.
So now in the Appearance tab of the PictureUploader Avatar element on the Design tab, I'm going to say the "Dynamic image," I'm going to point that to a state, and that is on the "company," or on the page, the avatar: "company's Avatar".
So what is this delete button for? Well, the delete button is basically a way to reset the state, and that will clear out that state image, go back to the default where they can then click again and upload a new image. So you can see this loop, this 360-degree closure that we've created with this button.
So let's add a workflow on delete. And we're simply just going to add a new action and say "Element Actions" --> "Set state," go find the state that we created, it's called Avatar, and it's on the company page. Then we're just going to leave the value blank. It will reset the state. Simple as that. So then the user deletes it out and they can upload another image. Once they are happy with this image that has been uploaded, then we're going to save the state.
I'm going to click on Save, edit the workflow, and back to step one, what we do need is a way to capture and save that image. So I'm going to add another field, and I'm going to call this field "Avatar" that is type "image." Create. And this is where it's interesting because it's not the PictureUploader's value, because we actually reset that and replaced it with the state. And because the state is a type image, this database field is an Avatar of type image, it's a match! Therefore, we can just point to the state's value. So where is the state? It's at the company on the page. So it's expecting an image, and it's getting an image via the state ("company's Avatar"). How great is that?
So we've enabled all of the state functionality, but remember, states are reset on page load. I'm letting you think for a second, and I know what you're thinking. You're thinking, "well, Greg, it's not going to show them my image if it's a state, because the next time they arrive at the dashboard, there is no state. So at some point, a state has to be set." So why don't we set the state with the image that's been saved to the database so we can recreate this functionality again? Because maybe Hana is coming back to update their image a third time.
Okay, so I'm going to click on Group Navlink (Settings), edit the workflow, and then we're going to go to add a new action and go to "Element Actions" --> "Set state." Set it at the company level, and currently the state is empty, but the image has probably been saved to the database, so we're going to go pull it out of the database and into this image state. So input "Current User's Avatar" for the value. Now, by default, a "Go to page" action has to be the last step, so I'm going to pick up Step 1 and move it to the next step. And it doesn't matter if the Current user's Avatar is empty, there is no one, it doesn't matter. It does not matter.
Okay, I know that's a lot to take in, guys. One small change I want to make before we test this out is on the Alert Successfully saved. I just want to change the weight to 500 (Medium) and the size to 14. And I'm just going to make sure that in the style, it's the same thing, okay? 14 px and 500 (Medium). I'm just trying to be consistent with text weights in this build. And then maybe on the Layout tab, we'll change the min height to 44. Yeah, we still obviously want to be able to see it, but it's green. I mean, how can you miss it in the center at the top? Actually, one more thing we need to do on this alert is just set a top margin of maybe about 12, just so it's not touching the top of the page. Yeah, sitting in the center here.
Okay, so you learned some new concepts there, and this is how I build my UX around picture uploaders: I use states. Can you save it directly to the database? In some instances, yes, you can because it's the Current User who exists, but I prefer this! It keeps your database clean. And we're going to come back later to also talk about how do we delete an image? Because an image field in Bubble is just a link to Amazon Web Services, who Bubble uses and installs automatically for you. And that actually is hosted there, so we'll talk about how to delete a file a bit later on. But for now, we're done. And when we come back, we're going to sign up as Hana and start working on updating Hana's details. I'll see you then.