Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions samples/dynamic-tag-gallery/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Dynamic Tag Gallery Component

## Summary

This Power App demonstrates a component displaying a gallery of hashtags detected automatically from text and which dynamically places the hashtags in buttons across rows depending on the width of each and the room available on the row.

![Component Demonstration Screen](assets/Screen1.png)

Kudos to Dave Wyatt for his implementation of this concept and for giving me the idea for this approach. Building on his version that uses a predetermined number of buttons within a container, my approach uses a gallery to create as many buttons as required dynamically. Please do read [Dave’s excellent blog](https://community.powerplatform.com/blogs/post/?postid=b3d4acb9-bfc6-ef11-b8e8-7c1e5267b708) first.

## Applies to

![Power Apps](https://img.shields.io/badge/Power%20Apps-Yes-green "Yes")
![Power Automate](https://img.shields.io/badge/Power%20Automate-No-red "No")
![Power BI](https://img.shields.io/badge/Power%20BI-No-red "No")
![Power Pages](https://img.shields.io/badge/Power%20Pages-No-red "No")
![Power Virtual Agents](https://img.shields.io/badge/Power%20Virtual%20Agents-No-red "No")
![Dataverse](https://img.shields.io/badge/Dataverse-No-red "No")
![AI Builder](https://img.shields.io/badge/AI%20Builder-No-red "No")
![Custom Connectors](https://img.shields.io/badge/Custom%20Connectors-No-red "No")
![Power Fx](https://img.shields.io/badge/Power%20Fx-Yes-green "Yes")

## Compatibility

![Premium License](https://img.shields.io/badge/Premium%20License-Not%20Required-red.svg "Premium license not required")

## Contributors

* [James Williams](https://github.com/wjamesw)

## Version history

Version|Date|Comments
-------|----|--------
1.0|Febrary 2nd, 2025|Initial release

## Prerequisites

None

## Minimal path to awesome

### Using the solution zip

* [Download](./solution/dynamic-tag-gallery.zip) the `.zip` from the `solution` folder
* Within **Power Apps Studio**, import the solution `.zip` file using **Solutions** > **Import Solution** and select the `.zip` file you just downloaded.

### Using the source code

You can also use the [Power Apps CLI](https://docs.microsoft.com/powerapps/developer/data-platform/powerapps-cli) to pack the source code by following these steps:

* Clone the repository to a local drive
* Pack the source files back into a solution `.zip` file:

```bash
pac solution pack --zipfile pathtodestinationfile --folder pathtosourcefolder --processCanvasApps
```

Making sure to replace `pathtosourcefolder` to point to the path to this sample's `sourcecode` folder, and `pathtodestinationfile` to point to the path of this solution's `.zip` file (located under the `solution` folder)
* Within **Power Apps Studio**, import the solution `.zip` file using **Solutions** > **Import Solution** and select the `.zip` file you just packed.

### Use the component in your app

Open your target app and click the **Get more components** icon from the **Insert** tab. On the **Import components** pane, select **cptTagGallery** from the **Dynamic Tag Gallery Component Library** and then click **Import** to import the component into your target app.

Then select **cptTagGallery** from the **Library components** group on the **Insert** tab.

Set the **Input Text** property of the component instance to the text, or the source of the text, you want the component to analyse.

Set the **Button Padding** and **Button Margin** properties of the component instance, or leave these as their default values.

Add logic to your app to retrieve the **Output Tags** property from the component instance.

## Features

The component displays a gallery of hashtags detected automatically from text and which dynamically places the hashtags in buttons across rows depending on the width of each and the room available on the row.

This is done using a technique whereby the controls in the gallery all have their co-ordinates calculated dynamically using the whole space within the gallery, rather than just the usual row per item within the gallery. This technique can be used to create many interesting visuals.

The dynamic calculations take place predominantly within the OnReset function of the component.

The key to successfully aligning controls in a gallery space is ensuring that you compensate for the offset of (at least) one pixel, resulting from the Template Size property of the vertical gallery control, which can not be set to zero. Apart from that one issue, controls across items in a gallery do not have to stay within the bounds of their item's row.

This solution illustrates the following concepts:

* Power Apps components

## Help

We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.

If you encounter any issues while using this sample, you can [create a new issue](https://github.com/pnp/powerapps-samples/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=dynamic-tag-gallery&authors=@wjamesw&title=dynamic-tag-gallery%20-%20).

For questions regarding this sample, [create a new question](https://github.com/pnp/powerapps-samples/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=dynamic-tag-gallery&authors=@wjamesw&title=dynamic-tag-gallery%20-%20).

Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/powerapps-samples/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=suggestion.yml&sample=dynamic-tag-gallery&authors=@wjamesw&title=dynamic-tag-gallery%20-%20).

## Disclaimer

**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**

<img src="https://m365-visitor-stats.azurewebsites.net/powerplatform-samples/samples/dynamic-tag-gallery" aria-hidden="true" />
Binary file added samples/dynamic-tag-gallery/assets/Screen1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 71 additions & 0 deletions samples/dynamic-tag-gallery/assets/sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
[
{
"name": "pnp-powerplatform-samples-dynamic-tag-gallery",
"source": "pnp",
"title": "Dynamic Tag Gallery Component",
"shortDescription": "This Power App demonstrates a component displaying a gallery of hashtags detected automatically from text and which dynamically places the hashtags in buttons across rows depending on the width of each and the room available on the row.",
"url": "https://github.com/pnp/powerplatform-samples/tree/main/samples/dynamic-tag-gallery",
"downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/powerplatform-samples/tree/main/samples/dynamic-tag-gallery",
"longDescription": [
"This Power App demonstrates a component displaying a gallery of hashtags detected automatically from text and which dynamically places the hashtags in buttons across rows depending on the width of each and the room available on the row."
],
"creationDateTime": "2025-02-02",
"updateDateTime": "2025-02-02",
"products": [
"Power Apps",
"Power Fx"
],
"tags": [
"Hashtag"
],
"categories": [
"CANVAS",
"COMPONENT-LIBRARY"
],
"metadata": [
{
"key": "POWERAPPS-EXPERIMENTAL",
"value": "No"
},
{
"key": "POWERAPPS-PREMIUM",
"value": "No"
},
{
"key": "POWERAPPS-ONPREM",
"value": "No"
},
{
"key": "POWERAPPS-CUSTOMCONNECTOR",
"value": "No"
}
],
"thumbnails": [
{
"type": "image",
"order": 100,
"url": "https://github.com/pnp/powerplatform-samples/raw/main/samples/dynamic-tag-gallery/assets/Screen1.png",
"alt": "App preview"
}
],
"authors": [
{
"gitHubAccount": "wjamesw",
"pictureUrl": "https://github.com/wjamesw.png",
"name": "James Williams"
}
],
"references": [
{
"name": "Microsoft Power Platform documentation",
"description": "Discover how to make the most of Microsoft Power Platform products with online training courses, docs, and videos covering product capabilities and how-to guides.",
"url": "https://learn.microsoft.com/power-platform/"
},
{
"name": "Components from Components - Dynamic Tags (by Dave Wyatt)",
"description": "In this example we are going to build our own dynamics tags, an example is Power DevBox Shortcut, a Edge/Chrome Extension which creates custom tags to filter your environments by",
"url": "https://community.powerplatform.com/blogs/post/?postid=b3d4acb9-bfc6-ef11-b8e8-7c1e5267b708"
}
]
}
]
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# msbuild output directories
/bin
/obj

# MSBuild Binary and Structured Log
*.binlog
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PowerAppsTargetsPath>$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\PowerApps</PowerAppsTargetsPath>
</PropertyGroup>

<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<Import Project="$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Solution.props" Condition="Exists('$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Solution.props')" />

<PropertyGroup>
<ProjectGuid>fbea9f87-0fe7-48e6-bde7-d077726d7344</ProjectGuid>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<!--Remove TargetFramework when this is available in 16.1-->
<TargetFramework>net462</TargetFramework>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<SolutionRootPath>src</SolutionRootPath>
</PropertyGroup>

<!--
Solution Packager overrides, un-comment to use: SolutionPackagerType (Managed, Unmanaged, Both)
Solution Localization Control, if you want to enabled localization of your solution, un-comment SolutionPackageEnableLocalization and set the value to true. - Requires use of -loc flag on Solution Clone or Sync
-->
<!--
<PropertyGroup>
<SolutionPackageType>Managed</SolutionPackageType>
<SolutionPackageEnableLocalization>false</SolutionPackageEnableLocalization>
</PropertyGroup>
-->

<ItemGroup>
<PackageReference Include="Microsoft.PowerApps.MSBuild.Solution" Version="1.*" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\.gitignore" />
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\bin\**" />
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\obj\**" />
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.cdsproj" />
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.cdsproj.user" />
<ExcludeDirectories Include="$(MSBuildThisFileDirectory)\*.sln" />
</ItemGroup>

<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)\**" Exclude="@(ExcludeDirectories)" />
<Content Include="$(SolutionPackageZipFilePath)">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" />
<Import Project="$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Solution.targets" Condition="Exists('$(PowerAppsTargetsPath)\Microsoft.PowerApps.VisualStudio.Solution.targets')" />

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<CanvasApp xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>crad7_dynamictaggallerycomponentlibrary_de9c6</Name>
<AppVersion>2025-02-02T20:34:15Z</AppVersion>
<Status>Ready</Status>
<CreatedByClientVersion>3.25013.14.0</CreatedByClientVersion>
<MinClientVersion>3.25013.14.0</MinClientVersion>
<Tags>{"primaryDeviceWidth":"640","primaryDeviceHeight":"640","supportsPortrait":"true","supportsLandscape":"true","primaryFormFactor":"Phone","showStatusBar":"false","publisherVersion":"3.25013.14","minimumRequiredApiVersion":"2.2.0","hasComponent":"true","hasUnlockedComponent":"true","isUnifiedRootApp":"false"}</Tags>
<IsCdsUpgraded>0</IsCdsUpgraded>
<GalleryItemId xsi:nil="true"></GalleryItemId>
<BackgroundColor>RGBA(251,101,60,1)</BackgroundColor>
<DisplayName>Dynamic Tag Gallery Component Library</DisplayName>
<Description xsi:nil="true"></Description>
<CommitMessage xsi:nil="true"></CommitMessage>
<Publisher xsi:nil="true"></Publisher>
<AuthorizationReferences>[]</AuthorizationReferences>
<ConnectionReferences>{}</ConnectionReferences>
<DatabaseReferences>{}</DatabaseReferences>
<AppComponents>[{"appComponentName":"a77fca6af24446eb8638a6b9a78dc07e","displayName":"cptTagGallery","appName":"59dc2f33-903f-4b07-b50c-aaadec9bb9a1","appVersion":"2025-02-02T20:34:15Z","appComponentLibraryLogicalName":"crad7_dynamictaggallerycomponentlibrary_de9c6","appDisplayName":"Dynamic Tag Gallery Component Library","environmentName":"6ca51c28-f05d-ee87-8afd-29fcc9ef7fad","owner":{"id":"cd350c02-a2b3-4e79-aa4d-c8260894d466","displayName":"James Williams","type":"User","tenantId":"bd78dee9-9abf-4401-b6d6-e142688c4654","userPrincipalName":"james@wjwdev.onmicrosoft.com"},"allowCustomization":true,"createdOn":"2025-02-02T20:34:19.162Z","lastModifiedOn":"2025-02-02T20:34:19.162Z","connectionReferences":{},"databaseReferences":{}}]</AppComponents>
<AppComponentDependencies>[]</AppComponentDependencies>
<CanConsumeAppPass>0</CanConsumeAppPass>
<CanvasAppType>1</CanvasAppType>
<BypassConsent>0</BypassConsent>
<AdminControlBypassConsent>0</AdminControlBypassConsent>
<EmbeddedApp xsi:nil="true"></EmbeddedApp>
<IntroducedVersion>1.0</IntroducedVersion>
<CdsDependencies>{"cdsdependencies":[]}</CdsDependencies>
<IsCustomizable>1</IsCustomizable>
<BackgroundImageUri>/CanvasApps/crad7_dynamictaggallerycomponentlibrary_de9c6_BackgroundImageUri</BackgroundImageUri>
<DocumentUri>/CanvasApps/crad7_dynamictaggallerycomponentlibrary_de9c6_DocumentUri.msapp</DocumentUri>
<AdditionalUris>
<AdditionalUri>/CanvasApps/crad7_dynamictaggallerycomponentlibrary_de9c6_AdditionalUris0_identity.json</AdditionalUri>
</AdditionalUris>
</CanvasApp>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"__Version":"0.1","App":"924e520f-0486-4777-9cb2-45d7f6536c30","Test_7F478737223C4B69":"d93e89c5-a972-481f-b8a0-1828689cec0e","Host":"8ddf98ae-6e0e-4b82-b649-85cb0ed52810","Screen1":"b6023237-a598-4863-bd83-a32478a8f128","cptTagGallery":"f1283332-8a5e-43d6-afee-a55c5052fa68","VerticalContainer":"31ea1b05-64a0-43b2-90cd-0f2415bd9265","VerticalGallery":"ea952032-0109-480c-bb97-5c1bac430bda","galleryTemplate2_2":"2b3f3dcd-b982-4681-8abb-f923d5866871","ButtonCanvas":"54029025-f26f-4bf1-897c-4dc2903ebd1b"}
Binary file not shown.
Binary file not shown.
Loading