PowerGrid

lowcodera PowerGrid Component

Purpose

Packed with features and customization options, the lowcodera PowerGrid takes presenting, interacting and editing your tabular data in Power Apps to a new level.

Binding Data

You can bind data to the PowerGrid using the items property. Simply select your data source like you would with any out of the box control like the Gallery or Data Grid.

PowerGrid Properties

Columns Dataset

The items property allows you to bind the grid to your data source and render it. In addition to this, there is some advanced functionality available in the PowerGrid which is unlocked through using the columns dataset property which is defined in JSON. Key attributes for our column dataset schema are documented below

Example Schema

Table(
    {
        fieldName:"ID",
        displayName:"ID",
        isKey:true        
    },
    {
        fieldName:"Title",
        displayName:"Work Order"        
    },
    {
        fieldName:"District",
        displayName:"District"
    },
    {
        fieldName:"Service",
        displayName:"Service"        
    },
    {
        fieldName:"LeadTech",
        displayName:"LeadTech"                
    },    
    {
        fieldName:"WorkDate",
        displayName:"Work Date",                
        dataType:"date",//datatype for the value eg. string,number
        dataFormat:"DD-MMM-YYYY" //Custom date format         
    },
    {
        fieldName:"Payment",
        displayName:"Payment",
        dataType:"choices",
        choices:ForAll([
            {
                key:"COD",
                value:"C.O.D."
            },
            {
                key:"account",
                value:"Account"
            }
        ], {Value: ThisRecord})  
    },
    {
        fieldName:"LbrHrs",
        displayName:"Labor Hours",
        dataType:"number",        
        dataFormat:"{{value:d1}}"// data format mechanism to format the number value eg. 100.0
    },
    {
        fieldName:"Techs",
        displayName:"Techs",       
        dataType:"number",
        conditionalFormat: //Display background-color of the value based on two or more conditions 
        ForAll([
            {
                condition: "value == 1",
                ifTrue: {backgroundColor: "red"}                
            },
            {            
                condition: "value == 2",
                ifTrue: {backgroundColor: "blue"}                
            },
            {
                condition: "value == 3",
                ifTrue: {backgroundColor: "green"}                
            }
        ], {Value: ThisRecord})      
    },
    {
        fieldName:"TotalPayable",
        displayName:"Total Cost",
        dataType:"number",
        dataFormat:"{{value:d2}}",//Set the data format of the value eg. 100.25
        dataAlign: "right"//Set the alignment of the value eg. left,center,right        
    }
)

Saving Data

There are two approaches for saving data back to your data source- using the dataset API or by patching records via the OnChange Event. The Dataset API is simpler to use, however it is a new feature from Microsoft and there are some limitations which means it is not suitable for all situations.

Using the Dataset API

To use this method for saving data, make sure the “Use Dataset API” property is set to true and the Hide Toolbar property is set to false.

As users make changes to column values, the toolbar will show a count of unsaved row changes. Users need to press the save button in the toolbar to commit changes back to the underlying data source.

Saving via the OnChange Event

Before using this method:

  1. Set the IsKey attribute to true for whichever the unique ID column is in your Columns Dataset.

  2. Set the “Use Dataset API” property to false

  3. Set the “Hide Toolbar” property to true.

This method requires PowerFX to be inserted into the OnChange event of the PowerGrid. There are 3 sections to the PowerFX code which are documented in the example code snippet below.

  • Generating a collection of changed rows

  • Generating a collection of changed values from the changed rows

  • Patching the changed values back to the data source

See below for an example code snippet for saving data via the OnChange Event:

// 1.  Parsing changed rows into a collection
Clear(updatedRowsCol);
Clear(updatedItemsCol);

ForAll(
    Split(Self.onUpdatedItems,"</Row>"),
    Collect(updatedRowsCol,Result)
);

// 2. Parsing the ID, ColumnName and new value for each changed row

ForAll(
    updatedRowsCol,
    Collect(
        updatedItemsCol,
        {
            id: First(Split(ThisRecord.Value,"</>")).Result,
            fieldName: First(LastN(Split(ThisRecord.Value,"</>"),2)).Result,
            value: Last(LastN(Split(ThisRecord.Value,"</>"),2)).Result
        }
    )
);

// 3. Save the final data - Patch Updates

ForAll(
    updatedItemsCol As UpdatedItems,
    Switch(
        UpdatedItems.fieldName,
        "field_LeadTech",
        Patch(
            colWorkOrders,
            LookUp(
                colWorkOrders,
                ID = Value(UpdatedItems.id)
            ),
            {LeadTech: UpdatedItems.value}
        ),
        "field_ReqDate",
        Patch(
            colWorkOrders,
            LookUp(
                colWorkOrders,
                ID = Value(UpdatedItems.id)
            ),
            {
                ReqDate: DateValue(
                    UpdatedItems.value,
                    "en-GB"
                )
            }
        ),
        "field_Service",
        Patch(
            colWorkOrders,
            LookUp(
                colWorkOrders,
                ID = Value(UpdatedItems.id)
            ),
            {Service: UpdatedItems.value}
        ),
        "field_District",
        Patch(
            colWorkOrders,
            LookUp(
                colWorkOrders,
                ID = Value(UpdatedItems.id)
            ),
            {District: UpdatedItems.value}
        ),
        "field_LbrHrs",
        Patch(
            colWorkOrders,
            LookUp(
                colWorkOrders,
                ID = Value(UpdatedItems.id)
            ),
            {LbrHrs: Value(UpdatedItems.value)}
        )
    )
);

