Comments (7)
This issue isn't really caused by ngrx-forms. Have a look a this article.
The issue here is that by dispatching that action you are updating the application state which in turn updates the bindings. And since the form control state is part of a larger state tree, that tree gets updated as well, which causes bindings on the parent component to be updated, which in turn leads to the error you observe.
I had to deal with similar issues in my application and I have the following suggestion on how to fix it (although I am not 100% sure that it will work for you). Usually I would simply recommend to move the dispatch of the action into the constructor, but since you need the bound values that is not possible. However, you can dispatch the action as part of updating the binding by using a setter property (which if I remember correctly does not cause the "change after check" error). This has the upside of making your directive react to changes in the values
it is provided (i.e. if the values
binding is updated, a new action is dispatched), but it has the downside of having a bit more complex code to deal with the arbitrary order of binding initialization. Therefore, I propose the following code:
import { Directive, Input, OnInit } from "@angular/core";
import { FormControlState, SetUserDefinedPropertyAction } from "ngrx-forms";
import { ReferenceData } from "../../services/reference-data/reference-data.model";
import { ActionsSubject } from "@ngrx/store";
@Directive({
selector: 'app-autocomplete[ngrxFormControlState][values]',
})
export class AutocompleteValuesDirective {
private formControlStateId: string;
private refData: ReferenceData[];
@Input() set ngrxFormControlState(state: FormControlState<string>) {
const prevStateId = this.formControlStateId;
this.formControlStateId = state.id;
// deal with the case that values is bound initially before the state is bound
// or if the state's ID changes while refData is set
if (state.id !== prevStateId && !!this.refData) {
this.updateAutocompleteValues();
}
}
@Input() values(refData: ReferenceData[]) {
this.refData = refData;
if (!!this.formControlStateId) {
this.updateAutocompleteValues();
}
}
constructor(private actionsSubject: ActionsSubject) { }
updateAutocompleteValues() {
this.actionsSubject.next(new SetUserDefinedPropertyAction(this.formControlStateId, 'AUTOCOMPLETE_VALUES', this.refData));
}
}
from ngrx-forms.
@sylvaingirardbe did this resolve your issue?
from ngrx-forms.
I haven't been able to get to this issue again. I'll try to take a look at it this week.
from ngrx-forms.
The proposed solution didn't work... The reason I'm trying this is because I have an autocomplete control and I was trying to use the values in the user defined property to validate the user input against since nothing prohibits him from entering something completely random.
When I was first looking into this, I wasn't completely sure that, even with the values in the user defined property, it was going to work. Do you maybe have some piece of example code how to validate input against a property (values) on a control?
from ngrx-forms.
@sylvaingirardbe Sorry for the late response.
Validating a control based on a user defined property should be straight forward, something like this:
interface FormValue {
searchTerm: string;
}
const initialState = createFormGroupState<FormValue>('some ID', {
searchTerm: '',
});
const groupReducer = createFormGroupReducerWithUpdate<FormValue>({
searchTerm: searchTerm => {
if (searchTerm.userDefinedProperties.allowedValues.indexOf(searchTerm.value) >= 0) {
return searchTerm;
}
return setErrors({
invalidValue: {
actualValue: searchTerm.value,
allowedValues: searchTerm.userDefinedProperties.allowedValues,
},
}, searchTerm);
};
});
The trick is of course in getting the allowedValues
set on the control. The way you are doing it with an additional directive seems just fine. Alternatively you could of course just dispatch the action inside your component. However, my preferred way would be to do it in a reducer. I guess you are loading the allowed values for the autocomplete from the server, right? In that case you'd have an action that sets the allowed values somewhere in the store. You could simply write a reducer for the form state that reacts to that action and sets the user defined property. Something like this:
const customFormGroupReducer = (state: FormGroupState<FormValue>, action: Action) => {
if (action.type === 'your action that sets the allowed values') {
return updateGroup<FormValue>({
searchTerm: setUserDefinedProperty('allowedValues', action.payload.values),
}, state);
}
return formGroupReducer(state, action);
};
from ngrx-forms.
@sylvaingirardbe have you resolved your issue by now? May I close this issue?
from ngrx-forms.
I'm replacing the autocompletes with plain old dropdowns since they weren't very user friendly so the immediate need for this is gone. I suspect it'll pop up somewhere down the line again. Until then I'll close it and consider it resolved.
Thanks!
from ngrx-forms.
Related Issues (20)
- Sure, just replace the players update with something like this:
- `NgrxFormControlDirective`: Update view when `ngrxValueConverter` changes HOT 1
- Pattern: Supply different "feature state" into the form reducer? HOT 1
- mat-radio checked not working? HOT 1
- Type inference is incorrect with readonly[]
- Question: Bind server-side validation to ngrx-forms forms
- [QUESTION] - Validation of a nested formState HOT 1
- Primitive unions are not supported
- Add compatibility with typescript 4.8 HOT 1
- New Angular Version 15 with breaking changes on Material to mat-list-options HOT 3
- No valid view adapter for Slider with Angular Material 15
- FormArrayState, the state doesn't update when SetValueActions are disptached
- Add compatibility with Typescript 5
- material 15+ (MCD based components) compatibility HOT 1
- Angular 16 support HOT 4
- Enable/Disable nested array properties HOT 3
- Programmatically Triggering Async Validation HOT 3
- Add sortArray function HOT 4
- Control validation order, run async after synchronous complete without error
- Question: Update parent form state based on child control states
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ngrx-forms.