Microsoft Power Apps (Canvas + Model-Driven) — Complete Guide
Canvas vs Model-Driven · Formulas · Delegation · Business Rules · BPF · ALM · Scenarios · Cheat Sheet
Table of Contents
- Canvas vs Model-Driven — Core Differences
- Canvas Apps — Deep Dive
- Power Fx Formulas & Delegation
- Model-Driven Apps — Deep Dive
- Integration, Performance & ALM
- Scenario-Based Questions
- Cheat Sheet — Quick Reference
1. Canvas vs Model-Driven — Core Differences
What is the fundamental difference between Canvas and Model-Driven apps?
Canvas apps: maker-designed pixel-perfect UI. You drag-and-drop controls onto a blank canvas and connect to any data source. Full control over layout, navigation, and UX. Think of it like building a PowerPoint with logic and data.
Model-Driven apps: UI is auto-generated from the Dataverse data model. You define the data (tables, columns, relationships, forms, views) and the app renders itself. Consistent, accessible, and responsive UI out of the box — but less visual customisation.
Key distinction: Canvas = UI-first (you design the screen). Model-Driven = data-first (the data model drives the UI).
When would you choose Canvas over Model-Driven and vice versa?
Choose Canvas when:
- Custom, branded, pixel-perfect UI is required
- Data comes from multiple sources (SharePoint + SQL + API in one screen)
- Mobile-first field worker apps with offline support
- Simple task apps: inspections, checklists, data capture forms
- Non-Dataverse data sources are primary (Excel, SharePoint lists)
Choose Model-Driven when:
- Complex Dataverse data model with many related tables
- Business process flows, rules, and complex relationships required
- Standard enterprise UI (forms, views, dashboards) is acceptable
- Dynamics 365 customisation or extension
- Role-based access using Dataverse security roles is critical
What data sources does Canvas support vs Model-Driven?
Canvas apps: 400+ connectors — SharePoint, Excel, SQL Server, Dataverse, REST APIs, Salesforce, SAP, Teams, OneDrive, Azure Blob, and many more. A single canvas app can connect to multiple different data sources simultaneously.
Model-Driven apps: exclusively Dataverse. All data must be in Dataverse tables. Virtual tables can surface external data inside Dataverse, but the app layer itself only reads from Dataverse.
Warning: This is one of the most-tested distinctions. Model-Driven = Dataverse only. Canvas = anything.
What is a Power Apps Component Framework (PCF) control?
PCF controls are custom UI components built with TypeScript/React that can be used in both Canvas and Model-Driven apps. They extend the built-in control library with custom visualisations or input controls not available natively.
| PCF Type | Description | Example |
|---|---|---|
| Field-type | Replaces a standard column control | Rich text editor replacing a plain text field |
| Dataset-type | Replaces a view/grid | Custom Gantt chart instead of a standard grid |
PCF controls are packaged in solutions and deployed via Power Platform CLI: pac pcf push.
What is the difference between a Canvas app and a Model-Driven app in terms of licensing?
Both require a Power Apps licence. However:
- Canvas apps connecting to premium connectors (Dataverse, SQL, HTTP) require a Power Apps Premium licence per user
- Model-Driven apps always require Power Apps Premium (since they exclusively use Dataverse)
- Apps using only standard connectors (SharePoint, Teams, Excel) can use a Microsoft 365 licence (included)
2. Canvas Apps — Deep Dive
What are the key controls in Canvas apps?
| Control | Purpose |
|---|---|
| Gallery | Scrollable list/grid of records from a data source |
| EditForm | Create or edit a single record with auto-generated fields |
| DisplayForm | Read-only view of a single record |
| Data table | Tabular read-only grid view of a collection |
| Dropdown / ComboBox | Selection controls (ComboBox supports multi-select + search) |
| Text input | Single or multi-line text entry |
| Button | Triggers OnSelect formula on tap/click |
| Label | Displays text — bound to data field or formula result |
| Camera | Captures photos — returns image for storage |
| Pen input | Captures signatures or drawings |
| Timer | Fires events after a duration — useful for auto-refresh |
| Toggle | Boolean input — true/false |
How does a Gallery control work and how do you connect it to a data source?
Set the Gallery's Items property to a data source or collection. Each template in the gallery repeats for every record. Use ThisItem inside the gallery template to reference the current record's fields.
Gallery.Items = Accounts ← entire table
Gallery.Items = Filter(Accounts, Status = "Active")
Gallery.Items = Search(Accounts, SearchBox.Text, "Name")
Gallery.Items = Sort(Accounts, CreatedOn, Descending)
Gallery.Items = SortByColumns(
Filter(Accounts, Status = StatusFilter.Selected.Value),
"Name", Ascending)
Inside gallery template:
Label.Text = ThisItem.Name
Label.Text = ThisItem.'Account Number'
Image.Image = ThisItem.Logo
Label.Color = If(ThisItem.Status = "Overdue", Color.Red, Color.Black)
How do EditForm and SubmitForm work in Canvas apps?
EditForm: bound to a data source. Displays fields for creating or editing a record. Set Item property to the selected record for editing; leave empty for new record creation.
SubmitForm: called in a Button's OnSelect to save the form data back to the data source. Triggers OnSuccess or OnFailure.
Button.OnSelect =
If(MyForm.Valid,
SubmitForm(MyForm),
Notify("Please fill all required fields", NotificationType.Error)
)
MyForm.OnSuccess =
Navigate(HomeScreen, ScreenTransition.Fade);
Notify("Saved successfully", NotificationType.Success)
MyForm.OnFailure =
Notify("Save failed: " & MyForm.Error.Message, NotificationType.Error)
New record mode:
NewForm(MyForm) ← reset form to blank
ResetForm(MyForm) ← discard changes
EditForm(MyForm) ← switch to edit mode
What are Collections in Canvas apps and how do they differ from data sources?
A Collection is an in-memory table stored locally in the app session. It is not persisted to any external data source — it exists only while the app is running.
ClearCollect(MyCol, Filter(Accounts, Active=true)) ← populate from source
Collect(MyCol, {Name:"New", Status:"Active"}) ← add a record
Remove(MyCol, ThisItem) ← remove a record
Clear(MyCol) ← empty the collection
Patch(MyCol, First(Filter(MyCol, ID=1)), {Name:"Updated"}) ← update a record
RemoveIf(MyCol, Status = "Inactive") ← remove matching records
Use Collections to: cache data to reduce repeated data source calls, store user selections across screens, build a "shopping cart" pattern (stage multiple changes before a single save), and work offline.
What is offline capability in Canvas apps and how do you implement it?
Canvas apps can work offline by caching data locally using SaveData and LoadData functions, combined with the Connection.Connected signal.
App.OnStart:
If(Connection.Connected,
ClearCollect(LocalOrders, Orders);
SaveData(LocalOrders, "OrdersCache"),
LoadData(LocalOrders, "OrdersCache", true)
)
Submit button OnSelect:
If(Connection.Connected,
Patch(Orders, Defaults(Orders), NewOrderForm),
Collect(PendingSync, NewOrderForm);
SaveData(PendingSync, "PendingSync")
)
Monitor Connection.Connected to auto-sync when reconnected:
Timer.OnTimerEnd =
If(Connection.Connected && CountRows(PendingSync) > 0,
ForAll(PendingSync, Patch(Orders, Defaults(Orders), ThisRecord));
Clear(PendingSync);
SaveData(PendingSync, "PendingSync")
)
Warning:
SaveData/LoadDataonly works in the Power Apps mobile app — not in browsers. Offline mode must be tested with airplane mode on the device.
What is the Navigate function and what transitions are available?
Navigate(Screen, Transition, {context}) moves to another screen. The optional context passes data to the destination screen as screen context variables.
Navigate(DetailScreen, ScreenTransition.Fade)
Navigate(DetailScreen, ScreenTransition.Cover)
Navigate(DetailScreen, None, {SelectedID: Gallery.Selected.ID, Mode: "Edit"})
On destination screen — read context variables directly:
Label.Text = SelectedID
EditForm.DefaultMode = If(Mode = "Edit", FormMode.Edit, FormMode.View)
Go back:
Back()
Navigate(HomeScreen, ScreenTransition.UnCover)
Available transitions: None, Fade, Cover, CoverRight, UnCover, UnCoverRight
3. Power Fx Formulas & Delegation
What is delegation in Power Apps and why does it matter?
Delegation is the ability of Power Apps to pass a data operation (filter, sort, search) to the data source for server-side processing, rather than downloading all records to the app and processing locally.
Delegable: the server filters/sorts and returns only matching records — scales to millions of rows.
Not delegable: Power Apps downloads up to the Data row limit (default 500, max 2000) and processes locally. Records beyond the limit are silently ignored — you get wrong results without any error.
| Delegable (Dataverse) | Not Delegable |
|---|---|
Filter(Table, Status="Active") |
Filter(Table, Left(Name,3)="Acc") |
Search(Table, text, "Name") |
Filter(Table, IsBlank(Field)) |
Sort(Table, CreatedOn) |
CountIf with complex expressions |
Filter on indexed columns |
String manipulation functions |
Critical: The delegation warning (blue underline) in Power Apps Studio is one of the most important signals to watch. Silent data truncation is the #1 cause of apps returning incorrect results in production.
How do you work around delegation limitations?
- Use delegable columns: apply non-delegable operations only on small, pre-filtered collections — not directly on large tables
- ClearCollect into a collection first: use a delegable
Filterto fetch a manageable set, then apply non-delegable operations locally - Add a calculated column in Dataverse: move complex logic server-side so the filter column itself is simple and delegable
- Use a Power Automate flow: complex server-side queries via FetchXML or OData, return results to the app
- Increase row limit to 2000: a stopgap, not a real solution for large datasets
What is the Patch function and how does it work?
Patch creates or updates one or more records in a data source without using a Form control. It gives direct programmatic control over what gets saved.
Create a new record:
Patch(Accounts, Defaults(Accounts),
{Name: "Contoso", Status: "Active", Revenue: 50000})
Update an existing record:
Patch(Accounts, LookUp(Accounts, ID = varID),
{Status: "Inactive", ModifiedNote: "Closed by user"})
Update the currently selected gallery item:
Patch(Accounts, Gallery1.Selected,
{Status: StatusDropdown.Selected.Value})
Batch update using ForAll:
ForAll(MyCollection,
Patch(Accounts, LookUp(Accounts, ID = ThisRecord.ID),
{Status: "Processed"}))
Tip: Patch is preferred over SubmitForm when you need to save specific fields programmatically, update multiple records, or save without a Form control visible on screen.
What is the difference between Filter, LookUp, and Search?
Filter(Table, condition)
→ Returns a TABLE of all matching records
→ Use for Gallery.Items, collections
→ Filter(Accounts, Status="Active" && Revenue > 10000)
LookUp(Table, condition)
→ Returns a single RECORD (first match)
→ Use when you need one specific record
→ LookUp(Accounts, ID = varSelectedID)
Search(Table, searchText, "col1", "col2")
→ Returns a TABLE of records where searchText appears in any listed column
→ Delegable for Dataverse and SharePoint
→ Search(Accounts, SearchBox.Text, "Name", "AccountNumber")
Combined pattern for gallery with search + filter:
Gallery.Items = Search(
Filter(Accounts, Status = StatusFilter.Selected.Value),
SearchBox.Text, "Name"
)
What are variables in Power Apps — global vs context vs collections?
Global variables (Set):
→ Available on ALL screens
→ Use for user identity, app-wide state, toggle flags
Set(varUserName, User().FullName)
Set(varIsAdmin, varUserName = "Admin User")
Context variables (UpdateContext):
→ Available only on the CURRENT screen
→ Use for screen-level state: selected item, dialog visibility, form mode
UpdateContext({varSelectedID: Gallery.Selected.ID})
UpdateContext({varShowDialog: true, varMode: "Edit"})
Collections (ClearCollect / Collect):
→ In-memory TABLE — multiple records
→ Use for lists, caches, multi-select, staged data
ClearCollect(CartItems, {Product: "A", Qty: 1})
rule:
Set= global single value.UpdateContext= screen-local single value.ClearCollect= in-memory table. Confusing these is a common mistake.
What is Concurrent() and when should you use it?
Concurrent() executes multiple formulas simultaneously in parallel rather than sequentially. It dramatically reduces app loading time when multiple independent data source calls are needed on startup.
Without Concurrent (sequential — slow):
App.OnStart:
ClearCollect(Accounts, Accounts); ← waits 2s
ClearCollect(Contacts, Contacts); ← then waits 1.5s
ClearCollect(Products, Products) ← then waits 1s
Total: ~4.5 seconds
With Concurrent (parallel — fast):
App.OnStart:
Concurrent(
ClearCollect(Accounts, Accounts),
ClearCollect(Contacts, Contacts),
ClearCollect(Products, Products)
)
Total: ~2 seconds (slowest single call)
Tip: Using
ConcurrentonApp.OnStartfor multiple data loads is a standard performance best practice look for.
What are Named Formulas (App.Formulas) and why are they useful?
Named Formulas are reusable expressions defined once in App.Formulas and referenced anywhere in the app by name. Unlike variables, they are recalculated lazily (only when needed) and are always current.
App.Formulas:
ActiveAccounts = Filter(Accounts, Status = "Active");
CurrentUserEmail = User().Email;
IsAdmin = "Admin" in currentUserRoles;
Usage anywhere in the app:
Gallery.Items = ActiveAccounts
Label.Text = CurrentUserEmail
Button.Visible = IsAdmin
Advantage over variables: Named Formulas don't need initialisation and auto-update when underlying data changes. No
Set()orUpdateContext()needed.
4. Model-Driven Apps — Deep Dive
What are the key components of a Model-Driven app?
| Component | Description |
|---|---|
| Tables (entities) | Dataverse tables forming the data model |
| Forms | Define how a single record is displayed/edited |
| Views | Define how a list of records is displayed |
| Dashboards | Charts and lists of records |
| Business Process Flows | Guided stage-based process overlay on forms |
| Sitemap | Navigation structure — areas, groups, sub-areas |
| Command bar | Ribbon buttons on forms and views |
| Business rules | Declarative logic rules on forms or server-side |
| Charts | Visual representations of view data |
What are the types of Forms in Model-Driven apps?
| Form Type | Description | Use Case |
|---|---|---|
| Main | Primary full-page form for viewing/editing a record | Default form on record open |
| Quick Create | Lightweight side-panel form for fast record creation | Create without leaving current page |
| Quick View | Embedded read-only view of a related record | Show Account details inside Contact |
| Card | Compact display for dashboards | Interactive dashboards |
Tip: Multiple Main forms can exist for the same table — control which users see which form using Security Roles assigned to the form.
What are Business Rules in Model-Driven apps and what can they do?
Business Rules are declarative logic rules configured without code. They can execute client-side (form only) or server-side (all saves including API calls).
What business rules can do:
- Show or hide fields based on conditions
- Enable or disable (lock) fields
- Set field values
- Set field requirement level (required / not required / recommended)
- Show validation error messages
Critical distinction: Business rules with scope "Entity" run server-side on every save — even via API or Power Automate. Business rules with scope "Form" only run in the browser form.
What is a Business Process Flow (BPF) and how does it work?
A Business Process Flow is a guided workflow overlaid on a Model-Driven app form. It shows a progress bar of stages at the top — users move through stages sequentially. Each stage can require specific fields before advancing.
Key properties:
- Can span multiple Dataverse tables (e.g., Lead → Opportunity → Quote)
- Each stage has steps (fields the user must fill)
- Can branch based on conditions
- BPF instances are stored as Dataverse records — queryable and reportable
- Multiple BPFs can be active on the same table — user picks the process
What is JavaScript in Model-Driven apps and what are its common uses?
JavaScript web resources are attached to form events (OnLoad, OnSave, OnChange) to extend form behaviour beyond Business Rules.
Common uses:
- Complex field show/hide/enable logic beyond Business Rule capability
- Auto-populating fields from related records via the Xrm API
- Client-side validation with custom error messages
- Calling external APIs from the form
- Programmatically opening dialogs or navigating to records
function onLoad(executionContext) {
var formContext = executionContext.getFormContext();
var status = formContext.getAttribute("statuscode").getValue();
if (status === 2) {
formContext.getControl("cr123_reason").setVisible(true);
formContext.getAttribute("cr123_reason").setRequiredLevel("required");
}
}
function onStatusChange(executionContext) {
var formContext = executionContext.getFormContext();
var amount = formContext.getAttribute("totalamount").getValue();
if (amount > 10000) {
formContext.ui.setFormNotification(
"This order requires director approval.",
"WARNING", "high_value_warning");
}
}
What is the Dataverse security model in Model-Driven apps?
Model-Driven apps use Dataverse's built-in security model:
| Security Layer | Description |
|---|---|
| Security roles | CRUD privileges on each table at org/BU/team/user scope |
| Business units | Organisational hierarchy that partitions data |
| Teams | Group users to share roles and record ownership |
| Field-level security | Restrict read/write on individual columns |
| Record sharing | Share individual records beyond role-based access |
Scope hierarchy: Organisation > Business Unit > Parent/Child BU > User. Each scope progressively restricts which records a user can access.
What are Views in Model-Driven apps and what types exist?
Views define how lists of records are displayed — columns shown, default filters, sort order.
| View Type | Description |
|---|---|
| Public views | Visible to all users with table access |
| System views | Built-in views (e.g., "Active Accounts", "My Activities") — not deletable |
| Personal views | Created by individual users for their own use |
| Quick Find view | Defines which columns are searched when using the search box |
| Lookup view | Shown in lookup fields when selecting a related record |
5. Integration, Performance & ALM
How do you call a Power Automate flow from a Canvas app?
Use the Power Automate panel in Power Apps Studio to add an Instant flow. The flow must use the "Power Apps V2" trigger.
Button.OnSelect =
Set(varResult, MyFlow.Run(TextInput.Text, Gallery.Selected.ID));
Notify(varResult.message, NotificationType.Success)
In Power Automate:
- Trigger: "When Power Apps calls a flow (V2)"
- Define inputs: text, number, boolean, date parameters
- Add flow logic
- "Respond to Power Apps" step → define output variables
- Output available as
varResult.outputnamein the app
Tip: Power Apps V2 trigger supports typed inputs. Prefer V2 over the legacy V1 trigger for all new flows.
What are the key Canvas app performance best practices?
- Use
Concurrent()on App.OnStart to load multiple data sources in parallel - Avoid OnStart overload — only load immediately-needed data; lazy-load the rest on screen navigation
- Use delegable queries — never load entire large tables into collections
- Limit Gallery items — use
Filterbefore binding toGallery.Items, not after - Cache static data — load lookup tables once into collections, don't query on every screen visit
- Avoid nested galleries — a gallery inside a gallery causes N×M data calls
- Use Named Formulas (App.Formulas) — define reusable calculated values evaluated lazily
- Minimise controls per screen — more controls = slower render
- Enable "Delayed load" in app settings — defers loading of non-visible screens
- Use Monitor tool — record and analyse app startup to find slow calls
How do you package and deploy Power Apps across environments?
Power Apps are packaged in Power Platform solutions for ALM.
Steps:
- Add the app to a solution in the maker portal
- Include all dependencies: flows, connection references, environment variables, Dataverse tables/columns
- Export as managed (for prod) or unmanaged (for dev)
- Import into target environment via admin centre or CLI
- Configure connection references and environment variable values post-import
pac solution export --path ./sol.zip --name MyAppSolution --managed
pac solution import --path ./sol.zip
Warning: Canvas app connections are not included in solutions — Connection References must be configured per environment after import.
What are Canvas app components and component libraries?
Canvas components are reusable UI building blocks within a single app — like a custom control with its own properties, inputs, and outputs.
Component libraries are shared libraries of components that can be used across multiple apps. Changes propagate to all apps that use them (with a manual update step).
Component custom properties:
Input property → data passed into the component
Output property → data/events passed out of the component
Example header component:
Input: Title (text), ShowBackButton (boolean)
Output: OnBackPressed (behaviour/event)
Usage in app:
HeaderComponent.Title = "My Page"
HeaderComponent.ShowBackButton = true
Tip: Component libraries are the Power Apps equivalent of a shared UI design system. Enterprise apps should centralise headers, navigation, and common controls in a component library.
How do you use the Monitor tool for Canvas app debugging?
The Monitor tool (Power Apps Studio → Advanced tools → Monitor) provides a real-time stream of app events — data calls, formula evaluations, control events, and errors.
Key uses:
- See which data source calls are slowest on startup
- Debug formula errors with full context
- See exactly what data is returned from each connector call
- Trace navigation and screen load events
- Identify delegation warnings materialising at runtime
6. Scenario-Based Questions
Scenario: Canvas app is slow to load. Walk through your optimisation approach.
Situation: App takes 8–12 seconds to open before users can interact.
- Open Monitor tool — record app startup and identify which data calls are slowest
- Check
App.OnStart— is it loading too much? Move non-critical loads to individual screenOnVisibleinstead - Wrap independent data loads in
Concurrent()to parallelise them - Replace large table loads with targeted
Filterqueries — neverClearCollect(Col, FullTable)on a large table - Check for delegation warnings — non-delegable queries on large tables silently download only 500 rows
- Enable "Delayed load" in app settings — defers loading of non-visible screens
- Reduce the number of controls on the first visible screen — more controls = more render work on startup
- Check if any flows are being called on startup — move them to on-demand triggers
Scenario: Design a Canvas app for field engineers to capture inspection data offline.
Requirements: Engineers work in areas with no internet. They capture inspection forms, photos, and signatures. Data syncs when connectivity returns.
Architecture:
- App.OnStart: check
Connection.Connected- Online:
ClearCollect(InspectionTemplates, Templates)thenSaveData(InspectionTemplates, "templates") - Offline:
LoadData(InspectionTemplates, "templates", true)
- Online:
- Inspection form: bind to a local
PendingInspectionscollection — not directly to Dataverse - Photos:
Cameracontrol — store image in collection as base64 - Signature:
Pen inputcontrol — save as image - Submit:
Collect(PendingInspections, formData); SaveData(PendingInspections, "pending") - Sync on reconnect: Timer monitors
Connection.Connectedchange →ForAll(PendingInspections, Patch(Inspections, Defaults(Inspections), ThisRecord))→Clear(PendingInspections); SaveData(PendingInspections, "pending") - Status badge:
Label.Text = CountRows(PendingInspections) & " pending sync"
Warning: Test offline mode by turning on airplane mode before opening the app. Offline only works in the Power Apps mobile app, not the browser.
Scenario: A Model-Driven app needs different forms for different user roles.
Requirement: Sales reps see a simplified Account form. Managers see the full form with financials. Admins see all fields.
- Create three separate Main forms for the Account table: "Sales Rep Form", "Manager Form", "Admin Form"
- On each form, include/exclude the relevant sections and columns
- In each form's properties → Form order and security roles: assign the appropriate security role to each form
- Set form order — the system shows the highest-order form for which the user has a matching security role
- Test by switching to each security role in the app
Tip: If a user has multiple roles and multiple forms match, form order determines which is shown. Order forms from most-specific role to least-specific.
Scenario: How do you implement a master-detail pattern in a Canvas app?
Pattern: Left panel shows a list of Orders. Right panel shows the selected Order's line items.
Single screen master-detail:
Left Gallery (Orders):
Items = Filter(Orders, Status = StatusFilter.Selected.Value)
OnSelect = Set(varSelectedOrder, ThisItem)
Right Gallery (Order Lines):
Items = Filter(OrderLines, OrderID = varSelectedOrder.ID)
Header on right panel:
Label.Text = varSelectedOrder.OrderNumber
Label.Text = "Total: " & Text(varSelectedOrder.Total, "[$-en-US]$#,##0.00")
Navigation-based master-detail (separate screens):
Left gallery OnSelect:
Navigate(DetailScreen, None, {PassedOrder: ThisItem})
On DetailScreen:
Label.Text = PassedOrder.OrderNumber
Gallery.Items = Filter(OrderLines, OrderID = PassedOrder.ID)
EditForm.Item = PassedOrder
Scenario: How do you prevent users from submitting a form with duplicate records?
Requirement: Prevent duplicate Account records by checking if an account with the same name already exists before saving.
Submit button OnSelect:
If(
CountRows(Filter(Accounts, Name = AccountNameInput.Text)) > 0,
Notify("An account with this name already exists.", NotificationType.Warning),
SubmitForm(AccountForm);
Notify("Account created successfully.", NotificationType.Success)
)
For Model-Driven apps: use a Business Rule or a Dataverse duplicate detection rule (configured in Settings → Data Management → Duplicate Detection Rules) — server-side enforcement is more reliable.
Scenario: How do you implement role-based navigation in a Canvas app?
Requirement: Admins see all screens. Standard users see only their relevant screens. Navigation menu adapts dynamically.
App.OnStart:
Set(varUserEmail, User().Email);
ClearCollect(UserRoles,
Filter(AppUsers, Email = varUserEmail)
);
Set(varIsAdmin, CountRows(Filter(UserRoles, Role = "Admin")) > 0)
Navigation gallery Items:
Filter(
NavItems,
(RequiresAdmin = false) || (RequiresAdmin = true && varIsAdmin)
)
Screen Visible property (hide admin-only screens from URL):
varIsAdmin
Button OnSelect (guard):
If(varIsAdmin,
Navigate(AdminScreen),
Notify("Access denied", NotificationType.Error)
)
7. Cheat Sheet — Quick Reference
Canvas App Formulas at a Glance
Data retrieval:
Filter(Table, condition) → table subset
Search(Table, text, "col1","col2") → text search result
LookUp(Table, condition) → single record
Sort(Table, column, Ascending) → sorted table
SortByColumns(Table, "col", Ascending) → sorted table
Data modification:
Patch(Source, record, {field:value}) → create/update
Remove(Source, record) → delete record
RemoveIf(Source, condition) → delete matching
SubmitForm(FormName) → save form
NewForm(FormName) → reset to blank
Collections:
ClearCollect(Col, source) → replace collection
Collect(Col, record) → add to collection
Remove(Col, record) → remove from collection
Clear(Col) → empty collection
UpdateIf(Col, condition, {field:val}) → update matching rows
Variables:
Set(varName, value) → global variable
UpdateContext({varName: value}) → screen variable
Navigation:
Navigate(Screen, Transition)
Navigate(Screen, None, {ctx: value})
Back()
Notifications:
Notify("message", NotificationType.Success)
Notify("message", NotificationType.Error)
Notify("message", NotificationType.Warning)
Power Fx — Commonly Tested Functions
| Function | Description | Example |
|---|---|---|
Concat |
Join collection values into string | Concat(Items, Name & ", ") |
CountRows |
Count records in collection | CountRows(Filter(Orders, Status="Open")) |
CountIf |
Count matching records | CountIf(Orders, Amount > 1000) |
Sum |
Sum a column | Sum(Orders, Amount) |
Max / Min |
Highest/lowest value | Max(Orders, Amount) |
Average |
Average of a column | Average(Orders, Amount) |
Distinct |
Unique values from column | Distinct(Orders, Status) |
AddColumns |
Add calculated column to table | AddColumns(Orders, "Tax", Amount * 0.2) |
IsBlank |
Check null/empty | If(IsBlank(Email.Text), ...) |
IsEmpty |
Check empty collection | If(IsEmpty(CartItems), ...) |
Coalesce |
First non-blank value | Coalesce(varName, "default") |
Text |
Format number/date as string | Text(Today(), "dd/mm/yyyy") |
Value |
Convert string to number | Value(PriceInput.Text) |
DateAdd |
Add days to date | DateAdd(Today(), 7, Days) |
DateDiff |
Difference between dates | DateDiff(StartDate, Today(), Days) |
Delegation Quick Reference
| Data Source | Delegable Functions |
|---|---|
| Dataverse | Filter, Search, Sort, SortByColumns, LookUp, CountRows, Sum, Min, Max, Average |
| SharePoint | Filter (most columns), Search, Sort, SortByColumns |
| SQL Server | Filter, Search, Sort, SortByColumns |
| Excel / CSV | NOT delegable — all processing is local, 2000 row max |
Always non-delegable: Left(), Mid(), Right(), IsBlank(), IsEmpty(), StartsWith() in filter conditions, Len() comparisons
Model-Driven App Component Summary
Form types:
Main form → full record view/edit (role-controlled)
Quick Create → lightweight side-panel creation
Quick View → embedded related record (read-only)
Card form → compact dashboard display
View types:
Public view → visible to all users
System view → built-in, cannot be deleted
Personal view → user-created, private
Quick Find view → defines search columns
Lookup view → shown in lookup field dialogs
Business Rule scope:
Form scope → runs in browser form only
Entity scope → runs on all saves (including API/flow)
BPF:
Stages → guided steps with required fields
Branches → conditional routing between stages
Cross-table → can span multiple Dataverse tables
ALM Deployment Checklist
Pre-export:
☐ App fully tested in dev environment
☐ All flows, connection references in solution
☐ Environment variables defined (not values)
☐ Dataverse tables/columns in solution
☐ PCF controls included if used
☐ Component libraries included if used
Export:
☐ Managed solution for UAT/prod
☐ Unmanaged for dev
Post-import:
☐ Configure connection references
☐ Set environment variable values
☐ Share app with users/groups
☐ Assign security roles (Model-Driven)
☐ Test all screens and flows
☐ Publish canvas app
Top 10 Tips
- Canvas = UI-first, Model-Driven = data-first — state this clearly when asked to compare. It anchors every other answer.
- Delegation is the most-tested Canvas topic. Know which functions are delegable, what happens when they're not (silent 500-row limit), and the three main workarounds.
SetvsUpdateContextvsClearCollect— global vs screen vs table scope. This trips up many candidates.Concurrent()on App.OnStart is the #1 performance answer. Mention it proactively in any performance question.- SubmitForm vs Patch — SubmitForm requires a Form control; Patch works anywhere programmatically. Know when to use each.
- Business Rule scope (Form vs Entity) — Entity scope runs server-side on ALL saves including API calls. This distinction separates mid-level from senior candidates.
- Connection References are mandatory for ALM. Hardcoded connections break on solution import.
- BPF can span multiple tables — Lead → Opportunity → Quote is the classic example. Many candidates don't know this.
- PCF controls work in BOTH Canvas and Model-Driven. Know the two types (field and dataset).
- Offline capability requires
SaveData/LoadData+Connection.Connected+ mobile app deployment. Know all three requirements.
No comments:
Post a Comment