-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ngModelChange fires twice when the value for nimble-text-field is updated #1017
Comments
Tried it in the example app and reproduce the behavior. I can see that the first time it is triggered it is the DefaultValueAccessor running: The second time it is triggered is the NimbleTextFieldControlValueAccessorDirective that runs: I expect Nimble's to be running, but don't understand why Angular is also binding the DefaultValueAccessor... The selector for the DefaultValueAccessor should not match nimble-text-field: https://angular.io/api/forms/DefaultValueAccessor#selectors |
OverviewWent down the rabbit hole 🐇 and have a theory of what is happening. The current Textfield CVA extends Angular's DefaultValueAccessor directly. If you follow the inheritance tree you land on this magical comment:
So my theory is that the way we are trying to leverage the DefaultValueAccessor gets Angular confused and injecting it's own DefaultValueAccessor along with the TextField CVA at runtime. We have a Custom CVA that Angular recognizes as a Default CVA based on the stuff we are inheriting from. (Hand wavy guess / theory, I haven't traced the exact mechanism). Edit: I think this theory / behavior is essentially confirmed by angular/angular#9146 Solution Fork Angular form CVAsI made a branch where I vendor in the DefaultValueAccessor and remove any funny business linking back to Angular's heirarchy and it seems to work (open dev tools and type characters in the underline text field, notice one console log per character). This is essentially the first product facing issue related to #732 which cites that we are un-supportedly extending Angular's private API the way we are doing CVAs. This is similar to the radio_control_value_accessor we need to fork the Angular Form Directives we are interested in if we want to leverage their implementations for our web components. 😢 Maybe a submodule patch workflow and a separate package would be useful... Non-solution Re-use Angular CVAs as hostDirectivesUnfortunately the Angular 14 hostDirectives feature discussed in #732 won't work in this case because the DefaultValueAccessor directive is not standalone and the Angular team is hesitant about making the form directives standalone Solution Compose the Angular CVAs in wrapper DirectivesI created a prototype branch of doing this with the DefaultValueAccessor. I found a TypeScript pattern to make sure we capture the API surface of the public API / that we can catch any public API deviations from the wrapper to the original at compile. I'd want to try a more sophisticated CVA to see if the approach is workable. Solution Compose the Angular CVAs in wrapper Directives with ProxyExample branch using es6 Proxies to forward everything automatically to an instance of the DefaultValueAccessor and making it lie correctly for instanceof checks. |
This is something that is currently impacting the Asset Management team. Found this bug before creating a newer one on the same issue. |
@catalin-drulea were you able to find a workaround for your use case? I re-added the triage tag to remind the team to evaluate options and priority since this is cropping up again. |
I'm also encountering the same problem when trying to add a search bar in the Feeds application. I haven't found any workarounds. |
# Pull Request ## 🤨 Rationale Update to Angular 15.2 for nimble-angular. Resolves #1079 Resolves #1017 Resolves #1570 Resolves #732 Resolves #1665 ## 👩💻 Implementation - Update Angular version to 15.2 using Angular's upgrade utility - Create forks of some of Angular's CVAs and Angular's RouterLink directive under `angular-workspace\projects\ni\nimble-angular\src\thirdparty\directives\` with modifications to get them to work as expected as base classes for nimble directives - Add explicit dependency on `source-map-loader` to `nimble-components` to ensure the tests continue to run as they previously did ## 🧪 Testing - Ran the Angular app and verified it worked as expected - Existing unit tests pass - Copied & adapted Angular tests for CVAs and RouterLink directive into `angular-workspace\projects\ni\nimble-angular\src\thirdparty\directives\tests\` - Added new unit tests for each nimble CVA that verifies that `ngModelChange` is only called once when a control's value changes - Added new unit tests for each routerLink directive that verifies that the href was sanitized - Used the built package to verify it works correctly in SystemLinkShared ## ✅ Checklist <!--- Review the list and put an x in the boxes that apply or ~~strike through~~ around items that don't (along with an explanation). --> - [ ] I have updated the project documentation to reflect my changes or determined no changes are needed. --------- Co-authored-by: Mert Akinc <7282195+m-akinc@users.noreply.github.com> Co-authored-by: Milan Raj <rajsite@users.noreply.github.com>
🐛 Bug Report
Noticed that I was logging twice in my ngModelChange handler when typing new values into a nimble-text-field
💻 Repro or Code Sample
https://stackblitz.com/edit/angular-ivy-ayatnv?file=src/app/app.component.ts
🤔 Expected Behavior
ngModelChange should call my handler once per character change
😯 Current Behavior
ngModelChange calls my handler twice per character change
Behavior as demonstrated by the stackblitz link
💁 Possible Solution
N/A
🔦 Context
Trying to update a service value with the text field's new value
🌍 Your Environment
OS: Windows, Stackblitz
Browser: Microsoft Edge, FireFox
The text was updated successfully, but these errors were encountered: