Decoupling the browse gallery from the display / edit forms in PowerApps
One of my favorite features of PowerApps is the "Start with your data" way of creating apps. The ability to start with a fully-functional app (a browse screen that lists the items from your data source, plus two screens with a details view and an edit view of individual items) that you can customize is a great way for people to start playing with the platform. The app that is generated has fairly simple formulas, to further help understanding how PowerApps works.
One of the characteristics of the app is that both the detail and the edit forms used in the app are bound to the selected item in the gallery: the Item property of the form controls is set as shown below:
DetailForm1.Item: BrowseGallery1.Selected EditForm1.Item: BrowseGallery1.Selected
This works well for most cases - but now all. A user in the forums wanted to have not one but two browse galleries, so it couldn't bind the item in the forms to only one of them. Another user wanted to go to the display/edit screens not by selecting an item in the gallery, but by performing a lookup in the list based on some property (such as an id). I've also faced a problem while using that app, since it's possible possible that, after changing the item, it will not be part of the items shown in the gallery anymore (as shown in the example below):
One way to solve this problem - and some of the other problems I mentioned above - is to decouple the form item from the gallery selection, by passing the item that is selected to the screens in which the forms appear. I'll go over the changes needed below.
The browse screen
Let's start with the browse screen. Currently, the formula for the NextArrow1 icon in the gallery that navigates to the details page doesn't pass any information to that page, but we can change it using the third argument to the Navigate function:
NextArrow1.OnSelect: Navigate(DetailScreen1, ScreenTransition.None, {displayItem:ThisItem})
When the screen 'DetailScreen1' is shown, it will contain a context variable that will have the item that was selected in the gallery (via the ThisItem operator).
The details screen
In the details screen, the places that reference the gallery's selected item will need to be changed, to reference the item
variable that was passed to this screen:
DetailForm1.Item: displayItem IconDelete1.OnSelect: Remove(Contacts, displayItem); If (IsEmpty(Errors(Contacts)), Back())
We also need to change the OnSelect property of the edit icon, to pass the item that is being viewed to the next screen to be edited:
EditForm(EditForm1);Navigate(EditScreen1, ScreenTransition.None, {editItem:displayItem})
The edit screen
As the item was passed from the details screen, we also need to update the reference in the edit form to use the item that was passed. In addition, when a form is submitted successfully, then we need to update the item to be displayed (to reflect the changes made by the user). We can use the LastSubmit property of the form, which contains "the last successfully submitted record" - which is exactly what we want to display.
EditForm1.Item: editItem EditForm1.OnSuccess: Navigate(DetailScreen1, ScreenTransition.None, {displayItem:EditForm1.LastSubmit})
And those are the main changes that need to be made. There is a small difference in behavior - when a new item is created, before the user would be sent back to the browse screen (via the Back function), but with the change in the OnSuccess property of the edit form it now always navigates to the details page. That's something that has been requested as well, but if you prefer the old behavior, we can always pass another parameter when navigating to the edit screen (such as a true/false value that indicates whether to navigate to the browse or details screen) and use the If function to decide where to send the user.
Comments
- Anonymous
November 04, 2017
Thanks very much for this article - helped me a lot.One area I was stumped on for a while was where I had two forms, a DisplayForm on one screen and an EditForm on another and I needed a button on the DisplayForm to take me to the EditForm and set it to show the same record.I did this by creating a new context variable in the Navigate function and setting it to the existing displayItem variable as follows:EditForm(frmPayOrder);Navigate(scnPayOrder, ScreenTransition.Fade, {displayItemPayOrder:displayItem})On my EditForm I set the Item property to displayItemPayOrder.