Thursday, July 9, 2026

Enhancing Model-Driven App Views with Custom Column Icons

Enhancing Model-Driven App Views with Custom Column Icons

A Hidden Feature That Can Make Your Views Much More User-Friendly

I came across a feature that I had never used before, even after working with Dynamics CRM and Power Platform for many years. While editing a column in a Dataverse view, I noticed two properties:

  • Web Resource
  • Function Name

At first, I thought Microsoft had introduced a new feature that allows custom rendering for individual view columns. After researching further, I learned that this capability has actually existed for quite some time, but it has remained somewhat hidden and underused.

Once I noticed it in the modern Power Apps maker experience, I decided to test it immediately. Within a few minutes, I was able to replace the standard Yes/No text in my Is Mandatory? column with custom icons.

The result was simple, but very effective. The view became much easier to scan visually.


What Is This Feature?

This feature allows a Dataverse view column to call a JavaScript function from a web resource. That JavaScript function can return an image web resource and tooltip text.

Dataverse then displays that image next to the column value in the view.

[
  "ImageWebResourceName",
  "Tooltip Text"
]

It is lightweight, simple, and useful for adding visual indicators to Model-driven App views.


A Simple Example

Normally, a view might display something like this:

Question Is Mandatory?
Check Pressure Yes
Enter PSI No
Verify Seal Yes

After configuring custom icons, the same view can display:

Question Is Mandatory?
Check Pressure ✅ Yes
Enter PSI ❌ No
Verify Seal ✅ Yes

The underlying data does not change. Only the visual representation changes.


How Does It Work?

The JavaScript function receives row data from Dataverse. Based on the value in that row, it returns the appropriate image web resource.

function showMandatoryIcon(rowData, userLCID) {

    var row = JSON.parse(rowData);

    var isMandatory =
        row.insp_ismandatory_Value ??
        row.insp_ismandatory;

    if (isMandatory === true || isMandatory === "true" ||
        isMandatory === 1 || isMandatory === "1") {

        return ["insp_yes", "Mandatory Question"];
    }

    return ["insp_no", "Optional Question"];
}

In this example:

  • insp_yes is the image web resource for Yes.
  • insp_no is the image web resource for No.
  • Mandatory Question and Optional Question are tooltip values.

Implementation Steps

Step 1: Create Image Web Resources

Create image web resources in your Dataverse solution.

insp_yes
insp_no

These can be SVG or PNG image web resources.

Step 2: Create a JavaScript Web Resource

Create a JavaScript web resource and add your function.

function showMandatoryIcon(rowData, userLCID) {
    try {
        var row = JSON.parse(rowData);

        var isMandatory =
            row.insp_ismandatory_Value ??
            row.insp_ismandatory;

        if (isMandatory === true || isMandatory === "true" ||
            isMandatory === 1 || isMandatory === "1") {

            return ["insp_yes", "Mandatory Question"];
        }

        return ["insp_no", "Optional Question"];
    }
    catch (e) {
        console.error("showMandatoryIcon failed:", e);
        return ["insp_no", "Icon error"];
    }
}

Step 3: Configure the View Column

Open the table view in the maker portal and select the column where you want the icon to appear.

In the column properties, configure:

Web Resource:
Your JavaScript web resource

Function Name:
showMandatoryIcon

Then save and publish your customizations.


Debugging Tip

One challenge is identifying the exact property name Dataverse passes into the JavaScript function.

To inspect the row data, temporarily add console logs:

function showMandatoryIcon(rowData, userLCID) {

    console.log("Raw rowData:", rowData);

    var row = JSON.parse(rowData);

    console.log("Parsed row object:", row);

    return ["insp_yes", "Test"];
}

Open browser developer tools using F12, go to the Console tab, and refresh the view. This will show the row object and available field names.


Practical Business Scenarios

This feature can be useful in many Model-driven App scenarios.

Inspection Status

  • 🟢 Completed
  • 🟡 In Progress
  • 🔴 Overdue

Pass / Fail

  • ✔ Pass
  • ✖ Fail

Priority

  • ⬇ Low
  • ➡ Medium
  • ⬆ High

