
I've created a PCF for Canvas Apps that reads the Browser dark/light mode and Browser language really simple, just 10 lines of code (and adds an event listener to track changes while running the app).
In the end I'm calling notifyOutputChanged to pass the values back to the Canvas Apps (directly from inside updateView).
If I'm doing it like that I create an infinte loop (seems like when an output property is set to the same value again it triggers updateView regardless).
So I started to check first if the value has actually changed before calling notifyOutputChanged. Now I have noticed (with the help of console.log) that my updateView code still runs 4 times. It's no performance issue in my case but still really strange.
This is basically the whole code of the PCF:
public updateView(context: ComponentFramework.Context<IInputs>): void
{
this._live = context.parameters.CheckLive.raw
//set Event Listener when "LiveCheck" is set
if(this._live) {
this.darkModeMediaQuery.addEventListener('change', this.darkModeListener);
}
var ischanged = false;
var langchanged = false;
//initial check
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
ischanged = this._mode!=='dark';
this._mode = "dark";
} else {
ischanged = this._mode!=='light';
this._mode = "light";
}
//get language code (can't be changed without browser restart - no event listener needed)
langchanged = navigator.language.substring(0 ,2) !== this._lang;
this._lang = navigator.language.substring(0 ,2) ?? "-";
if (ischanged === true || langchanged === true) {
this._notifyOutputChanged();
}
console.log('UpdateView: Browsermode: '+this._mode+' - Browserlanguage: '+this._lang)
}
public darkModeListener = (event: MediaQueryListEvent) => {
if (event.matches) {
// Dark mode is enabled
this._mode = "dark";
} else {
// Dark mode is not enabled
this._mode = "light";
}
this._notifyOutputChanged();
};
public darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
/**
* It is called by the framework prior to a control receiving new data.
* @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as “bound” or “output”
*/
public getOutputs(): IOutputs
{
console.log('Get Outputs: Browsermode: '+this._mode+' - Browserlanguage: '+this._lang)
return {
BrowserMode: this._mode,
LanguageCode: this._lang
};
}
The picture shows what happens, when I change for light to dark mode. GetOutputs is called because the EventListener triggered
and afterwards UpdateView runs 4 times
Hi @R2Power ,
Hm... not sure if that's your issue.. but...in updateView you attach to an event
this._live = context.parameters.CheckLive.raw
//set Event Listener when "LiveCheck" is set
if(this._live) {
this.darkModeMediaQuery.addEventListener('change', this.darkModeListener);
}
But updateView might be called a few times by the platform. In that case, you would attach the same event listener a few times.
So when that darkModeMediaQuery changes, the darkModeListener will be called a few times. Inside that function, you have the notifyOutputChanged, so that will be called a few times.: so could trigger the updateView even more...
I think you need there to see if the CheckLive changed, and only if there was a change to add or remove the eventListener.