bug: virtual prop mode does not account if assigned dynamically for all components
Prerequisites
- [X] I have read the Contributing Guidelines.
- [X] I agree to follow the Code of Conduct.
- [X] I have searched for existing issues that already report this problem, without success.
Ionic Framework Version
v7.x
Current Behavior
If a global mode is defined using
IonicModule.forRoot({ mode: 'ios' })
Mode on component level won't assign the defined mode, instead global mode is used.
public mode = isPlatform('ios') ? 'ios' : 'md'
<!-- works only if app is initialized with this component first -->
<ion-button [mode]="mode"><ion-button>
But if you use the mode value directly like
<!-- works always -->
<ion-button mode="md"><ion-button>
it works, even if global mode is set to ios.
https://github.com/ionic-team/ionic-framework/assets/26873275/d7041deb-6a44-4afe-b9fa-e72a7d30336c
In this example both tabs have assigned mode="md". Some of them directly (fixed mode), some with value binding (dynamic mode). As you can see here only the first initialized tab is working as expected with both fixed and dynamic mode as md. If you now switch the tab, the md mode is gone and ios mode is visible.
Expected Behavior
mode on component level should also work with value binding, even if global mode is set to ios
Steps to Reproduce
- open provided stackblitz
- "Listen Now" Tab is Visible, style for ion-button and ion-refresher is md ✅
- switch tab to "Radio"
- dynamic pull-to-refresh is iOS (should be md), dynamic button is iOS (should be md) ❌
- refresh the application while "Radio" Tab is active
- now both buttons are correct ✅
- switch tab to "Listen Now"
- fixed pull-to-refresh is md (correct), dynamic button is iOS (should be md) ❌
Code Reproduction URL
https://stackblitz.com/edit/angular-od4spf?file=src%2Fapp%2Fhome%2Fhome-page.component.html
Ionic Info
9.x
Additional Information
I think this bug only occurs in angular where the mode is defined in proxies.ts, since all components use changeDetection: ChangeDetectionStrategy.OnPush.
Since global mode is set using IonicModule.forRoot({ mode: 'ios' }), reassigning mode on component level doesn't trigger changeDetectionRef.detectChanges(), so the components keep the global defined mode.
related: #29137
Thank you for the issue. I can reproduce this, but need to dig into why exactly it's happening. If the issue is indeed with the change detection, we'll need to figure out the best path forward to resolving that.
Hello @DwieDima this behavior is working as intended in Ionic Framework.
Virtual properties do not behave the same as our @Prop decorated properties. They aren't reactive and are not intended to be.
With Angular we have an additional limitation that the property value is not set immediately when the element is inserted into the DOM with the binding syntax ([mode]="foo"). It is initially undefined and 1-2 frames later is set to the value you provide. Since these properties are not reactive, they fallback to the detected mode instead of the specified mode when using the binding syntax.
Supporting reactive properties is something the team has discussed in the past, but has a lot of edge cases where reactive config options can cause issues in a users application. As a result we decided against supporting it.
Do you have a use case from an application where a dynamic mode is required that we could explore further?
In the past when faced with this type of behavior, I would render different instances of an element with the mode set statically to achieve the behavior around the limitations that Ionic Framework + Angular have.
Hi @sean-perkins, thanks a lot for the detailed explanation about how virtual properties work in Ionic.
I appreciate the suggestion to display components statically based on conditions to address the issues with reactive properties. This approach has resolved the problem.
I wasn't aware that virtual properties cannot handle dynamic values. Is this documented anywhere in Ionic's official documentation?
Thank you for raising this issue! I've created an issue to have it added to the official Ionic documentation: https://github.com/ionic-team/ionic-docs/issues/3814.
I'll be closing this issue, but feel free to add any feedback to the linked issue if you think there's anything missing from the documentation that would be helpful to include. 🙂
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.