Skip to content

Commit 8f91ea7

Browse files
committed
chore: updated README with section on dynamic form groups
1 parent fe23ab2 commit 8f91ea7

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,67 @@ As you can see most properties are shared with controls via the common base inte
220220

221221
Group states are usually completely independent of the DOM (with the exception of root groups that are associated with a `form` via `NgrxFormDirective`). They are updated by intercepting all actions that change their children (i.e. the group's reducer is the parent reducer of all its child reducers and forwards any actions to all children; if any children change it recomputes the state of the group). A group state can be created via `createFormGroupState`. This function takes an initial value and automatically creates all child controls recursively.
222222

223+
#### Dynamic Form Groups
224+
225+
Sometimes you will have to render a variable number of fields in your form. In such a case you can provide a form value interface that has an index signature and then add and remove controls dynamically. Instead of an index signature you can also use optional fields if the potential members of the form value are statically known. At runtime you can add and remove controls in two ways:
226+
227+
1) explicitly call the `addControl` and `removeControl` update functions (see the section below)
228+
2) set the value of the form group via `setValue` which will automatically update the form group based on the value you provide
229+
230+
Below you can find an example of how this would look. Assume that we have an action that provides a variable set of objects which each should be mapped to a group with two form controls.
231+
232+
```typescript
233+
import { Action } from '@ngrx/store';
234+
import { FormGroupState, setValue, cast } from 'ngrx-forms';
235+
236+
interface DynamicObject {
237+
id: string;
238+
someNumber: number;
239+
someCheckbox: boolean;
240+
}
241+
242+
interface DynamicObjectFormValue {
243+
someNumber: number;
244+
someCheckbox: boolean;
245+
}
246+
247+
interface DynamicFormValue {
248+
[id: string]: DynamicObjectFormValue;
249+
}
250+
251+
interface SetDynamicObjectsAction extends Action {
252+
type: 'SET_DYNAMIC_OBJECTS';
253+
objects: DynamicObject[];
254+
}
255+
256+
interface AppState {
257+
someOtherState: string;
258+
dynamicForm: FormGroupState<DynamicFormValue>;
259+
}
260+
261+
export function appReducer(state: AppState, action: Action): AppState {
262+
switch (action.type) {
263+
case 'SET_DYNAMIC_OBJECTS': {
264+
const newFormValue = (action as SetDynamicObjectsAction).objects.reduce((v, obj) => {
265+
v[obj.id] = {
266+
someNumber: obj.someNumber,
267+
someCheckbox: obj.someCheckbox,
268+
};
269+
return v;
270+
}, {} as DynamicFormValue);
271+
272+
// the `setValue` will add and remove controls as required; existing controls that are still
273+
// present get their value updated but are otherwise kept in the same state as before
274+
const dynamicForm = cast(setValue(newFormValue, state.dynamicForm));
275+
return { ...state, dynamicForm };
276+
}
277+
278+
default:
279+
return state;
280+
}
281+
}
282+
```
283+
223284
### Updating the State
224285

225286
All states are internally updated by ngrx-forms through dispatching actions. While this is of course also possible for you there exist a set of utility functions that can be used to update states. This is mainly useful to change the state as a result of a different action in your reducer. Note that ngrx-forms is coded in such a way that no state references will change if nothing inside the state changes. It is therefore perfectly safe to repeatedly call any of the functions below and the state will be updated exactly once or not at all if nothing changed. Each function can be imported from `ngrx-forms`. The following table explains each function:

0 commit comments

Comments
 (0)