Device Health

  • 🟢 Healthy
  • 🟠 Needs Service
  • 🔴 Out of Service

Approval Status

  • ⏳ Pending
  • ✔ Approved
  • ✖ Rejected

Question Types

  • ☑ Yes / No
  • 📝 Text
  • 📅 Date
  • 🔢 Number
  • 📋 Choice

Important Limitations

This is a very useful feature, but it is important to understand its limitations.

1. It Cannot Render HTML

You cannot return custom HTML, CSS, buttons, links, progress bars, or formatted text. The function only returns an image web resource and tooltip.

2. The Icon Is Not Clickable

The icon cannot open a dialog, execute JavaScript, navigate to another page, or trigger Power Automate. It is only a visual indicator.

3. It Does Not Work in Editable Grids

This feature is intended for read-only grids. If the view is using an editable grid, the custom icons will not display the same way.

4. No Cell Formatting

You cannot change the font color, background color, row color, alignment, padding, or row height.

5. No Interactive Controls

You cannot embed buttons, checkboxes, toggles, dropdowns, or input controls.

6. Images Must Be Web Resources

The image must already exist as a Dataverse image web resource. You cannot return external URLs, base64 images, or dynamically generated images.

7. Limited to One Image Per Column Cell

The function returns one image and one tooltip. It is not meant for displaying multiple icons inside a single cell.

8. Performance Matters

The JavaScript function runs once for every visible row in the view. Keep the logic lightweight and avoid expensive operations.

9. Not a Replacement for PCF

If you need rich UI features like badges, progress bars, charts, clickable buttons, custom layouts, or interactive components, a Power Apps Component Framework control is still the better option.


When Should You Use This Feature?

This feature is best used when you want to make a view easier to scan without building a full custom control.

Sometimes a small visual cue, like a green checkmark or red warning icon, communicates status faster than plain text.


My Thoughts

This is one of those small Dataverse features that can make a big difference in user experience.

It will not replace PCF controls, dashboards, or custom pages. But for lightweight visual indicators in Model-driven App views, it is extremely useful.


References

Wednesday, April 29, 2026

Stop Burning Power Automate Runs While Testing Loops

If you have ever built a serious Power Automate flow, not just a demo flow, but something actually used by the business, you have probably seen this problem.

You test your flow once, and suddenly it starts processing hundreds of records.

  • Your run history becomes messy
  • Debugging becomes painful
  • You waste time and flow runs
  • You may even trigger unnecessary emails or HTTP calls

I have learned this from real Power Platform projects. Now, when I am testing an Apply to each loop, I do not let it process the full dataset during development.


The Real Problem

In Power Automate, many actions return arrays, such as:

  • SharePoint Get items
  • Dataverse List rows
  • Select
  • Filter array

Most of the time, we plug the full output directly into an Apply to each loop.

outputs('Select')

That is fine for production, but it is not ideal while testing.


The Simple Fix

During testing, limit the loop input using the take() expression.

take(outputs('Select'), 5)

This tells Power Automate to process only the first 5 items from the array.

You are not changing the structure of the flow. You are simply controlling how much data the loop processes while you test.


Real Example from My Work

In one of my Power Automate flows for a Water outage notification process, the flow checks SharePoint list items, validates attachments, builds a webhook payload, sends an HTTP request, and handles failure emails.

That flow includes logic like:

  • Checking whether a .txt attachment exists
  • Validating outage counts
  • Sending data to an external webhook
  • Handling HTTP success and failure responses
  • Sending error emails only to the development team

Now imagine testing that logic against hundreds of records.

That is not controlled testing. That is noise.

By using:

take(outputs('Select'), 5)

I can test only a few records first, confirm the logic, and then remove the limit when I am ready for full testing or production.


Another Example: Case Management System

I have also worked on model-driven Power Apps and Dataverse-based projects where flows and backend logic interact with case records, person records, validation rules, and business processes.

In those kinds of systems, testing against too many Dataverse rows at once can make troubleshooting harder.

For Dataverse List rows, the same idea works:

take(body('List_rows')?['value'], 5)

This lets me test with a small number of records before running the logic across the full dataset.


