Skip to main content

Deleting a list of things (Lesson 3.10)

We have the power in Bubble to delete multiple things at once. In our app, we want to use this power to delete all of the diary entries associated with a trip whenever we delete that trip.

Sofia Maconi avatar
Written by Sofia Maconi
Updated today

Transcript

In this lesson, we're going to learn how we delete multiple things at once because we want to create this end-user experience where a user can click on this little three dot menu here at the top and then go to delete their trip and all of the diary entries that are associated with the trip should also be deleted at this time.

So to start with, let's just do a little bit of user experience housekeeping here and set up this three dot menu. So, I'm actually going to set this up as another trailing button in our app bar on our trip details page. And we'll set the button type to be an icon. And the one that we're looking for here is just this really simple dots three. And we'll set it to be our text color as well.

Now, we've talked about the size for icons that are clickable being at least 44 pixels on their width and also on their height to give users the best chance of tapping them. And if we do that here, we could also bump up the icon size here for our ellipsus, or as it's otherwise called, our three dot icon.

Just note that at the time of recording, there's a slight bug with these icons. So, this is our filters icon that is the 44 pixel size. If I go and open another view here, and then go back, you see how the bottom of it here is just slightly cut off. Now, this isn't really a problem for our three dot icon since it doesn't have a background, but of course, it is for this filters icon.

So, what we might want to do just to work around this bug in the meantime is just to set the fixed width to be slightly smaller, like 36 pixels, which is just going to solve that UI issue at the expense of making that filters icon there just slightly smaller to tap on.

At any rate, let's add the menu that will appear when this three dot icon is clicked. So, I'm going to add a new sheet to the page. And this can be our sheet menu. And I'm just going to add two buttons to it. That's all I'm going to do. I'm going to add two buttons to it.

The first thing that I'm going to do is change the style here to this link light secondary. And I want this to be our edit button, which is going to have both a pencil icon. So I'm going to choose here from the Phosphor library and add that same pencil icon that we've used over in the top here. And then the label can just be edit.

And then I want everything over here on the left-hand side. So I'm going to set the alignment to be left aligned. The gap between the icon and the label can probably be increased a little bit as well. So we'll use one of our trusty eight-point grid numbers again: 16.

And then on the sheet so that our button isn't hard up against the edges here, I will add 16 pixels. Again, that trusty number of padding on either side.

And then I'm just going to duplicate this by hitting command or control D on my keyboard. And this is actually going to be our delete button. I want this to be actually a red color. So I'm going to choose here this link light destructive instead.

And then we've just got to change these settings again. So the icon in this case is actually going to be again from the Phosphor library and we're going to look for this trash icon. And then of course let's not forget to change the label to delete.

Now we can add the workflow to our three dot menu which is going to show this sheet. And so if we test this out by hitting that three dot menu, you can see there is our sheet.

A couple of small tweaks I think I'd make here is just adding a little bit of space between the two buttons. So I'll add 16 pixels. And then let's reduce the height of this sheet by setting the default snap point to fit its height to the content of the elements inside.

When we test that out, we get this behavior here, which I think is pretty good.

So now just to wrap this up before we get into the delete logic, we've got this existing edit icon on the page, this trailing button. The workflow that is attached to this icon, which is going to go to the trip, create an edit view. I want to reattach this action to this edit button here, which is called button edit.

And one way that you can do that is if you go into the workflow tab and you find here the workflow event that is triggering this workflow, you can see it's attached to the trailing button. That's the pencil icon there in the header.

So what we can do is we can just change this trigger element to some other element on our page like the edit button that we just created. And then we should be safe to delete by hitting backspace on our keyboard that old pencil trailing icon in our app bar.

That will then result in this lovely UX where if I hit the edit button then I'm going to view that edit modal and I can hide that as well. The only thing is that that sheet stays on the page.

So, one thing that you want to do in these situations is just explicitly hide the sheet as well when the user has clicked one of the buttons inside of it. So, we'll hide that sheet menu.

Now, of course, we could finesse the menu here a little bit more by increasing the gray out color so that more of the screen is grayed out and maybe adding very slight blur as well. Maybe we even decide that this delete button is a little too close to the bottom. So, we add just a little bit of extra padding at the bottom of the sheet.