Copy and Pasting Data

The grid supports copying and pasting data into it from data sources like Excel. The Ctrl + V keyboard shortcut will need to be used to perform the paste operation.

When data is pasted into the grid, there is a pastedData EventType which is exposed. This should be used in the OnChange event to process the pasted data. The pasted data is held in the onUpdatedItems output property, as per when any data is updated in the grid.

You will need to handle the two scenarios of when data is pasted into existing records and when pasted data is creating new rows. When the pasted data is creating a new row on the grid, the id attribute for that row of onUpdatedItems will be set to "NEW_ROW".

See the example PowerFx code below for how the OnChnage event of the grid can be used to process regular updates to the grid as well as from Copy and Paste operations.#

    Clear(updatedRowsCol);
    Clear(updatedItemsCol);

If(
    Self.onEventType = "pastedData",

// 1.  Parsing pasted rows into a collection
ForAll(
        Split(
            Self.onUpdatedItems,
            "</Row>"
        ),
        Collect(
            updatedRowsCol,
            Result
        )
    );
    
// 2. Parsing the ID, ColumnName and new value for each pasted row
ForAll(
        updatedRowsCol,
        Collect(
            updatedItemsCol,
            {
                id: First(
                    Split(
                        ThisRecord.Value,
                        "</>"
                    )
                ).Result,
                fieldName: First(
                    LastN(
                        Split(
                            ThisRecord.Value,
                            "</>"
                        ),
                        2
                    )
                ).Result,
                value: Last(
                    LastN(
                        Split(
                            ThisRecord.Value,
                            "</>"
                        ),
                        2
                    )
                ).Result
            }
        )
    );
    
// Patch any new records from the paste operation. New rows hav an id value of NEW_ROW
ForAll(
        Filter(
            updatedItemsCol,
            id = "NEW_ROW"
        ) As UpdatedItems,
        Switch(
            UpdatedItems.fieldName,
            "Payment",
            Patch(
                colltestData,
                Defaults(colltestData),
                {Payment: UpdatedItems.value}
            ),
            "Title",
            Patch(
                colltestData,
                Defaults(colltestData),
                {Title: UpdatedItems.value}
            ),
            "JoinDate",
            Patch(
                colltestData,
                Defaults(colltestData),
                {JoinDate: DateValue(UpdatedItems.value)}
            )
        )
    );
    
//Patch Updates for pasted rows which already exist
ForAll(
        updatedItemsCol As UpdatedItems,
        Switch(
            UpdatedItems.fieldName,
            "Payment",
            Patch(
                colltestData,
                LookUp(
                    colltestData,
                    ID = Value(UpdatedItems.id)
                ),
                {Payment: UpdatedItems.value}
            ),
            "Title",
            Patch(
                colltestData,
                LookUp(
                    colltestData,
                    ID = Value(UpdatedItems.id)
                ),
                {Title: UpdatedItems.value}
            ),
            "JoinDate",
            Patch(
                colltestData,
                LookUp(
                    colltestData,
                    ID = Value(UpdatedItems.id)
                ),
                {JoinDate: DateValue(UpdatedItems.value)}
            )
        )
    ),
    
//Handle regular updates to rows

    
// 1.  Parsing chnaged rows into a collection
ForAll(
        Split(
            Self.onUpdatedItems,
            "</Row>"
        ),
        Collect(
            updatedRowsCol,
            Result
        )
    );
    
// 2. Parsing the ID, ColumnName and new value for updated row
ForAll(
        updatedRowsCol,
        Collect(
            updatedItemsCol,
            {
                id: First(
                    Split(
                        ThisRecord.Value,
                        "</>"
                    )
                ).Result,
                fieldName: First(
                    LastN(
                        Split(
                            ThisRecord.Value,
                            "</>"
                        ),
                        2
                    )
                ).Result,
                value: Last(
                    LastN(
                        Split(
                            ThisRecord.Value,
                            "</>"
                        ),
                        2
                    )
                ).Result
            }
        )
    );
    
    
//Patch Updates for chnaged rows
ForAll(
        updatedItemsCol As UpdatedItems,
        Switch(
            UpdatedItems.fieldName,
            "Payment",
            Patch(
                colltestData,
                LookUp(
                    colltestData,
                    ID = Value(UpdatedItems.id)
                ),
                {Payment: UpdatedItems.value}
            ),
            "Title",
            Patch(
                colltestData,
                LookUp(
                    colltestData,
                    ID = Value(UpdatedItems.id)
                ),
                {Title: UpdatedItems.value}
            ),
            "JoinDate",
            Patch(
                colltestData,
                LookUp(
                    colltestData,
                    ID = Value(UpdatedItems.id)
                ),
                {JoinDate: DateValue(UpdatedItems.value)}
            )
        )
    )
);

