Repeater field bug

Hi,

Try this:

  1. just 3 records in repeater
  2. delete middle record
  3. add some record
  4. save

Repeater saves only first and last record.
Doesnt work in all my sites.

What version of October CMS are you using?

Ive used the latest version 3.7.11

Do you mean it only happens in some of your sites?

No in all sites is a problem. Looks like JS is getting wrong index - same as last record on newly created record. This happens after deleting record before creating new one.

I also noticed strange behavior, if you add a new item and then change its position in the list, the data is not saved correctly. Worked in conjunction with Repeater + ExpandoModel

@daft I can confirm this - we have the same problem using Group Repeater.

It can be reproduced like this:

  • delete any existing item (but not the last one)
  • add a new item (will be placed at the end)

Newly added (last) item will have the same ID as the previous last item (now second from the end).

When saved, only the newly added item is saved and the other is lost.

This bug is not present in OCv1

Hey @jan-vince

I can’t reproduce this in the demo theme (About Page management area). Does it happen here?

Hi @daft,

Group Repeater in Demo theme works (even when changed to span: large so the Add button is above items).

I have tested Group Repeater with Static Pages and with my plugin - both have the same problem - when any of inner items is deleted the newly added item has a wrong index.

Only difference I have noticed so far is that with Demo theme the repeater <li> items have attribute draggable='false'. When used with Static Pages or plugin they don’t have this.

It may be something related to the relation repeater vs JSON repeater modes. That is the difference between the two.

Hi @daft,

I’ve been looking into what the problem is and I came up with this:

This is related only to JSON repeater.

The problem is caused by a method of retrieving next available item index.

In JSON mode, onAddItem() method simply checks the array items count without testing actual highest index number.

So when you remove any of (but not last) repeater item and add a new one, the new one get a duplicate index.

In this state when you save repeater you will lost data of item with duplicate index.

So some kind of reindexing is missing when the onRemoveItem method is called in JSON mode.


@daft will you have a time to look at this?

I will try to find a solution but right now this is beyond my skills.

A lot of our clients complain about this because we still use the JSON mode repeater in static pages, so it’s quite important to me.

Thanks, Jan

1 Like

Moving through a code I have found that a Repeater.php method getNextIndex() expects that a JSON repeater returns array with repeater item indexes to be array keys.

But this doesn’t happen as an getLoadValue() method in FormWidgetBase class returns array with gradually increasing keys from 0 for (JSON) repeater.

I can’t spend more time on this so I fixed this with a little hack - when not in Relation mode I set the next index to be a UNIX timestamp. So every new repeater item get unique index even when you remove items repeatedly.

With save and reload, (JSON) repeater widget set indexes correctly beginning from 0.

Hope for a better solution (@daft) but for now this is working :slight_smile:

File:
modules/backend/formwidgets/Repeater.php

Changes:

    /**
     * getNextIndex determines the next available index number for assigning to a
     * new repeater item
     */
    protected function getNextIndex(): int
    {
        $data = $this->getLoadValue();

        // For JSON repeater set new item index as UNIX time to be sure it will be unique
        if(!$this->useRelation) {
            if (is_array($data) && count($data)) {
                return (time());
            }
        }

        if (is_array($data) && count($data)) {
            return max(array_keys($data)) + 1;
        }

        return 0;
    }

1 Like