The Core Issue
- You follow the best practice of working with three environments: DEV, TEST and PROD
- MS forms cannot be deployed as a solution component
- Therefor changes you make to the forms during development (DEV) immediately affect the PROD environment as well.
- Bad things happen
The Core Solution
While it is not possible to make MS Forms directly "deployable", you can create two separate instances of MS Forms.
One for PROD and one for DEV - and, optionally, a third one for TEST.
But now, your flow won't know which form to pick. The actions "When a new response is submitted" and "Get response details" now need to access separate forms...
- Display name: "Forms ID"
- Data Type: "Text"
- Current Value: the long id string you can find in the URL of your MS Forms.
It's at the end of the URL, after "id="
(Or course your DEV forms and your PROD forms, will have different IDs!)
Two forms = Two sets of internal QuestionIds
If your PROD form is simply a copy of your DEV form, all the QuestionIds may initially be identical. However, you can't count on it. As soon as you start working with these two forms independently (e.g. during a later development cycle) you will get separate QuestionIds.
We need a way to map the question to the QuestionId for each environment. For this, let's create a list of key/value pairings in a new Dataverse table - where the key is an abbreviation of the question, and the value will be the target QuestionId (of the environment-specific MS Forms instance).Create a Dataverse table; call it something like "Forms Mapping".
Leave the default "Name" column, we'll use it as the key in our key/value pair.
Create a Text column called "Value", that holds the QuestionId
For each question in your forms, add a record to this new table. Example:
Question: "What's our email address?" -> name = "email", value="_email_question_id_here_"
Question: "What's your date of birth?" -> name = "birthdate", value="_date_question_id_here_"
Okay, but where do we get the actual QuestionIds for each form?
Luckily, that's quite easy, if you set your MS Forms to Preview mode and view the page's source code. If you are using Google Chrome and hover over the source code, it will help you navigate quickly through to the elements that hold the answer.
You are looking for <div data-automation-id="questionItem" ... and inside it, you will find the QuestionId on the next source code line; e.g. id="QuestionId_r334f23da2...". Copy the id (without the prefix "QuestionId_") into your Dataverse value field. Repeat for all questions.
Since the forms are not hardcoded anymore into the flow, we need a way to access each question, using the QuestionId. For this we will convert our Table "Forms Mapping" into something your flow can work with.
1) List rows (Dataverse)
Select your Name and Value columns (by their logical names). Sorting is not really necessary.
2) Select
From:
All items from the "List row" action (Dynamic content name = "value")
Map:
item()?['xyz_name']
(use your own prefix)
to:
outputs('Get_response_details')?['body']?[item()?['phfd_value']]
3) Compose
first(json(replace(string(body('Select')), '},{', ',')))
Now whenever you need access to a specific response of the form, don't use dynamic content. Instead, use the expression:
outputs('map')?['_question_key_here_']
Example:
outputs('map')?['birthdate']
This will resolve the key (or name) to the matching value (QuestionId) using your Dataverse Table "Forms Mapping" and use that Id to access the form's response to that question.
Lastly
There are two QuestionIds you don't need to worry about, because they are always the same:
For these you can absolutely use dynamic content safely.
I hope this approach works well for you. Good luck!


No comments:
Post a Comment