These are all things that I encourage you to tweak depending on the aesthetic that you're going for in your application. And when we use a sheet in this kind of user experience, as what we might call a drawer or just like a little bottom context menu here, we don't really need to have a cancel button. The user can just swipe down on the top of the sheet to remove it from view.

Now, let's get on to the delete logic. As much as possible, when we're developing in Bubble, we want to just try to reuse logic and interface elements that we've already created elsewhere. And of course, one of the things that we've already set up is this delete confirmation sheet to delete a trip that lives here on the trips view.

One way that I can just reuse an entire element like this, including its logic and workflows, is actually just to right-click on it and go down to copy special → copy with workflows. So I'm going to hit that. And I'm just going to go back to my trip details view. And then just somewhere on the canvas, doesn't really matter where, I'm going to right-click and I'm going to paste special → paste with workflows.

So what that's going to do is it's going to not only add that entire element to this view, but also if we go and inspect the workflows attached to the elements inside, like this delete button, you'll see that they are preserved. So that's already really, really handy because it means that all we need to do now is, if I go and hide this sheet and show our menu sheet instead, I can just hook up this delete button to show that delete confirmation sheet that we just copied over.

So all I'm going to do here is I'm going to hit show that delete confirmation sheet. And note here how our delete confirmation sheet has this cancel button hooked up to it, which is just going to hide that delete confirmation sheet. And that means that the behavior here by default is that if I now hit delete, I'm going to show that new sheet. It's going to be pushed above the menu sheet. But if I hit cancel, that menu sheet is going to still be visible.

So that may or may not be the behavior that you want in your application. And then also, if I show the delete confirmation sheet and I swipe down on the top of the sheet to hide it, then the preceding sheet underneath will be visible.

So you have to be very explicit when you're using multiple sheets like this that trigger each other as to when you want them to be hidden. In our case, I want that if the user navigates off of this sheet in any way, shape, or form, that they just end right back on the trip details view on this sort of parent view.

So to do that, I'm actually just going to be really explicit. When I am showing the delete sheet from clicking this button here, I'm going to, after I show the delete confirmation sheet, just hide that menu sheet. And that's going to mean that if we show the delete confirmation sheet, hit cancel, we just end right back onto the home view. Equally, if we hit delete to show the sheet and then swipe down on the top of it, then we're just straight back on the trip details view.

Now, one of the things that you may have noticed when this sheet is shown is that it seems like we're missing some text here. That text is appearing properly if we try to delete from the trips view. And that's because on the trips view, when one of our swipe actions is taken, what we're doing first before we show the delete confirmation sheet is actually displaying in that sheet the trip that we want to delete.

And that's possible because the delete confirmation sheet here has a type of content as a trip. And that, of course, is going to allow this text element to display the trip's title. But also, when this delete button is clicked, we know what trip to delete. So we need to reconnect this logic on our trip details view here.

And that means that when this delete button is clicked in our menu, we're going to add an action here before we show the sheet, which is just going to be that display data in a group action. And which group are we displaying data into? Well, of course, it's the sheet delete confirmation that's set up to hold that trip.

And then which data are we pushing into this delete confirmation sheet? Well, of course, this delete button exists here within the context of the trip details view, which has, as we set up earlier, a trip property. So this trip details view already has access to a particular trip. It's now just a matter of passing that on. It's just a matter of pass-the-parcel basically.

So, trip details view holds the trip, makes it available to be passed on to sheet delete confirmation. Let's add it there: the trip details trip. And then, of course, we can show the delete confirmation sheet after that. And then, when the delete button here is clicked, this delete trip action will just be deleting the trip that we just populated into the sheet.

So this will all work now fine. And if I try to delete one of my test trips here, so I'm going to hit delete, we do need to reconnect our navigation logic after that trip is deleted because now we're just here on the empty trip details view.

But one thing that we can notice is that if we go into our database, we'll see that that trip actually doesn't exist here. However, the diary entries related to that trip still do exist. So this is where we need to add our logic for not only deleting a trip but deleting all of the diary entries that are connected to that trip.

