top of page
Cilate logo.png
  • Writer's pictureArill André Aam

How to Pre-Populate 'To Recipient' Field with Selected Records' Contacts in a Model-Driven App?

Updated: Apr 30

User Story: As a user of a custom model-driven app, I want to be able to send emails to selected records in a list view (custom table with a lookup column to Contact).


Demo of end result.


This weekend I had the honour of fighting what seemed to be a simple PowerFx custom command for several hours before ultimately turning to javascript to find a good workaround. Hence, I now share some of these findings, as creating an email draft with selected records' contacts pre-selected in the 'To Recipient' list is quite a common use case for model-driven apps.


Initially, this is what I tried to do using PowerFx:

A simple Navigate with Patch to pre-populate the recipient list with selected records' Contacts and the subject "Hello world". However, no matter how I tried to tweak the PowerFx, it always resulted in a blank 'To Recipient' field upon navigation. So, why isn't it working?


Background insights:

The 'To Recipients' fields are polymorphic lookup fields where one can select records from multiple tables, including Contacts, Accounts, or Users. For those of us who have worked with Power Automate flows and the standard Activity tables, we know that we often have to specify which table we are populating records from using the 'Activity Party Attribute' fields. Example below:

However, for instance, we can set regarding fields on a normal Patch operation, as the metadata is included. Thus, Dataverse "understands" which table the record is coming from (e.g., the Contacts table or the Accounts table, depending on which record we patch).


But after trying to use the same principles as for Power Automate to populate the fields using PowerFx, I eventually gave up. Instead, I started working with JavaScript after finding a related post on Stack Overflow (link at the bottom of the article).


Anyhow, here is the workaround for different scenarios of prepopulating an email draft on navigate.


Scenario 1: Populating a single selected Contact from a list view (based on the Contacts table)


function openEmail(FirstSelectedItemId) {
    console.log("FirstSelectedItemId:", FirstSelectedItemId); // Log the value of FirstSelectedItemId to the console

    // Use Xrm.WebApi.retrieveRecord to get the "fullname" field value from the selected record
    Xrm.WebApi.retrieveRecord("contact", FirstSelectedItemId, "?$select=fullname")
        .then(
            function success(result) {
                // Retrieve the "fullname" field value from the result
                let contactFullName = result["fullname"];

                // Create activity parameters
                let activityParameters = {
                    to: [{
                        id: FirstSelectedItemId,
                        name: contactFullName, // Use the "fullname" field value
                        entityType: "contact"
                    }]
                };

                // Navigate to email entity
                window.parent.Xrm.Navigation.navigateTo(
                    { pageType: "entityrecord", entityName: "email", data: activityParameters },
                    { target: 2 } // Open in modal
                ); 
            },
            function(error) {
                console.log(error.message); // Handle error
            }
        );
}

Scenario 2: Populating multiple selected Contacts from a list view (based on the Contacts table)


function openEmail(selectedContactIds) {
    // Array to store recipients
    let toRecipients = [];

    // Loop through each selected contact ID
    selectedContactIds.forEach(function(contactId) {
        // Use Xrm.WebApi.retrieveRecord to get the "fullname" field value from each selected contact record
        Xrm.WebApi.retrieveRecord("contact", contactId, "?$select=fullname")
            .then(
                function success(result) {
             // Retrieve the "fullname" field value from the result
                    let contactFullName = result["fullname"];

                    // Add the contact to the recipients array
                    toRecipients.push({
                        id: contactId,
                        name: contactFullName,
                        entityType: "contact"
                    });

             // If all selected contacts are processed, navigate to the email entity
                    if (toRecipients.length === selectedContactIds.length) {
                        // Create activity parameters
                        let activityParameters = {
                            to: toRecipients
                        };

                        // Navigate to email entity
                        window.parent.Xrm.Navigation.navigateTo(
                            { pageType: "entityrecord", entityName: "email", data: activityParameters },
                            { target: 2 } // Open in modal
                        ); 
                    }
                },
                function(error) {
                    console.log(error.message); // Handle error
                }
            );
    });
}

Scenario 3: Populating multiple selected Contacts from a list view (based on a custom table with a lookup column to Contacts)


function openEmail(selectedRecordIds) {
    // Array to store recipients
    let toRecipients = [];

    // Loop through each selected record ID
    selectedRecordIds.forEach(function(recordId) {
        // Use Xrm.WebApi.retrieveRecord to get the lookup field value from each selected record
        Xrm.WebApi.retrieveRecord("prefix_custom_table", recordId, "?$select=_prefix_contact_value")
            .then(
                function success(result) {
         // Retrieve the contact lookup field value from the result
                    let contactId = result["_prefix_contact_value"];

                    // Use Xrm.WebApi.retrieveRecord to get the "fullname" field value from the related contact record
                    Xrm.WebApi.retrieveRecord("contact", contactId, "?$select=fullname")
                        .then(
                            function success(contactResult) {
                                // Retrieve the "fullname" field value from the contact record
                                let contactFullName = contactResult["fullname"];

                         // Add the contact to the recipients array
                                toRecipients.push({
                                    id: contactId,
                                    name: contactFullName,
                                    entityType: "contact"
                                });

                        // If all selected records are processed, navigate to the email entity
                                if (toRecipients.length === selectedRecordIds.length) {
                                    // Create activity parameters
                                    let activityParameters = {
                                        to: toRecipients
                                    };

                                    // Navigate to email entity
                                    window.parent.Xrm.Navigation.navigateTo(
                                        { pageType: "entityrecord", entityName: "email", data: activityParameters },
                                        { target: 2 } // Open in modal
                                    ); 
                                }
                            },
                            function error(contactError) {
                                console.log("Error retrieving contact record:", contactError.message);
                            }
                        );
                },
                function error(recordError) {
                    console.log("Error retrieving record:", recordError.message);
                }
            );
    });
}

So there you go - hope you enjoyed the read!


Credit to these guys who helped me put me on track for the final result:

Learn more:






© 2024 by Cilate.

bottom of page