This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.

Maz
Maz

[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

mjauvin
mjauvin

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.

Maz
Maz

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: repeater bug

Facing that I tried to do another way... but didn't get it to work more than the dependsOn way.

Last updated

Maz
Maz

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

mjauvin
mjauvin

could it be because your field names start with an underscore, preventing the refresh somehow?

Maz
Maz

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.

mjauvin
mjauvin

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.

Maz
Maz

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

mjauvin
mjauvin

No idea but AFAIK, formExtendRefreshFields() does not expect a return value.

formExtendRefreshData() does

mjauvin
mjauvin

Forget my last comment, I remembered incorrectly.

Maz
Maz

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

You cannot edit posts or make replies: the forum has moved to talk.octobercms.com.