Skip to content

Commit 43be652

Browse files
committed
dynamic :formControl
1 parent 44f2750 commit 43be652

5 files changed

Lines changed: 28 additions & 25 deletions

File tree

docs/custom-properties.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -438,14 +438,14 @@ Forms made easy!
438438
Full example:
439439
```XML
440440
<Column :formGroup="loginFormGroup">
441-
<TextField :formControl="username">
441+
<TextField :formControl="'username'">
442442
<decoration>
443443
<InputDecoration labelText="'username' | translate" errorText="ctrl.loginFormGroup.get('username').firstErrorIfTouched | translate">
444444
</InputDecoration>
445445
</decoration>
446446
</TextField>
447447

448-
<TextField :formControl="password" obscureText="true">
448+
<TextField :formControl="'password'" obscureText="true">
449449
<decoration>
450450
<InputDecoration labelText="'password' | translate" errorText="ctrl.loginFormGroup.get('password').firstErrorIfTouched | translate">
451451
</InputDecoration>
@@ -464,8 +464,8 @@ Then add the controls in the controller class:
464464
```dart
465465
MyLoginController() {
466466
loginFormGroup.addAll([
467-
FomrControl<String>('username', '', validators: [Validators.required]),
468-
FomrControl<String>('password', '', validators: [Validators.required])
467+
FormControl<String>('username', '', validators: [Validators.required]),
468+
FormControl<String>('password', '', validators: [Validators.required])
469469
]);
470470
// add this only if you use :formSubmit
471471
loginFormGroup.onSubmit(_login);
@@ -495,13 +495,13 @@ Then add the controls in the controller class:
495495
- The `:formGroup` is optional, if you didn't add it then the form group will be named as `formGroup`.
496496
- The `:formControl` can be added to `TextField` or any Widget that have `value` property and `onChanged` event like `Switch`, `DropdownButton`:
497497
```XML
498-
<SwitchListTile :formControl="darkModeEnabled">
498+
<SwitchListTile :formControl="'darkModeEnabled'">
499499
<title>
500500
<Text text="'Dark mode'" />
501501
</title>
502502
</SwitchListTile>
503503

504-
<DropdownButton :formControl="selectedLocale">
504+
<DropdownButton :formControl="'selectedLocale'">
505505
<items>
506506
<DropdownMenuItem value="'ar'">
507507
<Text text="'العربية'" />

src/generators/class-generator.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,18 @@ export class ClassCodeGenerator {
137137
138138
class ${rootWidget.controller}Base {
139139
bool _loaded = false;
140-
bool _controllerAttached = false;
140+
Map<String, dynamic> _attachedControllers = Map();
141141
${varsLines.join('\n ')}
142142
143-
void _attachFormControllers(${formControls.map(a => `${a.controller}`).join(',\n ')}) {
144-
if (_controllerAttached) {
145-
return;
143+
dynamic _attachController(String controlName, controllerBuilder) {
144+
if (_attachedControllers.containsKey(controlName)) {
145+
final controller = _attachedControllers[controlName];
146+
return controller;
146147
}
147-
_controllerAttached = true;
148-
${formControls.map(a => `${a.name}.attachTextEditingController(${a.controller});`).join('\n ')}
148+
final controller = controllerBuilder();
149+
_attachedControllers[controlName] = controller;
150+
formGroup.get(controlName).attachTextEditingController(controller);
151+
return controller;
149152
}
150153
151154
void _load(BuildContext context) {
@@ -196,7 +199,6 @@ class ${widgetName} extends StatelessWidget${mixinsCode} {
196199
...rootWidget.vars.map(a => `${a.type} ${a.name};`),
197200
...(routeAware ? [`RouteObserver<Route> _routeObserver;`] : [])
198201
];
199-
const attachFormControllersCode = `ctrl._attachFormControllers(${formControls.map(a => `${a.controller}`).join(',\n ')});`;
200202
const stateVarsInit: string[] = [
201203
...(hasController ? [`ctrl = new ${rootWidget.controller}();`] : []),
202204
...rootWidget.params.map(a => `ctrl._${a.name} = widget.${a.name};`),
@@ -231,7 +233,7 @@ class _${widgetName}State extends State<${widgetName}>${mixinsCode} {
231233
void didChangeDependencies() {
232234
super.didChangeDependencies();${routeAware ? `\n _routeObserver = Provider.of<RouteObserver<Route>>(context)..subscribe(this, ModalRoute.of(context));` : ''}
233235
${rootWidget.providers.map(a => `${hasController ? `ctrl._${a.name} = `: ''}${a.name} = Provider.of<${a.type}>(context);`).join('\n ')}
234-
${hasController ? `ctrl._load(context);\n ${attachFormControllersCode}` : ''}
236+
${hasController ? `ctrl._load(context);` : ''}
235237
}
236238
237239
@override

src/property-handlers/form-control.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export class FormControlHandler extends CustomPropertyHandler {
2727
type: 'FormGroup'
2828
});
2929

30-
const formControlName = `${formGroupName}.get('${attr.value}')`;
30+
const name = attr.value;
31+
const formControlName = `${formGroupName}.get(${name})`;
3132
// const formControlName = `${attr.value}FormControl`;
3233
// targetWidget.vars.push({
3334
// name: `FormControl get ${attr.value}FormControl => ${formGroupName}.get('${attr.value}');`,
@@ -39,17 +40,17 @@ export class FormControlHandler extends CustomPropertyHandler {
3940
if (['TextField', 'TextFormField'].filter(a => a === targetWidget.type).length === 1) {
4041
addLocalVar = false;
4142
const controllerName = element.attributes['controller'] ? element.attributes['controller'].split(' ')[1] : '';
42-
const privateControllerName = `${formGroupName}${attr.value[0].toUpperCase()}${attr.value.length > 1 ? attr.value.substring(1) : ''}Controller`;
43+
const privateControllerName = `ctrl._attachController(${name}, ${controllerName || '() => TextEditingController()'})`;
4344

4445
if (!controllerName) {
4546
// only add controller if there is no one present
4647
targetWidget.properties.push({
4748
dataType: 'object',
48-
controller: {
49-
name: privateControllerName,
50-
type: 'TextEditingController',
51-
isPrivate: true
52-
},
49+
// controller: {
50+
// name: privateControllerName,
51+
// type: 'TextEditingController',
52+
// isPrivate: true
53+
// },
5354
value: privateControllerName,
5455
name: 'controller'
5556
});

src/property-handlers/form.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ suite("Forms", function () {
8585

8686
test(":formControl with :width wrapper", function() {
8787
const xml = `
88-
<TextField :formControl="quantity" :width="80" />
88+
<TextField :formControl="'quantity'" :width="80" />
8989
`;
9090

9191
const expected = `
@@ -96,7 +96,7 @@ suite("Forms", function () {
9696
return SizedBox(
9797
width: 80,
9898
child: TextField(
99-
controller: formGroupQuantityController
99+
controller: ctrl._attachController('quantity', () => TextEditingController())
100100
)
101101
);
102102
}

src/property-handlers/if-element.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ Container(
348348
<Text text="'if'" />
349349
</if>
350350
<elseIf value="ifElseCondition | stream">
351-
<TextField :formControl="test">
351+
<TextField :formControl="'test'">
352352
</TextField>
353353
</elseIf>
354354
<else>
@@ -389,7 +389,7 @@ Container(
389389
stream: ctrl.formGroup.get('test').valueStream,
390390
builder: (BuildContext context, ctrlFormGroupGetTestValueStreamSnapshot) {
391391
return TextField(
392-
controller: formGroupTestController
392+
controller: ctrl._attachController('test', () => TextEditingController())
393393
);
394394
}
395395
)

0 commit comments

Comments
 (0)