This is actually fairly straightforward to do. We have an action which I can add within this delete workflow, which lives under data and it's called delete a list of things. We hit that. We're going to select what type of thing we want to delete. So in our case, of course, that's diary entries.

We're going to say which diary entries do you want to delete? So we need to tell Bubble where to look to find the entries that we want to delete. And when we're looking for a list of data, most of the time we're going to be using this do a search for operator or data source.

We, of course, are searching for diary entries. And then which diary entries in particular do you want to delete? Well, the diary entries that are all attached to this trip that we're deleting, right? So we'll add a new search constraint which is going to look, or basically going to ask the question of each diary entry in our database: "Hey, is your trip the same trip as the trip inside of the trip details view?"

Right inside of the trip details view here that the user has hit delete from. So that trip, from the context of this sheet, actually it could be either living inside of the trip details view. Technically, this would work, but it's cleaner since we are running this from the context of a sheet and we're already passing in a trip into that sheet that we just rely on the sheet's data source.

Sort of protects us if we need to move this entire sheet, copy with workflows once again. Then it's all self-contained. Nothing's going to break because it's referencing data that lives in another element.

If that all sounds a little bit too abstract, don't worry too much about it. In short, both of these data sources will work absolutely fine. So, we're going to choose sheet delete confirmation's trip, the same data source that we are using. So, we're going to set this to it could be either the sheet delete confirmation's trip or because this delete button, if I click on it and right-click to reveal it in the design canvas.

That's another little handy trick. This delete button lives inside of a sheet which is holding on to a trip type of thing that allows the actions or the workflow attached to this button to access the parent group's data source. So the content within that parent sheet.

So we could also, by that logic, use here the parent group's trip, which, as it so happens, is exactly what we're doing for the actual delete trip action. So what we're doing is we're first deleting all of the diary entries attached to a trip and then we're deleting that trip.

If we're going to do that, yeah, hiding the sheet kind of feels a little bit redundant actually. So I'm going to delete it. What we probably want to do instead is actually just navigate the user back to that trips view.

So I'm going to navigate the user here in a stack back to the trips view. And if we go and test this out by deleting this family trip to Spain, so I'm going to hit delete and go delete. Well, the user experience isn't quite what we expect, is it?

We've still got this delete confirmation sheet appearing. And if I click to hide it, I see that I've got this back button up the top. What's that about? I can actually click on that and it will take me to the trip details view, but it's empty. There's no trip details in here.

So, what's going on here? Can you actually work it out for yourself what's going on when we click that back button? Well, if we look at the workflow for when this delete button is clicked, the last thing that we're doing here is we are adding the trips view as the latest view on the stack.

And if you remember, we've got some built-in navigation ability within the mobile app that we build to be able to go back to the previous view in the stack. So essentially, take off that top trips view and reveal the view underneath just like a stack of cards. So that's what was happening within the app bar of our trips view here.

Only the view that it allowed us to go back to was actually the trip details view for a trip that we just deleted. Hence why it's just appearing here as empty. Also, the fact that the delete confirmation sheet was still visible is because we didn't explicitly hide it here within this workflow. But we don't have to do that.

And we can remove this ability to go back to this trip details view by just hitting reset navigation stack. So what this is going to do is, given a stack of views, instead of just adding the trips view as the latest view on the stack, which would then allow us to remove it and go back to the previous view, what reset navigation stack does is that it adds trips as the latest view on the stack, but it also just gets rid of the previous stack.

So, this effectively is the new stack. So, with a new test trip that I've just quickly created, I'm going to test this out by hitting delete and now confirming the deletion. And now, look, we're back on the trips view. I can't go back. There's no weird sheets appearing.

Although, it wouldn't hurt to just add it in here because you saw there was sort of a slight glitch there for a second where you could still see the sheet. So, it wouldn't hurt to add it in there. But nonetheless, resetting the navigation stack is definitely what we want to do.

And critically, if we look in our database, the diary entries that I had just created for that trip aren't there. And neither is the trip.


Quick housekeeping note: in the app that we're going to end up building, I want to also, within the diary entry details, be able to click on the three dot menu and delete a diary entry from its own context menu.

So, I'm just going to spend a few minutes here at the end of this lesson setting up this exact structure for our diary entry. You can follow along with me if you want; otherwise, feel free to skip to the next lesson.

