I have a backend form with a repeater element. I have added a partial button to it that when clicked calls a function on the controller.
The function carries out various tasks that include adding another repeater item. I would like after everything has completed to refresh the repeater element with the new entries.
I can see using a debugger that the $this->formRenderField('fieldToUpdate', ['useContainer'=>false]); is using the originally loaded model not the modified version. Even if it’s saved back to the database and refetched prior to $this->initForm($model);
Yes, it will contain the unmodified model since the handler won’t automatically apply the form values. Try running this command inside the AJAX handler to log all the post variables to the system log (storage/logs/system.log) to inspect what is inside, then populate the model
trace_log(post());
This can be helpful to understand what data you have available. The following example can be useful
public function onDoSomething()
{
// Get an instance of the model
$model = $this->formGetModel();
// Sets all the values from the current form
$this->formGetWidget()->setFormValues();
// Sets an individual field
$this->formGetWidget()->setFormValues([
'my_field' => 'foobar'
]);
// Refreshes specific fields
return $this->formRefreshFields([
'my_field'
]);
}
A repeater is a more complicated example. What form do you want to manipulate, specifically? Consider the following structure:
Parent Form
^- Repeater Field
^- Child Form 1
^- Child Form 2
^- Child Form 3
Do you want to set values on a single Child Form? Or do you want to establish the entire set of Child Forms?
To follow on from this solution
$parentForm = $this->formGetWidget();
$repeaterWidget = $parentForm->getFormWidget('repeater');
$repeaterForm = ... // No method exists to locate a child form
@daft I add new records to the repeater, which depend on the fields of the main form, that is, I create new Expando models, if I simply refresh the page I see them, but when I call the Ajax handler, the repeater is not updated
in modules\backend\formwidgets\repeater\HasRelationStore.php
/**
* getLoadValueFromRelation
*/
protected function getLoadValueFromRelation()
{
// This code blocks the addition of new relations if they are created elsewhere
// if ($this->relatedRecords !== null) {
// return $this->relatedRecords;
// }
// @deprecated This could be refactored to always use deferred binding
// and make sure the array keys match the model keys and drop the _id
// if ($this->isLoaded) {
// $value = $this->getLoadedValueFromPost();
// $ids = is_array($value) ? array_map(function ($v) {
// return $v['_id'] ?? 0;
// }, $value) : [];
// $records = $this->getRelationQuery()->find($ids);
// if ($records) {
// $indexes = array_flip($ids);
// foreach ($records as $model) {
// $rIndex = $indexes[$model->getKey()] ?? null;
// if ($rIndex !== null) {
// $this->relatedRecords[$rIndex] = $model;
// }
// }
// }
// } else {
$this->relatedRecords = $this->getRelationObject()
->withDeferred($this->getSessionKey())
->get()
->all();
//}
// Store the results locally on the model to make it available to the
// RelationController via the initNestedRelation method
if ($this->relatedRecords) {
[$model, $attribute] = $this->resolveModelAttribute($this->valueFrom);
$model->setRelation($attribute, $model->newCollection($this->relatedRecords));
}
return $this->relatedRecords;
}