Why This Is Useful

  • No premium connector required
  • No major flow redesign
  • No extra variable needed
  • Works with almost any array
  • Makes debugging much easier

My Personal Testing Rule

When I am building or debugging a flow, I usually follow this pattern:

  1. Build the flow normally
  2. Use take() to limit the loop during testing
  3. Validate the logic with a small number of records
  4. Remove the limit before production use

Important Reminder

Do not forget to remove or update the take() expression before moving to production, unless your actual business requirement is to process only a limited number of records.

This is mainly a development and testing technique.


Final Thought

Power Automate is not always the problem. Sometimes the way we test our flows makes development harder than it needs to be.

For me, using take() during loop testing is a small habit that saves time, keeps run history cleaner, and makes troubleshooting much easier.

If you are building serious Power Automate flows, do not test large loops blindly.

Control the loop first. Scale later.

Friday, March 13, 2026

Power Automate Optimization: Filter Rows vs Trigger Conditions - When and Why to Use Each

Filter Rows vs Trigger Conditions in Power Automate

Filter Rows vs Trigger Conditions in Power Automate

Why your flow might not even start

Recently in a Power Platform WhatsApp group, someone asked a very good question about created/modified trigger filtering in Power Automate.

“Isn't Power Automate being hit either way? You're just deciding whether to continue or not. So you aren't really reducing the number of Power Automate executions with that filter?”

This is actually a very common misunderstanding, even among experienced Power Platform developers.

My answer in the group was:

Trigger Conditions are evaluated server-side before the flow starts. The system decides whether the flow should execute or not.

Because this topic comes up frequently, I thought it would be useful to write a short blog explaining:

  • How Trigger Conditions actually work internally
  • How Filter Rows works
  • Why both help reduce unnecessary flow executions

The Misconception: “The flow runs anyway”

Many developers assume the following sequence happens:

Record Updated

Then

Power Automate flow is triggered

Then

A condition inside the flow is checked

Then

The flow stops if the condition is not met

If this were true, then yes, the flow would still count as an execution.

But this is not how Trigger Conditions work.

What Actually Happens Internally

When you configure a Trigger Condition, the evaluation happens before the flow instance is created.

Record Updated

Then

Power Automate trigger receives the event

Then

Trigger Condition is evaluated on the server side

Then

If the condition is True

Then

Flow instance is created

Then

Actions execute

If the condition evaluates to False:

Record Updated

Then

Trigger Condition is evaluated

Then

Condition is False

Then

Flow instance is not created

Meaning:

  • The flow never runs
  • No flow execution is created
  • No actions execute
  • No API calls are consumed
This behavior applies to most modern event-based triggers such as Dataverse and SharePoint.

Trigger Conditions vs Conditions Inside the Flow

Scenario 1 — Condition inside the Flow

Trigger: When a row is modified

Then

Condition inside the flow: State = Texas

Then

If Yes, send an email

Here is the problem.

Every update still starts the flow when you use a normal Condition action inside the flow. The check happens only after the flow has already begun.

Update Event Flow Runs
Customer name changed Yes
Phone number updated Yes
Notes updated Yes
State changed to Texas Yes

Even if the condition fails, the flow still ran.

  • Wasted flow runs
  • Extra API calls
  • Unnecessary system load

Scenario 2 — Using Trigger Conditions

Trigger: When a row is modified

Trigger Condition:
@equals(triggerOutputs()?['body/address1_stateorprovince'], 'Texas')

With Trigger Conditions, the check happens before the flow instance is created. If the condition is false, the flow does not start.

Update Event Trigger Condition Result Flow Runs
Customer name changed False No
Phone number updated False No
Notes updated False No
State changed to Texas True Yes

Now the flow starts only when the target business condition is met.

Where Trigger Conditions Are Configured

  1. Open your flow
  2. Click the Trigger
  3. Click Settings
  4. Add your expression under Trigger Conditions
@equals(triggerOutputs()?['body/address1_stateorprovince'], 'Texas')

Multiple trigger conditions can be added, and they act as AND conditions.

What About “Filter Rows”?

If you are using Dataverse triggers, you will also see Filter Rows.

address1_stateorprovince eq 'Texas'

Filter Rows uses OData query syntax.

