This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.
[EDIT]Ok I found my first problem: Only the field which have the dependsOn property is refreshed, not the entire form, so in the example on the bottom of this thread: I can only change the state/value for the price_prefix field, can't refresh another field.
I still have the problem to add fields to repeater: nothing changes on refresh, for now I tried (with the dependsOn on my repeater field:
public function formExtendRefreshFields($formWidget, $fields)
{
$fields['_offers_descriptions']->value = [
['name' => 'titre1', 'description' => 'description1'],
['name' => 'titre2', 'description' => 'description2']
];
}
With this repeater:
_offers_descriptions:
label: 'Description des projets de maisons neuves'
type: repeater
dependsOn: selected_mixable_house_models
form:
fields:
offers:
label: Descriptions des projets de Maisons Neuves
type: section
name:
type: text
disabled: true
description:
label: Description
required: 1
type: Backend\FormWidgets\RichEditor
Hi.
I created a form with a repeater, I don't want the users to push the button "Add an item", but want to fill the repeater from another model datas.
I made the repeater dependsOn the other fields, but I can't push datas to the repeater, first I tried to use the accessors getMyRepeaterAttribute, but it seems to fail with some field type (RichEditor works well but not text... huh??)
But anyway I'll look deeper into this later, for now I tried a workaround in my controller with the formExtendRefreshFields event triggered when dependsOn fields changes.
To understand how I should use it, I try a really simple example but can't make it work:
public function formExtendRefreshFields($formWidget, $fields)
{
Flash::success('Called');
$fields['price_suffix']->disabled= true;
return $fields;
}
Also tried with formExtendRefreshData to change a field value but can't make it work either.
The flash message is fired, so my function is properly called, but no changes is made on the form.
Here is the part of my yaml:
fields:
price:
label: Prix
type: text
price_prefix:
label: Indication avant le prix
type: text
dependsOn: price
price_suffix:
label: Indication après le prix
type: text
Any suggestions?
Last updated
Did you look at the source code for the FormController
behavior ? It's calling this as shown below: (/modules/backend/behavior/FormController.php)
$this->formWidget->bindEvent('form.beforeRefresh', function ($holder) {
$result = $this->controller->formExtendRefreshData($this->formWidget, $holder->data);
if (is_array($result)) {
$holder->data = $result;
}
});
You might want to use the debug bar plugin to show what gets passed as $holder->data, might not be what you expect.
Hi @mjauvin, the fact is I first tried to make is really simple, with a dependsOn on the repeater, look at this file:
_selected_mixable_house_models:
label: 'Choisissez les modèles de maisons à mixer'
span: full
type: checkboxlist
_offers_descriptions:
label: 'Description des projets de maisons neuves'
type: repeater
dependsOn: _selected_mixable_house_models
form:
fields:
name:
type: text
span: full
description:
label: Description
span: full
type: Backend\FormWidgets\RichEditor
// I hard coded some values to confirm it's an issue, the same data are returned every time: debugbar just failed on my october update
public function getOffersDescriptionsAttribute($value)
{
return [
['name' => 'titre1', 'description' => 'description1'],
['name' => 'titre2', 'description' => 'description2']
];
}
But it seems like there is a repeater bug: At the firs load, fields are correctly rendered, but on refresh, the name fields are empty:
Facing that I tried to do another way... but didn't get it to work more than the dependsOn way.
Last updated
Damn!!! Yes I looked into the doc all day long but the problem was me in the first place: I set the "disabled" option on field set to true. I removed it on my previous snippets because I didn't even expect it should come from there...
But man! Disabled field are not submitted... So the value is set to null....
readOnly instead of disabled solved the problem...
Shame on me. But I still can't refresh a repeater:
public function formExtendRefreshData($formWidget, $dataHolder) {
$dataHolder['_offers_descriptions'] = $this->getDescriptionForSelected();
// Flash::success(print_r($dataHolder)); // Data is correctly set
return $dataHolder;
}
public function getDescriptionForSelected() {
return [
['_name' => 'titre1', 'description' => 'description1'],
['_name' => 'titre2', 'description' => 'description2']
];
}
The function is correctly set, I made a Flash return to show the content of the dataHolder, but the repeater doesn't display any field:
[_offers_descriptions] => Array
(
[0] => Array
(
[_name] => titre1
[description] => description1
)
[1] => Array
(
[_name] => titre2
[description] => description2
)
)
Here is my repeater in the yaml:
_offers_descriptions:
label: 'Description des projets de maisons neuves'
span: full
cssClass: 'col-xs-6 tw-font-black'
type: repeater
dependsOn: selected_mixable_house_models
style: accordion
form:
fields:
_name:
label: Modèle
cssClass: 'tw-font-black tw-text-xl'
type: text
readOnly: true
description:
label: Description
span: full
cssClass: 'tw-font-black tw-text-xl'
required: 1
type: Backend\FormWidgets\RichEditor
size: large
Last updated
could it be because your field names start with an underscore, preventing the refresh somehow?
I thought of that me too but I tried without the underscore: same result.
The fact is I doubt what I want to achieve is possible with a repeater...
I tried to add 2 items in the repeater, display the result in flash to compare the dataHolder structure with the one I submitted: they are exactly identic.
Then I thought it was due to the refresh data which could not be created into the repeater if the repeater is empty. So I add 2 items, then submit the ajax call so the data are just "modified": same result.
Maybe check the source code for the repeater? Also for the Form Widget, I'm sure you'll find why this is not working as you'd expect.
It made me completely mad and it still goes on... I couldn't figure out why I can't just add some data to repeater.
So I tried another way: since I just want to add fields on my form when I check some checkboxes: 1 check = 2 fields (name and description) and I don't need the "add items" button, I tried a more appropriate way, with addFields on formExtendRefreshFields.
But of course, it still doesn't work, the fact is the documentation and source code doesn't say what should be returned from this function, its just saying "array|void", but array of what? and can't we just use $formWidget->addField()
since $formWidget
is passed to the callback? I tried to return:
- $fields array push with some new field
- the widget fields array with widget->addFields()
- the widget itself
- void
Here is where I went, no success but it's imo the closer approach I've been until now:
public function formExtendRefreshFields($formWidget, $fields) {
$formWidget->addFields([
'my_field' => [
'label' => 'My Field',
'comment' => 'This is a custom field I have added.',
],
]);
$formWidget->removeField('facade'); // Just to try another field function
return $formWidget->fields;
}
Any thought about that and why this still doesn't work?
Last updated
No idea but AFAIK, formExtendRefreshFields() does not expect a return value.
formExtendRefreshData() does
Thanks again for your time @mjauvin, it was well appreciated. I finally found a solution and made a pull request to benefit the whole comunity.
In the case where the PR were not merged, the need is to extend the Backend\Widgets\Form
class to ensure OctoberCMS trigger a full form partial refresh instead of just the dependsOn fields partial.
To do so I check if there is a form structure modification (added or removed field), if so, I added a condition so the form is fully refreshed:
$fieldsBeforeRefresh = $this->allFields;
$this->fireSystemEvent('backend.form.refreshFields', [$this->allFields]);
$fieldsStructureModifications = array_merge(array_diff_key($fieldsBeforeRefresh, $this->allFields), array_diff_key($this->allFields, $fieldsBeforeRefresh));
/**
* Does any fields has been removed or added?
*/
$formStructureModified = (bool)$fieldsStructureModifications;
/**
* If so, refresh the form
*/
if (empty($result) || $formStructureModified) {
$result = ['#'.$this->getId() => $this->makePartial('form')];
}
You can see the exact file modification on the pull request.
1-11 of 11