cancel
Showing results for 
Search instead for 
Did you mean: 
paul_culmsee

Tips and Tricks for multiselect controls with advanced tagging options

Hi

 

I use SharePoint managed metadata a lot these days, as it provides a really important function in allowing effective content tagging.

 

A little while back, the PowerApps team rolled out support for managed metadata. This made me a very happy consultant indeed because I was working on a project that made heavy use of it. 

 

As a quick SharePoint managed metadata refresher, consider the example of a simple idea register. Below is a SharePoint list called IdeaRegister with 2 managed metadata columns called Audience (who the idea applies to) and Project Phase (what part of the project should this idea be done). My idea is to provide more icecream to hardworking people in Corporate Communications during the Risk and Design phases of the project.

 

 Blogpic1.PNG

 

This type of SharePoint list is now fully supported in PowerApps. We connect to this list as a data source and if we add an edit form to our app, we will get a default experience like the screen below. Our two managed metadata fields are rendered by default as combobox controls..

 

Blogpic2.PNG

If we take a closer look at the second combobox, we can see that multi-valued managed metadata columns are fully supported which is great. What is also nice is if you wish to make a change, the control has a built-in search/refiner that helps you quickly find terms. In the example below I type in the letters "C" and "O" and the three matching terms are listed for me to choose...

 

Blogpic3.PNG

But screen real-estate comes into play here. As per the above image, I picked "Construction". Now take a look at the screen. We can no longer see our tags. Instead we are told how many items were tagged and we have to click on the control to see what was tagged. 

 

Blogpic4.PNG Blogpic5.PNG

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I found this default experience a bit unfriendly, so I set about coming up with an alternate way of doing it. First here is a screenshot of an alternative approach. You can see that I have opted for an approach that removed dropdowns altogether. When a user click the tag button, they are prompted to pick one or more tags via a pop-up dialog...

 

Add in new idea and click tagAdd in new idea and click tagTag one or more rolesTag one or more rolesView all tagged rolesView all tagged roles 

Not only does this method look friendlier than the default experience, it has some other advantages.

 

  1. The approach is repeatable. Basically each time you click a tag button it is the same popup that appears, but it is able to handle the different managed metadata columns.
  2. The approach is bandwidth efficient. It will require less connection to SharePoint and in fact can be used in an offline scenarios as well.

So how was it done? Fortunately I recorded a video entitled "Have more team cuddles (and some PowerApps UI tricks with Managed Metadata)" - which if I say so myself, has to be a PowerApps academy award nominee in the category of "coolest PowerApps video title ever". 

 

In the video I delve into detail, but for the sake of keeping this article readable, I will just provide a high-level view on the tricks used...

 

 

Okay so in a nutshell I used the following tricks...

 

  1. The (at the time of writing) undocumented function called Choices()
  2. The Addcolumns() function
  3. A Canvas control with 3 Datacards and a gallery
  4. Some trickery with collections.
  5. The Patch() function 

The Choices() function is very useful. It basically allows you to retrieve all of the possible values from a column that has a discrete set of values. It takes a column from a connected data source as a parameter., In the example below, I used the managed metadata column named Audience and stored it in a variable called ChoiceList.

 

Blogpic9.PNG    Blogpic10.PNG

The data returned by this function is a table and the format depends on the type of column. For managed metadata columns we get columns called Label, Path, TermGuid, Value and WssId. Now the meaning behind these columns aren't that important for this article except to say that Label is the column that stores the term a user picks from.

 

Blogpic11.PNG

 

So armed with this knowledge, we can grab the latest set of managed metadata terms from a data source on application startup and store it in a variable or a collection.

 

Next I need to track which terms a user has selected. If you look at my screenshots above the video, you can see that the app tracks tagged terms via changing their color. To do this, I had to add an extra column to the table returned by the Choices() function. This column tracks whether this tag was selected by the user. I used the AddColumns() function to do this...

 

Blogpic13.PNG

 

AddColumns() takes multiple parameters. At a minimunm you specify 1) The collection or data source you want to add a column to, 2) The name of the new column and 3) the default value of the new column. In the screenshot above you can see that I have created two collections to store tags for Auduence and Project Phase. The additional column I named Selected with a default value of false. If we check out the AudienceTags collection, we can see the intended effect - a new column called Selected.

 