First thing that I'm going to do is I'm going to copy this sheet menu, and I'm going to put that over in our diary entry details view. I'm literally just going to paste it in here. I'm not going to paste it with workflows because there's no workflows that I can just port over. I have to recreate them because they're going to be unique to this diary entry details view.

Just as before on our trip details view, we've got this old pencil icon. I'm gonna add a new trailing button next to it, and that's going to be my three dot menu there. We'll make it text. I'm going to add another trailing button next to it, which is going to be the three dot menu, and it's going to be text colored.

Then we've got the existing trailing button for the three dot menu, which I could actually just create a new style from and call it something like clickable icon. And then I can just apply that style to the new trailing button that I just created. That's going to just give it the right icon size there. But I will need to set the width and the height manually.

Of course, what we want to do on this button is have it trigger the display of that menu sheet. And we can hook up our edit button in exactly the same way as we did for our trip by just swapping out the logic that is currently attached to this pencil icon, which if you recall is set up to show the diary entry create and edit view.

So, instead of this being triggered when the trailing button is clicked, I'm going to set this instead to be when that button edit is clicked. And I'm going to make sure that I hide my sheet here as well, just to be safe. That means that if I open up one of my diary entries and hit that three dot menu, hit the edit button, then things seem to be working fine. I can even close that modal. That's great.

So, we can now remove this trailing button because we don't need it. And then just add our delete logic.

The delete logic I'm going to recreate, but I am just going to steal the delete confirmation sheet because that's really handy. So, I'm literally just going to right-click, copy that, and paste that into my diary entry details. I'm just going to repurpose this delete confirmation for diary entry details.

So the type of content here, instead of being a trip, we can set this to be a diary entry instead. And then just update the text here to be the parent group's diary entry's title that we're warning the user is about to be deleted.

But then for this value to actually show up as something, we're going to have to push a diary entry into this delete sheet. Which means that on our sheet menu, when this delete button is clicked, we need to add a workflow that is going to show that delete confirmation sheet. But before we show it, we need to populate it with the diary entry that we're going to delete or temping ourselves to delete.

So we're going to use that same display data action there. So, we're going to display inside of sheet delete confirmation the diary entry, which of course comes from the diary entry details diary entry.

Perfect. That just means now if I go and click the three dot menu, format a diary entry, hit delete, you can see there is the name of the diary entry that we want to delete.

Only thing we have to worry about here is if I try to close this sheet, the menu sheet appears again. That's because we forgot to add a hide action. So, you've got to be a little careful when you're stacking sheets on top of one another.

You've really got to explicitly tell a sheet that you no longer want to see it; it's got to be hidden. Otherwise, it will just pop back into view when a sheet on top of it disappears. So, we're going to hide that sheet menu explicitly.

While we're here, let's also add a workflow on the cancel button to hide the delete confirmation sheet, which will result now in the behavior where I can show the delete confirmation sheet, swipe down on it, and I won't see that menu anymore. Equally, I can hit the cancel button and it'll just disappear.

So now the only thing for us to do is to hook up this delete button. So I'm going to add a workflow here. And again, please do try to figure this out for yourself. We're not introducing anything new here. We're just rounding out the end-user experience that we need for this application.

But what we're going to do predictably is delete a thing. Right? So, we're going to delete here the parent group's diary entry. That's the diary entry inside of this sheet, parent group's diary entry.

Beautiful. And then we can do two things to be safe. I always like to explicitly hide the sheet that we no longer want to see. So we're going to hide sheet delete confirmation. And then we don't want to hang out any longer on the view for the diary entry that we just deleted. So, it makes sense that we navigate the user off of the diary entry details view.

And we can just go back, right? Let's just go back to the previous view, which in our application right now is going to mean going back from the diary entry details to the trip details view.

So let's test this out by confirming the deletion, and I'm going to be now back on the parent trip, and the diary entry that we just deleted is, of course, gone.

Okay, so that rounds out this section of the course on working with data. In the next section, things are going to get even more interesting because we are going to learn how we can access resources, features basically on the user's actual device like their camera, their photo library, or even their GPS location.

So I will catch you in the next section.

Did this answer your question?