When we have a PCF component, it’s important to know when updateView will be called, in order to take care about performance. So when is updateView called?
In the documentation is stated:
“This method will be called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, component metadata values such as label, visible, etc.“
And that’s a good definition. But what does this mean? I’m sure I haven’tz discovered everything, but looking to a PCF component of type “field” in a model-driven app, here is what I’ve found out until now:
Called from inside the component
Beginning: after init
updateView will be called in the beginning, after the “init” method was called.
In the PCF learning path (https://docs.microsoft.com/en-us/learn/modules/get-started-component-framework/2-architecture) , we get a really good architecture overview, telling us that the updateView is called after the control calls notifyUpdateChanged method. After that, the Framework Runtime calls the getOutputs method and notified the Host. If the Host accepts the value, the updateView is called with the new value. If the Host rejects the value, updateView is called with the oldValue. Here is the overview from the learning path:
So we have to take care: the value the component changes, is not always the right one. And, in case the value notified to the FrameworkRuntime was accepted, the updateView will be triggered, with the same value that the control just notified.
We have the possibility to open our component FullScreen, using the context provided to the component:
When we call that, the updateView will be triggered. This blog (https://www.inogic.com/blog/2019/11/how-to-handle-updateview-function-call-while-calling-setfullscreen-function-in-pcf-control/) tells us how to look to context.updatedProperties and check if the last item in updatedProperties is “fullscreen_close” or “fullscreen_open”, in order to avoid unnecessary render.
But there is another important point to take care of: when using setFullScreen method (or when the user closes the Zoomed control using the X button), the value passed to the updateView method, is the last value that the Host was notified of. So, in case the user typed some text, but the Host is not aware of this change, the updateView will be called with the old value.
Calls from outside the component
Some script on the form could call some sdk methods like:
When setDisabled is applied to the control, the updateView will be called. BUT it will be called only if setDisabled is called with a different value. For instance, if the control is already disabled, and setDisabled is called with “true”, updateView won’t be triggered. Also, setDisabled is never called, if the control is not visible.
updateView will be called also when some script is showing the control back, but not when it is being switched to hidden.
For more details, here is a blog from Alex Shlega, talking about setVisible and setDisabled in combination with updateView: https://www.itaintboring.com/dynamics-crm/pcf-components-and-setvisible-setdisabled/
Attribute method “setValue”
Using <Attribute>.setValue(newValue), then updateView will be triggered with the new value. But updateView won’t be triggered if the value used for setValue(value) is not a new one. So calling twice setValue with same value won’t trigger updateView twice.
myAttribute.setValue("owesome"); //triggers updateView myAttribute.setValue("owesome"); //---- nothing happens
UpdateView will be called after setValue(), even if the control is disabled.
Saving and refreshing the from
If the page called (former Xrm.Page) formContext.data.save() or formContext.data.refresh(), the updateView will be called 2 times; even if the value for this control was not changed. So in case your control didn’t get to notify the form about the change, updateView will be called with wrong value. This gets even more complicated, if the autosave is activated.
Consider having an input of type text;
- the user introduced some text that the control notified to the host;
- then the user is introducing more text while the autosave is started.
- Until the autosave is back, the user introduced some more data, but the updateView is called with the last value that the form is aware of.
So what should be the right event to notify the form about the change? I had a log thread in the community about this: https://powerusers.microsoft.com/t5/Power-Apps-Pro-Dev-ISV/Which-event-for-notifyOutputChanged/m-p/496920#M1933 Thank you Ben Thompson and Hemant Gaur for helping me about this issue. It seems that for most of the cases it’s enough to notify the framework about the change using the “change” event, while in the updateView ignore the value if it’s an old one.
My colleague Tim Zech came up with a better solution: when the user starts to input the text, the control is responsible for the value; it notifies the host about the change but it ignores what the updateView tells. In “OnBlur” (or OnChange for inputs) the control stops being responsible for the value and accepts the value provided in updateView.
If the form is closed (maybe using formContext.ui.close()) the updateView will be called, BUT only if the control DID notified the host about being changed. That’s another point where we have to take care of: if the control notifies the host only on “blur”, it might happen that the input value is lost, since we have no chance to tell the host that the control is dirty.
The updateView will be called after the window was resized, BUT only if we tell the framework to do so. So we need to set this in the “init”:
Maybe there are some more events where updateView will be triggered. The documentation tell about metadata and offline. Maybe I’ll find soon some more events.