Unlike Trigger Conditions, Filter Rows works even earlier in the process.

In Dataverse, Filter Rows is applied at the event subscription level, meaning only matching events are sent to Power Automate.

Example:

address1_stateorprovince eq 'Virginia'
Record Updated Flow Triggered
State = Florida No
State = Virginia Yes

This prevents non-matching events from even reaching the flow trigger.

Filter Rows vs Trigger Conditions

Feature Filter Rows Trigger Conditions
Evaluation level Dataverse event subscription Power Automate trigger engine
Syntax OData query Workflow expression
Capabilities Simple column filters Complex logic such as and, or, empty, and comparisons
Best use case Record filtering Business rule validation

Filter Rows runs first, then Trigger Conditions.

In practice, both must evaluate to true for the flow to start.

Using Both Together

The best design is often to use both features together.

Example:

Filter Rows:
address1_stateorprovince eq 'Virginia'

Trigger Condition:
@equals(triggerOutputs()?['body/accountcategorycode'], 1)

In this example:

  • Filter Rows first limits the event to records where the state is Virginia
  • Trigger Condition then checks whether the account category matches the business rule
  • The flow starts only if both conditions are satisfied

Best Enterprise Design Pattern

In high-volume Dataverse environments, the best trigger configuration usually looks like this:

Trigger

Then

Select Columns

Then

Filtering Columns

Then

Filter Rows

Then

Trigger Conditions
  • Select Columns reduces payload size
  • Filtering Columns ensures the flow triggers only when specific fields change
  • Filter Rows limits which records generate events
  • Trigger Conditions applies the final business rule before the flow starts

Real Enterprise Example

Imagine a customer table where you only want to notify a team when a record belongs to Virginia.

Poor design:

Trigger: When a row is modified

Then

Condition inside flow:
If State = Virginia

Then

Send notification

This runs every time the record is edited, even when the state is not Virginia.

Better design:

Filter Rows:
address1_stateorprovince eq 'Virginia'

And optionally:

Trigger Condition:
@not(empty(triggerOutputs()?['body/emailaddress1']))

Now the flow starts only when:

  • The updated record belongs to Virginia
  • The record has the business data needed for the next step

SharePoint Example

SharePoint does not offer Dataverse-style Filter Rows in the same trigger experience, but it does support Trigger Conditions.

Example:

@equals(triggerOutputs()?['body/State'], 'California')

This means the flow starts only when the SharePoint item has a State value of California.

Common Mistakes

Using Conditions inside the flow for basic filtering

Trigger

Then

Condition

Then

Exit

This wastes executions because the flow has already started.

Ignoring Trigger Conditions

Many developers simply do not realize this feature exists.

Putting complex logic in Filter Rows

Filter Rows supports OData syntax only. It is not the place for full workflow expressions.

Not using Filtering Columns

If the flow only cares about a few fields, configure the trigger to watch those fields instead of reacting to every update.

Performance Impact

Using Filter Rows and Trigger Conditions properly helps:

  • Reduce flow runs
  • Reduce API consumption
  • Improve performance
  • Prevent throttling
  • Improve maintainability

This becomes extremely important in enterprise environments where thousands of records may be updated daily.

Even when skipped triggers do not create real flow runs, very high event volumes can still affect throughput and responsiveness. Good trigger design still matters.

Final Takeaway

Coming back to the original WhatsApp question:

“Isn't Power Automate being hit either way?”

The answer is No.

Trigger Conditions are evaluated server-side before the flow instance is created.

If the condition evaluates to false, the flow never starts.

And if you are using Dataverse, Filter Rows can stop irrelevant events even earlier.

That is why Trigger Conditions and Filter Rows are critical optimization techniques when building scalable Power Automate solutions.


Tip: Before publishing, you may want to replace sample column names with the exact logical names from your own environment.

-- Warm Regards, Sudip Chakrovorty, M.S. Hand Ph.: +1-(614) 309-8282 (EDT)

Enhancing Model-Driven App Views with Custom Column Icons

Enhancing Model-Driven App Views with Custom Column Icons A Hidden Feature That Can Make Your Views Much More User-Friendly I came acro...