Blogpic14.PNG

 

Next comes a bit that might seem countere intuitive. I want to have a screen pop up and ask the user to tag content. But I want to make a single tagging pop-up rather than make multiple screens for each managed metadata column. I did this by taking advantage of the ClearCollect() function. 

 

In short, depending on which tag icon you click, I initialise a generic collection called TagList by making a copy of the tag collection I want to work with. The diagram below shows how each button initialises the taglist from the two different source collections...

 

Blogpic16.PNG

 

That means we now have a collection of tags all ready to go and all we need now a tag selector UI. Rather than make a separate screen for this, I added a canvas control to my screen. (To do this, create a scrollable screen or cut and patse a canvas from such a screen.) I then added three data cards to the canvas and set their Fill property to a see-through grey color. I resized the middle data card to take up most of the screen. The net result is a nice overlay effect.

 

Blogpic15.PNG

In the middle data card, I added a gallery, set the data source to the TagList collection and added some nice formatting to make it look pretty. I added a button to the gallery to display the tag because I like the rounded edges (buttons have a property to control roundness). I also threw in the built-in tag icon and the result was the following...

 

Blogpic17.PNG

 

Next step is to record when a user select or de-selects a tag. I did this using the UpdateIf() function to change the value of the Selected column (remember I added that earlier). The function looks like this:

 

Blogpic18.PNG

 

Now we need to show the user that the tag has been selected. We do this by making the fill property of the button conditional on the selected column being set to true. Now that we have a boolean column called Selected, I can test for ThisItem.Selected. 

 

Blogpic19.PNG

 

Here is the effect... You can click and unclick to your hearts content...

 

Blogpic20.PNG

 

It was around this point that I also made the canvas conditionally visible. By default, the canvas is hidden and is only visible when a user clicks on one of the tag buttons. After tagging, the user either clicks the Done or Cancel buttons to hide the canvas again.

 

I did this by creating a variable variable called ShowCanvas and setting the Visible property of the Canvas to it. 

 

The final thing I did was to modify the Done button. Recall that the canvas only works with a generic collection called TagList. Once a user has chosen their tags, we need to save TagList back to the original collection (Audience or Project Phase), so I added some conditional logic to the button to copy TagList contents back to the source collection.

 

Now all I need to do is save this data back to SharePoint. For this, we will use the patch() function. Now this command looks way worse than it actually is, and I strongly recommend any aspiring PowerAppers to get familiar with it. Here is my patch function...I have wired it to the OnSelect property of a submit icon as shown below:

 

Patch(IdeaRegister,{ Title: TbComment_1.Text, Audience: Filter(AudienceTags, Selected), ProjectPhase: Filter(WBSTags, Selected) })

 

Blogpic21.PNG

 

The first parameter to Patch is the data source we want to write to, which in my case is the SharePoint list containing the managed metadata columns. Of interest is how I patched the Audience and ProjectPhase columns. I was able to simply send the collections straight back to SharePoint as a patch parameter. All I did was filter the collections to only send back those marked as selected...

 

Neat huh? In fact the SharePoint connector did not care about the additional Selected column either... it happily added the new idea to SharePoint as intended.

 

Blogpic22.PNG

I hope this article gave you some ideas for your own approaches. I should note that this approach is not well suited to multi-level managed metadata term sets, but I have a solution for that too, which I hope to cover in a future article and video.

 

Thanks for reading

 

Paul 

 

 

Comments

Fantastic thank you PC!

Hi Paul,

 

Did you manage to fetch more than 20 terms using the Choices function? I am implementing something similar and came across a PowerApps limitation when using managed metadata columns...I can fetch all the items only if I pass a text filter to the choices function, but that gives me information in chunks of data...for cases when we have loads of terms in the term set that would be nice to have a way to fetch them all at once and then do our manipulation.

Dear Paul, 

Super article! You mentioned: multi-level managed metadata term sets... I can do that too in a later article... did you ever publish that? If not, can you help me with that?

This is an awesome article.

 

However, I've run in to the same issue that @michelcarlo  posted a question about

"Did you manage to fetch more than 20 terms using the Choices function?".

 

Just wondering if there has been any solution or workaround to retrieve all terms in a termset.

 

Cheers

Anthony

@Pinnidgi I'm still waiting for a solution on this hahah