@@ -58,6 +58,11 @@ trait ComponentWithFormTrait
58
58
#[LiveProp(writable: true )]
59
59
public array $ validatedFields = [];
60
60
61
+ /**
62
+ * Internal flag to track if the form should be submitted on render.
63
+ */
64
+ private bool $ didFormSubmit = false ;
65
+
61
66
/**
62
67
* Return the full, top-level, Form object that this component uses.
63
68
*/
@@ -66,14 +71,20 @@ abstract protected function instantiateForm(): FormInterface;
66
71
/**
67
72
* Override in your class if you need extra mounted values.
68
73
*
69
- * Call $this->setForm($form) manually in that situation
70
- * if you're passing in an initial form.
74
+ * If you override, call $this->initializeFormValues() manually
75
+ * and also $this->formView = $form if you are passing in a Form.
76
+ *
77
+ * TODO: Refactor to PostMount when available.
78
+ * https://github.com/symfony/ux/pull/220
71
79
*/
72
- public function mount (? FormView $ form = null )
80
+ public function mount (FormView $ form = null )
73
81
{
74
82
if ($ form ) {
75
- $ this ->setForm ( $ form) ;
83
+ $ this ->formView = $ form ;
76
84
}
85
+
86
+ // set the formValues from the initial form view's data
87
+ $ this ->initializeFormValues ();
77
88
}
78
89
79
90
/**
@@ -86,7 +97,7 @@ public function mount(?FormView $form = null)
86
97
#[BeforeReRender]
87
98
public function submitFormOnRender (): void
88
99
{
89
- if (!$ this ->getFormInstance ()->isSubmitted ()) {
100
+ if (!$ this ->getFormInstance ()->isSubmitted () && ! $ this -> didFormSubmit ) {
90
101
$ this ->submitForm (false );
91
102
}
92
103
}
@@ -103,18 +114,6 @@ public function getForm(): FormView
103
114
return $ this ->formView ;
104
115
}
105
116
106
- /**
107
- * Call this from mount() if your component receives a FormView.
108
- *
109
- * If your are not passing a FormView into your component, you
110
- * don't need to call this directly: the form will be set for
111
- * you from your instantiateForm() method.
112
- */
113
- public function setForm (FormView $ form ): void
114
- {
115
- $ this ->formView = $ form ;
116
- }
117
-
118
117
public function getFormName (): string
119
118
{
120
119
if (!$ this ->formName ) {
@@ -124,18 +123,16 @@ public function getFormName(): string
124
123
return $ this ->formName ;
125
124
}
126
125
127
- public function getFormValues (): array
126
+ private function initializeFormValues (): void
128
127
{
129
- if (null === $ this ->formValues ) {
130
- $ this ->formValues = $ this ->extractFormValues ($ this ->getForm ());
131
- }
132
-
133
- return $ this ->formValues ;
128
+ $ this ->formValues = $ this ->extractFormValues ($ this ->getForm ());
134
129
}
135
130
136
- private function submitForm (bool $ validateAll = true ): void
131
+ private function submitForm (bool $ validateAll = true , bool $ throwOnValidationError = true ): void
137
132
{
138
- $ this ->getFormInstance ()->submit ($ this ->formValues );
133
+ $ form = $ this ->getFormInstance ();
134
+ $ form ->submit ($ this ->formValues );
135
+ $ this ->didFormSubmit = true ;
139
136
140
137
if ($ validateAll ) {
141
138
// mark the entire component as validated
@@ -146,14 +143,29 @@ private function submitForm(bool $validateAll = true): void
146
143
// we only want to validate fields in validatedFields
147
144
// but really, everything is validated at this point, which
148
145
// means we need to clear validation on non-matching fields
149
- $ this ->clearErrorsForNonValidatedFields ($ this -> getFormInstance () , $ this ->getFormName ());
146
+ $ this ->clearErrorsForNonValidatedFields ($ form , $ this ->getFormName ());
150
147
}
151
148
152
- if (! $ this -> getFormInstance () ->isValid ()) {
149
+ if ($ throwOnValidationError && ! $ form ->isValid ()) {
153
150
throw new UnprocessableEntityHttpException ('Form validation failed in component ' );
154
151
}
155
152
}
156
153
154
+ /**
155
+ * Call this to rebuild the form objects.
156
+ *
157
+ * This is useful in action where you call $this->submitForm(),
158
+ * then, after, change some of the form's underlying data. By
159
+ * call this function, the form can rebuild using the new data.
160
+ */
161
+ private function refreshForm (): void
162
+ {
163
+ $ this ->formInstance = null ;
164
+ $ this ->formView = null ;
165
+ // re-initialize the form object and the formValues from it
166
+ $ this ->initializeFormValues ();
167
+ }
168
+
157
169
/**
158
170
* Returns a hierarchical array of the entire form's values.
159
171
*
0 commit comments