Multi-select person fields in SharePoint are quite common, but not straightforward to fill in using Power Automate when you have a variable number of people that could be added. In this post, I’m sharing a way that you can achieve this!
Identifying how to provide the data
To understand how this works, we first need to look at how SharePoint builds up a multi-select person field. For this, add a SharePoint “create item” action with a list that has a multi-select person field defined in it. (You can also use “update item” or “update file properties”) Then, where the multi-select person field is added, enter two dummy inputs by clicking “Add new item” below the first dropdown and providing some data. After entering the data, click the “T” icon in the top right corner of the field to switch to inputting the entire array, and there you’ll see the format of the array that is passed to SharePoint.
This is the format that we need to provide the data in: an array (in between the square brackets) with objects (in between the curly brockets) that specify the “Claims” field, containing an email-address in between double quotes.
Creating an array
The easiest way to create an array in Power Automate is working with an array variable, and the “Append to array” built-in action. So to start, at the beginning of the flow, initialize a variable of type array and provide it with a meaningful name – in my case “CollaboratorsArray” since I will be adding a group of collaborators in an item in a list. Don’t supply an initial value.
Adding the necessary data to the array
Depending on where you’re getting the input email-addresses from, these steps will differ slightly. The basic idea is that for each emailaddress you want to add into the array, you have an “Append to array variable” action that will add an additional object to the array. You can do this with separate actions after each other if you want to combine multiple inputs into one, or you can do this inside a loop to add a list of emails.
In my case, I’m getting the emailaddresses that I want to add from a comma-separated string as a manual input from the flow. Therefore, I will need an “Apply to each” loop and will need to split the input string to get to the list of emailaddresses.
I’m first adding the “Apply to each” action to the flow, and adding the split function as the collection that the loop should iterate over. Afterwards, I add the “Append to array variable” action inside the loop and building up the object that needs to be supplied. So the value of your append action should have the following format:
Providing the array to the SharePoint action
Now, all that’s left is to provide the array we built to the SharePoint action in the right location. To make this work, we should add the array into the right field in the “input entire array” option. This is the option where you don’t have the “Add new item” button.
The result will look like the image below. This will correctly fill the multi-select person field in SharePoint, and works when the number of people that are added can be different each time the flow is called!
A couple of months ago, I shared how you can create a button for navigation with an icon in a component and match its behavior to that of the “normal” buttons in canvas apps in this blog post. Back then, buttons created in this way could only be used for one specific action (in my case, navigating to another screen).
Since Power Apps added behavior properties to its canvas components, we can now extend this component solution so that a click on the button can trigger any function you want! Isn’t that cool? Let’s see how we can do this.
I’ll be starting from the button I created in that previous blog post. If you want to (re-)read that first, click this link.
⚠ If you’ve created the button component in a component library and are using it in applications, make sure that you make changes in a copy of the component, otherwise your other apps could stop working.
💡While this functionality is in preview, make sure to turn it on in the settings of your app or component library.
It’s quite easy to change the button so it can trigger any function when selected. Three steps is all it takes.
Step 1: Delete the “Screen” input property
Because we will change the component so it can trigger any function when selected, we don’t need the dedicated “Screen” property anymore. Therefore, we can simply delete it from the component. This will add an error to the component. Don’t worry about that for now, we’ll fix that in step 3.
Step 2: Add an “OnSelect” behavior property
Add a new custom property to the component and name it “OnSelect”. By choosing “OnSelect”, it will be straightforward for people familiar with canvas apps what they can expect this property to do. All controls that can be selected have this property defined, so it will be recognizable. The configuration is shown in the image below.
Delete the “Screen” input property from the component
Add an “OnSelect” behavior property to the component
Trigger the “OnSelect” of the component when clicking the top button inside the component
Step 3: Configure the component to trigger OnSelect
The final step is to make sure that when the top button inside our component is clicked, this triggers the OnSelect property of the component itself. This is done by referencing the component’s OnSelect property in the OnSelect property of the top button.
Select the top button in your screen or from the tree view in the app studio and choose the OnSelect property from the property dropdown.
You’ll see that the function in the OnSelect property is still referencing the Screen property we deleted in the first step. This is why we’re getting an error. Replace the function in the function bar to simply reference the component’s OnSelect property as follows:
As a result, the error has disappeared, and we can now invoke any function we want when clicking the button inside our app by configuring the OnSelect property after we’ve added the button component.
Bonus: this is just like the standard buttons canvas apps provides, which makes it an intuitive solution, and you can offer this component to be used by beginning Makers without much risk.
With this new functionality, we’re not limited to navigation anymore, we can use it to patch data to a data source, show or hide controls on our app, etc. The possibilities are endless!
At the beginning of a new year, I like to reflect on what the past year has brought to learn and plan for the upcoming year so that I can start it on my terms.
2020 was an eventful year, to say the least. I believe no one was expecting it or prepared for it, I know I wasn’t. Just like everyone else, I tried to make the best of it. And just like everyone else, I had my ups-and-downs. So what did 2020 look like?
2020 was definitely the year that I started to be more active in the community.
In the beginning of the year, I started this blog. Even though I did not blog as consistent as I initially planned, I’m proud of the blog posts that I did publish. More importantly, I’m excited to continue blogging! That really is the main outcome I was aiming for. As I wrote in my very first blog post, I had tried blogging before and had given up, which I didn’t want to happen this time around. Of course, the universe threw some curveballs and there are some gaps. Despite this, I’m here in the beginning of 2021 and still blogging. And I already have some ideas I’m working on!
Just like I started blogging, I started speaking at conferences this year as well. I was fortunate enough to get the opportunity to speak at 2 live events before I was confined to the comfort of my own home indefinitely. Special thanks to Power Platform Saturday Warsaw 🇵🇱 for being the first ever conference I got the chance to speak at! I had some more events lined up that were cancelled and of course several of the organizers decided to move the event online. This resulted in 5 speaking engagements in total. A good start, and I’m eager for more. I’ve already got 2 events lined up for the first 2 months of the year, let’s hope more are added. And dare I hope for an in-person event towards the end of the year?
The theme for 2020 was courage. Stepping out of my comfort zone, trying new things and daring to question myself and my beliefs.
On the one hand, I had a lot of time for introspection because I had nowhere else to be but home. On the other hand, I found that the lockdown took away a lot of my energy and motivation. As an introvert, this was surprising since I get energy from being alone. I believe the uncertainty of when things will go back to “normal” is the main reason my energy level was down. It’s still challenging sometimes, and something I’m working on by trying to find stability and certainty in myself, instead of outside factors. It’s a journey…
Possibly the biggest surprise of 2020 was that in April I started running. And when I say started, I mean started from zero. My first run I averaged 7’52” for one kilometre. I followed a “start to run” plan and after 10 weeks I could run 30 mins straight. I was so proud of myself! To this day, I’m still running 3 times per week, and am on my way to running 10k. I never thought I’d say these words: I’m a runner. If nothing else, 2020 has made me a runner.
I read 13 books in 2020. Most memorable are Daring Greatly by Brené Brown and Good Morning, Good Life by Amy Landino. During my summer vacation, I took a trip down memory lane and teenage/young-adult nostalgia and re-read the entire Twilight series. I’m currently reading Sapiens by Yuval Noah Harari, also a recommendation if you want to gain some perspective on what we as humans have done in the time we’ve been on this planet.
We spent 1 week in the summer and the week between Christmas and New Year’s painting the majority of the house. Only two rooms left: my home office (picking colors isn’t easy!) and the guest bathroom downstairs. We plan on tackling those last two sometime in the next year.
I’ve picked up a new hobby in the last month: knitting. Completed projects are a headband, a blanket for our dog to lie in front of the pellet stove, a hat for my sister-in-law (Christmas present) and for my boyfriend. Currently working on a sweater for the dog. I’ve been looking for something creative to do in my spare time and knitting is fitting that gap nicely currently. Time will tell if it’s a keeper.
2021 will come with its own set of challenges, opportunities and learnings. The theme for the year will be action. I spend too much time thinking (mostly doubting and second-guessing) and want to turn that into action. One of my guiding quotes is:
The only things you’ll regret in life are the things you didn’t do
I’ve started reading The Daily Stoic by Ryan Holiday. It’s a one-page-a-day book from which I want to get a daily piece of wisdom on the three principles of Stoïcism: control your perceptions, direct your actions properly and accept what is outside of your control. Three things that will help me in living according to my theme of the year.
On the professional side, I will continue to blog and speak at conferences (if they’ll have me 😊). Other than that, I’m working on something together with a community rockstar, that I hope we will be able to share with the rest of the community in the coming months. Stay tuned for that…
All that’s left is for me to wish you, from the bottom of my heart, a very happy and healthy 2021!
Galleries are one of the core components of Power Apps canvas apps, and there are many ways in which you can use them. Most often, they are used to show a list of information and give the user the option to click through to get even more information about the record or to take action.
In these cases, I’ve found it’s often difficult to decide what information to put in the gallery, and which to put in the detail screen. You need to balance the need for information with the screen estate and not having information overload. Therefore, it can be useful to show some basic information at first and giving the option to show some additional information by expanding the item before clicking through to the detail screen.
The result will look like this:
How can you create this? Let’s take a look…
Setting up the gallery
A gallery in which one item is expanded while the others are collapsed is in essence a gallery where different rows can have a different height. Therefore, you need to use a “flexible height gallery”. In other types of galleries, you cannot get to the same behaviour as you have in the example above.
Therefore, let’s start by adding a “Blank flexible height” gallery to the screen.
You can resize it so it fits your application. In my case it’s taking up the entire screen. Add the data source for the gallery and the controls that you need to show the information, including that which you only want to show when the item is expanded. You’ll notice that apart from the first row (which is the template cell), the height of all rows will adjust automatically when adding an extra control and moving it below ones that are already there. This is the main function of the flexible height gallery, and what we will use to create the expand/collapse effect: the height of each row adjusts to what is present in that row.
After adding the data, let’s add a down and up arrow icon to the gallery. They should be at the same X and Y coordinates, so they replace each other when collapsing/expanding. In my gallery, I’ve added a “more info” label and navigation icon as well so it’s clear when a user selects it, that they will go to another screen with more information. Also, I’ve added a line at the bottom of the gallery (which is a rectangle with tiny height) to indicate the different rows in the gallery.
Adding the collapse/expand functionality
What we want to achieve is that when a row is collapsed (which is default for the entire gallery), a user only sees the down arrow and can press it to show some additional information for this row (in my case the phone number and birthday).
When a row is expanded, the down arrow is replaced by the upwards arrow. This can be clicked by the user to collapse the row again and hide the additional information.
To make this functionality work, there are three things that need to be done:
When selecting the “down” arrow, update a local variable “locInfoExpanded” to “true” and when selecting the “up” arrow, update a local variable “locInfoExpanded” to “false”.
Set the “Visible” properties of the additional information, up and down arrow so they are visible at the right time
(only when you have a separator between gallery rows) Change the Y position of the separator so it moves down when the row is expanded and up when it is collapsed
In the “OnSelect” property of the down arrow icon, add the following code:
The “Visible” property of the additional information and the up arrow should be adapted to the following:
ThisItem.IsSelected && locInfoExpanded
Alternatively, that of the down arrow should be the opposite:
! (ThisItem.IsSelected && locInfoExpanded)
This ensures that the down arrow is shown for all rows that are not selected and for the selected one only if it is not expanded. If the arrows are placed at the same X and Y coordinates (and have the same height and width), it will seem as if they replace each other.
💡 Note: you can use just one icon control and dynamically change the displayed icon and executed functions as well by using if-clauses in the “Icon” and “OnSelect” property of the icon control.
Position of the separator
The position of the separator should change with the visibility of the additional information. More specifically: when the additional information is not visible, it should be placed right underneath the last visible item (in my case the address). When the row is expanded, the separator should be at the bottom (in my case right underneath the birthday.
To make it simple, I’m using the visibility of the birthday value label to determine where the separator should be placed instead of using the “Visible” formula.
The Y position of the separator should be set as follows:
In this blog post, which is the last in this series, I want to share an approach to input parameters that allows a lot of flexibility in the number and names of input variables: using JSON as input in the flow.
Instead of creating an input parameter for all of the inputs that I need in the flow, I’m going to create one input parameter of type text. This input parameter will contain a JSON object (passed as a string), which will have fields for each of the desired inputs. What does that look like?
First, I’m going to add an “Initialize variable” action immediately after the trigger in my flow. This will be a variable of type string with the name “Inputs”. Just as in my previous blog post, I’m renaming the action to the name of the variable and then adding the “Ask in PowerApps” dynamic content. This will create an input parameter for the flow called “Inputs_Value”.
This variable will be a JSON object. To get the contents of the JSON object, I’m adding a “Parse JSON” action after my variable initialization. The content to parse will be the variable that I created. I’m generating a schema by providing a sample JSON object that represents the input parameters I want to provide in my flow. Taking the same example variables as in the previous blog posts, this is the sample schema I’m adding into my flow:
"EmailSubject": "Subject of the email"
The schema is generated automatically. If I now add another action into the flow, my input parameters will be available as outputs of the parse action.
If I add this flow into a Power Apps canvas app, there is only one text input variable needed, as you can see below.
The good and the bad
As mentioned before, this approach provides a lot of flexibility. If I need to remove an input, I remove it from the schema and don’t provide it in my app anymore. It will not still linger and be an extra input that I need to provide a value for even though it isn’t used anymore.
Adding an input is also relatively easy: I change the schema by adding a field and provide the extra input as part of the JSON string created in the app. This will have no impact on the trigger (it still expects one input parameter), and will not require me to remove and re-add the flow input my app before it works.
The main downside of this method is that if someone else is building the app and they are not aware that the input string should be JSON or which fields are expected exactly, they will not be helped by the hint in Power Apps studio. You can’t provide the correct inputs without having knowledge of the flow, or it being clearly documented somewhere.
Next to flexibility, another advantage of this method is that the trigger is completely separated from the logic in the flow. (The same goes for the approach using variables for each of the inputs described in my previous post.) If you want to change the trigger of the flow to a different trigger (for example a manual trigger to be used as a run-only child flow with owner-provided connections), you don’t have to replace the input parameters everywhere in the logic of the flow. You only have to replace it once in the “Initialize variable” action. Every reference to that variable will remain intact, sparing a lot of work.
I believe this approach to input parameters provides a lot of flexibility that is currently missing for Power Apps triggered flows. Given good documentation, it can enable you to always have the right input variables available in your flow, without risks of breaking it or the app(s) it is used in when things change.
In my previous blog post, I explained how Power Apps trigger input parameter names are generated based on the name of the action and the field it is used in. Since there are some drawbacks to the variety of names that are created this way, I want to share a uniform approach that I often use when working with a fixed set of input variables that I know is highly unlikely to change in the future.
We know that an input parameter is generated using 2 parameters:
The name of the action it is generated in
The name of the field it is generated in
We can only control the first part, so to have a uniform naming, we should use one action that can generate different types of parameters within the same field. That action is “Initialize variable“. Using the “Type” field, you can differentiate between different types of parameters that can be passed by a Power Apps canvas app. The second part of the input parameter name will always be _Value (since this is the field that we generate the parameter in). You can then control the first part of your input parameter name by renaming the action before you generate the input parameter. That way, you have a uniform naming convention. Let’s take the same example parameters as in the previous blog post.
For the subject of the email and the title of the item we want to create, we can create a string parameter, for the ID we’ll use an integer. After adding three “Initialize variable” actions, filling in the name and type of the variable, we need to take two actions to create our input parameters for the flow:
Rename the “Initialize variable” action to the name of the variable
Add the “Ask in PowerApps” dynamic content in the initial value
The resulting input parameters will now have a name according to the following pattern: VariableName_Value. A uniform approach to input variables!
The good and the bad
The great thing about using this approach is that all your input variables will show up using the same pattern in your app. When adding this flow to a Power Apps canvas app it’s easy to know what is expected in each of the input parameters thanks to these names.
However, this is not a flexible solution. If tomorrow it is decided that the email is replaced by an approval, the input variable will still be called EmailSubject_Value. Or if the parameter is not used anymore in the flow, it will still be present and required as input parameter. When adding a new input parameter in your flow, you could have to remove and add the flow again in order to ensure that the changes on the trigger are picked up and your app doesn’t break.
When you’re using a Power Apps trigger in a Power Automate flow, the names of input parameters are generated automatically. Additionally, once you’ve created an input parameter, it’s impossible to rename it or even remove it when it’s not needed or used anymore.
In this series, I’m starting by explaining the pattern of the name that is generated for these input parameters. In the next blog posts, I’m looking at other ways of creating and generating these input parameters: a uniform approach and one that provides more flexibility afterwards.
How are input parameter names generated?
Power Automate input variables are automatically generated for the Power Apps trigger when you choose the “Ask in PowerApps” dynamic content in any of the actions in your flow. In the below example, I’m choosing this dynamic content in the “Id” field of the SharePoint “Get item” action.
This will create an input parameter with the name “Getitem_Id”. As you can see, the name that is being generated is the name of the action without the spaces, followed by an underscore and the name of the field in the action, also without spaces.
Some more examples below:
Sounds good, no?
There are a few things to consider. As soon as the input parameter is generated, it will be saved in your flow. If you remove it from the action, it will remain present in the trigger and therefore you’ll need to specify it when you’re calling this flow in a canvas app. If you rename the action, the input parameter will not be renamed.
Depending on whether you rename your actions or not, these names can also be too generic. Let’s say you have two “create item” actions in your flow. How will you differentiate between the input variables without looking at the flow each time? Or what about when you’re not sending an email in the flow anymore but switched to an approval and the variable is still called “Sendanemail(V2)_Subject”?
You can see why it could be a good idea to approach input parameters for Power Apps triggered flows in a different way. In the next two blog posts I’ll share two alternative approaches.
As you probably know, it’s very easy to customize the standard SharePoint form for a list or library using Power Apps. However, if you’re working with document sets it’s not as easy. Well, it’s just as easy to create the custom form. What’s currently not possible out of the box is to choose any document set content type using the content type field of the SharePoint form. In this post I share a solution using Power Automate that does allow you to create a document set from a Power Apps customized SharePoint form without using any code.
💡 We start with a document library in SharePoint that has a document set content type already added to it.
Solution: Power Automate
Create a new Instant flow in the default environment of your tenant. It has to be in the default environment since otherwise you won’t be able to add it into the customized form later on. Choose Power Apps as the trigger for the flow.
Add an Initialize variable action for all metadata that you need to create the document set. In my case that’s Name , Description, Status, Deadline and Size. Make sure to choose an appropriate type for the types of variables that you’re working with.
💡 I’m renaming my actions to the name of the variable so the input variables have a clear name when adding the flow to my canvas app later on.
Add Ask in PowerApps as dynamic content in each of the variables you’ve created so that they become input parameters for your flow.
The next steps is where the magic happens. I always think of document sets as “folders with metadata” and introduce them to customers as such. Also, if you sync libraries that have document sets in them using OneDrive sync, document sets show up as folders in your file explorer. This lead me to conclude that you can create a document set using two steps:
Create a folder in the library
Change the content type of the created folder to that of the document set
To create a folder, add the Create new folder action to your flow. Fill in the parameters for the library and choose the Name variable as folder name. Next, add an Update file properties action. Fill in the library parameters and in the Id, add the Id of the folder that was created in the previous step.
Now you’ll notice that the document set content type is not available in the Content type Id dropdown. To change the content type to that of the document set, we need to get the Id from SharePoint and add it as a custom value into the Update file properties action. To get the content type Id, open the library settings in SharePoint and select the document set content type (to do this, “allow management of content types” needs to be turned on). When you have the library content type open, the content type Id will be at the end of the url after “&ctype=” (indicated in yellow in the below image). Copy everything after the equals sign and paste that into the Content type Id field as a custom value.
Now you can add the other variables as inputs for the corresponding metadata fields. Finally, save the flow. The resulting flow should look similar to the below image. Now we can customize the SharePoint form.
Solution: Power Apps
Open the document library for which you want to customize the form. Then choose Customize forms from the Power Apps dropdown in the menu bar. Power Apps will initialize your form with only the Title field present (which we actually don’t need). Start by adding all other fields you want users to fill to the form, leave the Title field in there as well. We’ll customize it to show the Name field instead.
Unlock the Title data card from the advanced properties and add Name into the DataField property of the data card. Change the label text to Name.
Now we need to make sure that the form behaves correctly both when creating and when editing the properties of the document set. Therefore, we need to make 3 additional changes.
1. Change the “OnSave” property of the SharePointIntegration
In the OnSave property of the SharePointIntegration, we need to make sure that the creation flow is called when creating a new document set. Since I have not created an edit flow I want to simply submit the form when editing the document set properties. If you have created an edit flow, make sure to add it into the second part of the formula.
To add the flow into the form, temporarily add a button control to the app and add your flow using the Action menu. (It cannot be added directly into the OnSave property.) After the flow has been added, you can delete the button and add the following formula into the OnSave property of the SharePointIntegration control. (Note that the name of the form in the below formula will be different if you renamed it in the Power App)
SharePointForm1.Mode = FormMode.New,
// FormMode.New: Run the flow and reset the form
YourFlowName.Run(InputProperty1, InputProperty2, ...);
// FormMode.Edit: Submit the form
In my case, the OnSave property looks as follows:
2. Change the OnReset property of the SharePoint form control to RequestHide().
3. Change the DisplayMode property of the Title/Name data card value
When submitting an edit form, the customized form does not make any changes to the Name of the document set. Therefore, to avoid confusion with users wanting to change the name of the document set, I want to make sure that in edit mode the Name data card is not editable.
Add the following formula into the Name text input control’s DisplayMode property:
The customized form is ready to be used and will work both when creating a new document set and when editing the properties of an existing one.
An important drawback of this approach is that saving the form when creating a new document set will not trigger a refresh of the SharePoint page. Users will have to do a manual refresh to see their newly created document set. Depending on the number of actions in your flow before creating the document set, the creation might take some time and the document set will not immediately show up.
If you’re working with multiple document set content types, you have to resolve the guid of the selected content type in order to create a document set with the right one. In this case, I have hardcoded the content type guid into my flow. It’s also possible to get the guid using a SharePoint HTTP call and resolving the required one based on the name. However, this takes some additional manipulations and would have led too far for this blog post.
In one of my current projects, we’re working on a canvas app where user experience is an essential part of the project. We teamed up with a designer to make sure that the app fits into the company’s styling guidelines and that the UI was as intuitive and attractive as possible. One of the elements present in the resulting design is a button with an icon on it in addition to the label.
In the standard button control, it’s not possible to add an icon. If we just added the icon on top of the button, the colors will differ when hovering over the button or the icon which is not ideal for user experience. Since we didn’t want to create a custom component with code to add the possibility of an icon, I created a button component using only standard controls.
The resulting button will look and behave like this:
Keep reading for the steps to create this button!
Buttons can be used for many different things in an app: submit a form, navigate to another screen, apply a filter to a gallery, etc. Typically, when a button is pressed, an action needs to happen. Since canvas components currently don’t support specifying actions as their inputs or outputs, we are limited in what we can do with a button component. In this project’s requirements, the buttons would be used to navigate to a different screen.
Creating the component
💡 It’s not required to create the button as a component, but I prefer to do this to have less controls in my actual app later on.
You can create the component in any canvas app you have or in a dedicated component library. After creating the component, I’m renaming it to btnNavWithIcon so it’s easily identifiable when I want to use it in my app. I’m also changing the height and width to a commonly used button shape and size.
I am then adding the four controls I need to create the button: the background button (btnBottom), a label (lblNavButton), a random icon (icnNavButton) and the top button (btnTop). The reason I’m adding two buttons is to make sure that the top button (which will be transparent) and background (which will have a color) will be exactly the same shape. At this point, it doesn’t matter where they are placed inside the screen since that will all be determined dynamically. What is important is that the top button control is in front so that that can actually be selected when the component is used in an app. We can see which control is at the front of the component in the Tree view (higher position in the tree = higher layer in the app/component).
I’m defining three custom input properties for my control:
Label (text): the label that will be visible in the final button
Icon (text): the icon that will be used
Screen (screen): the screen to navigate to when the button is pressed
The next thing to do is link these input properties to the controls in our component, remove the labels from the button controls and disable the bottom button.
Set the “Text” property of lblNavButton to btnNavWithIcon.Label
Set the ‘Icon” property of icnNavButton to btnNavWithIcon.Icon
Set the “OnSelect” property of btnTop to Navigate(btnNavWithIcon.Screen, ScreenTransition.None)
Set the “DisplayMode” property of btnBottom to DisplayMode.View
Set the “Text” property of btnTop and btnBottom to “”
Let’s complete the basic functionality and styling of the button as well.
Set the size of btnTop to the size of the component
Set the “X” and “Y” properties of btnTop to 0
Set “Height”, “Width”, “X” and “Y” of btnBottom to the corresponding properties of btnTop
Resize and position the icon and label so they fit nicely inside the component
Set “Fill” of btnTop to Transparent
Set “HoverFill” of btnTop to RGBA(255,255,255,0.1) – This is 90% transparent white, meaning the color behind it will be about 10% lighter
Set “PressedFill” of btnTop to RGBA(0,0,0,0.1) – This is 90% transparent black, meaning the color behind it will be about 10% darker
The last 3 properties will make it appear that the icon and label are part of one button, since their color will change together with the background color (the fill color of the bottom button).
The button will look like this:
💡 You can test the component by setting the input properties you defined using the formula bar. In this case, I’ve set “Icon” to Icon.Settings (without quotation marks) and “Label” to “Settings”.
Styling the button
To determine the styling of the button, there are plenty of options. You can fix colors, position and size of the icon and label inside the button, you can make their position and size dynamic based on the height and width of your component, or you can specify additional input properties so that whoever will use your component has control over it.
In my case, I’m choosing a dynamic styling based on user inputs. This means I need to add a couple more input properties for the location and size of my controls: IconLocation, IconSize and FontSize. I’m also adding two color input properties: ButtonFill and TextColor. For the IconLocation and IconSize, I’m specifying the possible values in the description: Top, Bottom, Left and Right for location and Small, Medium and Large for size.
To apply the styling on the controls, we first need to decide what we want the styling to be. Colors is easy, they will be defined when someone adds the control to their app. Apply the below settings to btnBottom, icnNavButton and lblNavButton.text
But what does “Top” or “Left” mean? And what size is “Large” compared to “Small”? I’m using the following definition:
If the position of the icon is “Top” or “Bottom”, the label and icon will be centered inside the component
Horizontal margins are 10% of the width of the control, vertical will be 10% of the height of the component
“Small” means the icon’s height and width is 30% of the minimum of height and width of the component, “Medium” 50% and “Large” 70%
Default position is “Left” and size “Medium”
Let’s break this down for the “X” property of the icon.
If the position of the icon is “Top” or “Bottom”, the center of the icon should be in the center of the button. Using the below image, we can work out what that means in terms of known properties.
If the position of the icon is left the margin compared to the left side of the button should be 10% of the width of the button. This translated directly to the X-coordinate of the icon.
If the position of the icon is right, the margin compared to the right side of the button should be 10% of the width of the button. We can again use an image to figure out what this means in terms of known properties.
Bringing these three together, we get the following formula for the X-coordinate of the icon.
By not specifying “Left”, this will act as the default location of the icon and will also work if no or an incorrect value is specified.
Using similar reasoning and the styling rules defined, the remaining position and size properties of the icon and label can be specified.
That’s it! The button component is now ready to be used!
We can easily test the resulting component by changing the input properties using the formula bar. Changing height, width and icon position could yield the result in the following animation.
We have successfully created a button component with a label and an icon with a couple of styling options to make it flexible. If we add this button to an app and specify the “Screen” property we can navigate to that screen by pressing the button. In the below animation I have created a simple test app with 3 screens and some buttons to navigate between them.
I hope this helps in creating your own custom button component with an icon. Good luck!
These days, more and more of us are staying home and going digital for work, pleasure and connecting with friends and families in order to #flattenthecurve. COVID-19 has spread across the globe and is impacting our lives in significant ways. The digital world that we have at our finger tips offers many advantages: it keeps us up to date, entertained, connected and allows us to work from home.
And yet, it also means we run the risk of losing track of our personal well-being. Digital connection is not the same as real-life connection. Working from home constantly makes it easy to forget where work ends and free time starts. I can only imagine what it’s like to throw children in the mix. There are a lot of tips out there on how to manage the working part in WFH when you’re not used to it, but I’d like to touch on everything else.
How do we stay sane and take care of ourselves in all this?
I’m a firm believer and supporter of the flexibility that working from home provides. You can choose more freely when you start and end the working day. There’s no commute that you need to take into account. You’ll find yourself to be more productive because there are no co-workers to distract you (there might be others asking for your attention, but that’s another issue). This is great if you’re working from home a couple of days a week and you can use the extra time to get some difficult work done. However, when you’re WFH full-time, it can easily turn into working all day, everyday. That’s not healthy.
To prevent this, decide a schedule for yourself and stick to it. Determine when you’ll start in the morning, take a proper lunch break and clock out in the afternoon/evening. Put it on the agenda, set a reminder in your phone, ask the other people in your house to come and remind you, teach your dog/cat/other animal to grab your attention when an alarm starts playing. Do whatever it takes, as long as you don’t end up spending every waking minute with work. Getting away from it and doing something else will mean you have a clearer mind when you pick it up the next day, or after the weekend. Yes, weekends still exist, and you should take them.
This may not be an easy one, depending on your living situation.
If you have a garden or can still go on the street, take a walk. If you have other living beings in the house, maybe even play a game. Throw a ball around, play hide and seek, run after your dog/cat/other animal. And a little rain will not hurt you, or who are you trying to save that hairdo for? 😉 With spring around the corner, you could possibly get some work done in the backyard. Remove the weeds, mow the lawn for the first time, replant some potted plants etc. Or just sit on the patio with your preferred drink and enjoy the sun and fresh air.
If you live in an apartment and you’re not allowed to go on the street anymore, it’s more difficult. But not impossible, you can still get fresh air. Go out on the balcony if you have one. If you don’t, open a window and stick your head out. Take a couple of deep breaths and let your eyes wander. If the weather’s nice, you can even open all the windows and air out your apartment. Fresh air and a bit of sunlight can do wonders to our mind, body and spirit.
Move your body
First things first, I’m not an athletic person by any means. I mean, I’m short of breath after two flights of stairs. And yet I mean it when I say that you should move your body. You might be surprised by the amount of movement we miss out on when we’re at home 24/7. Not walking to the car, public transport, the office, cafeteria, bathroom, that colleague on the other side of the building or site, your favorite coffee shop or lunch spot etc. That’s a lot of walking you’re not doing. You should make up for that.
There are different ways to move your body. You can take a walk if you can still go on the street or in your garden (see tip #2). Any stairs around? Go up and down them a couple of times. You can turn to YouTube for free workout videos, there are different options depending on your physique. From yoga to HIIT, there’s something for everyone. Chase your pets or kids if they like it. Turn on some music and have a dance party. And if you have significant other with you… I don’t need to spell that out, do I? Just move your body, whichever way you prefer. 😉
Get away from the screen
Just as your mind needs rest, your eyes need rest too. It’s easy when you clock out of work to browse the internet and fall down a Twitter, Instagram, YouTube or other social media rabbit hole. Try to avoid this. And yes, TVs and smartphones are screens to. Turn to something else. Read a real, paper book if you have one. Do something creative like drawing, painting or other arts and crafts. Play a board game with the family. Clean the house, one room every day (bonus tip to move your body!) or that oven, bathroom cabinet or other place that is in desperate need of a cleaning. Reorganize a space or closet. Make a jigsaw puzzle. There is so much you can do away from the screen, experiment and maybe you’ll find yourself a new hobby or rekindle an old one.
Get enough sleep
You may have thought “awesome, I don’t need to get up early because I don’t have to commute to and from work!”. Yes and no. If you have a one-way commute of an hour or more, definitely take that extra time to sleep a bit later. Just don’t use it as an excuse to stay up an hour later in the evening and binge-watch Netflix (or play another round of the board game you’re playing). Just as it is important to set and stick to a schedule for work, it’s important to maintain a healthy life schedule as well, and that includes getting enough sleep.
Decide when you want to get up and set your alarm. I highly recommend not straying too far from your normal wake up time so it’s easier to slip back in to your normal routine when the time comes. Once you know what time you want to get up and how many hours of sleep you need (on average it’s 8 hours, but you might need more or less), you know by what time you need to be in bed. Make it happen. You’ll thank yourself in the morning (or the next evening when you don’t have to work 2 hours longer than planned because you couldn’t get out of bed).
These tips are common sense and absolutely also valid in a time without COVID-19, but when you’re working from home it can be easy to forget. Consider this as your friendly reminder that you also need to take care of yourself. Don’t forget the personal aspect while we’re going digital even more than before. Stay at home to stay healthy physically and use these tips to stay healthy mentally.