Conditional Formatting

The columns schema can be used to define cell based rules for conditional formatting. The example code snippet below shows how the background color of a cell can conditionally be defined

    {
        fieldName:"AccountStatus",
        displayName:"Account Status",
        dataType:"number",
        conditionalFormat: ForAll([
            {
                condition: "value == 1",
                ifTrue: {backgroundColor: "red"}                
            },
            {            
                condition: "value == 2",
                ifTrue: {backgroundColor: "blue"}                
            },
            {
                condition: "value == 3",
                ifTrue: {backgroundColor: "green"}                
            }
        ] ,{Value: ThisRecord})   
    }

Supported operators

Relational operators

  • >

  • <

  • >=

  • <=

  • ===

  • <> or !== or !=

Logical operators

  • && or And

  • || or Or

  • ! or Not

  • ‘value’ or ‘x’ is used for the content in the cell

  • Schema for conditional formatting JSON (conditionalFormat in column definition of the grid)

When there are overlapping regions then the later style takes the precedence

Any CSS attributes can be used inside the ‘ifTrue’ and ‘ifFalse’. Also use camelCase for the CSS attributes.

Data Formatting

Cell values can be formatted in the PowerGrid by specifying the appropriate expression in DataFormat attribute of the JSON column schema.

Decimal places

Use the expression below, where the number after d denotes the number of decimal places. The example below formats the numbers to 2 decimal places. dataFormat: "{{value:d2}}"

Thousand separators

A thousand separator can be specified by extending the decimal formatting expression with “:t”. The example below formats the numbes to 0 decimal places, with a thousand separator

dataFormat: "{{value:d2:t}}"

Prefixes

Values can also be prefixed into the expression e.g. Currency Symbol. The example below formats the number to 0 decimal places, with a thousand separator and a £ currency symbol

dataFormat: "£{{value:d2:t}}"

Dates

When the DataType is Date, various data formatting expressions can be used to format the date.

dataFormat:"DD-MM-YYYY"

Action Buttons

Action buttons allow you to define in-line interactive buttons within the grid. You can have one or more buttons per row and style each one independently. Importantly, you can also assign an event to a button and define PowerFx expressions to trigger when the user clicks on it.

Adding buttons

Action buttons can be defined in the Column Schema by setting the DataType attribute for a column to be “actionButton”

Sample button definition
        fieldName: "button_column1",
        visible: true,
        displayName: "",
        editable: false,
        dataType: "actionButton",
        actionButtonProps: [
            {
                event: "viewProfile",
                id: "viewProfile",
                variant: "Outline",
                tooltip: "View Profile",
                name: "view",
                disabled: false,
                icon: "eye",
                fontColor: "green",
                backgroundColor: "transparent",
                borderColor: "transparent",
                width: 30,
                height: 30,
                fontSize: 12,
                borderRadius: 10,
                margin: 0
            }
        ]

Action button attributes

Handling user interaction

When a user clicks on an action button the PowerGrid onEventType property outputs the name of the event, as defined in the column definition. The actionButtonRowId output property also returns the id of the row the user has interacted with.

To handle the interaction, follow these steps:

  1. Make sure you have defined a unique name for the action button in the event attribute

  2. In the OnChange of the PowerGrid, add a PowerFx expression for when the onEventType is equal to the name of your event.

  3. Use the actionButtonRowId output to perform your action against the appropriate row in your data source

  4. See below for example, where the event has been called viewProfile

Switch(
    Self.onEventType,
    "viewProfile",
    Set(
        VarPlayerProfileID,
        Self.actionButtonRowId
    );
    Navigate('Player Profile')
)

Setting Predefined Filters

The PowerGrid supports scenarios where you need the grid prefiltered. To enable this simply populate the Set Filter input property with the appropriate JSON expression.

To save you having to manually generate the JSON for the filter query, the easiest way of setting a predefined filter is to first of all apply the filter condition(s) to the grid as an end user. Then copy the string generated in the output property filter and paste this into the set filter input property

Example filter
{
  "Nationality": {
    "filterType": "multi",
    "filterModels": [
      null,
      {
        "values": [
          "Argentina",
          "Austria",
          "Belgium"
        ],
        "filterType": "set"
      }
    ]
  }
}

Using Pre-set Grouping

It's possible to have predefined column grouping on the grid. To enable this follow thee steps

  1. Turn on the Use Custom Grouping property in the grid (set to true)

  2. In the column schema, for each column you want to group by, set the rowGroupIndex attribute. This should be a number from 0 onwards for each column which will be grouped. See example below.

{
    fieldName: "name",
    displayName: "name", 
},
{
    fieldName: "country",
    displayName: "category",
    rowGroupIndex: 0
},
{
    fieldName: "Language",
    displayName: "Language",
    rowGroupIndex: 1
}

Limitations/Known issues

  • Saving decimal data is currently not supported by the new dataset API

  • Saving data to SQL data source is currently not supported the new dataset API

  • Under certain scenarios, changes on the grid are not reflected in real-time even though they are saved to the data source

Last updated