Item sets vary between returning an object and an array

Enonic version: 6.0.0
OS: Windows 8.1

If you define an item-set in a content type, it usually gets returned as an array. Naturally you might want to use stuff like .map() and data-th-each on said set of items. If an editor happens to just put one item in the item-set, the item-set is returned as that single object. This means you probably have to put something like

if(!Array.isArray(content.data.steps)) {
    content.data.steps = [content.data.steps];
}

at strategic locations in your controllers.

Is this intentional or a bug?

Would it be possible for item-sets with (maximum == 0 || maximum > 1) to always return an array of items, even if there is only one item added to the set? (I guess it’s kind of a developer quality-of-life thing).

1 Like

Hi

I believe this is intentional, as this as been like this since 5.0 (I will ask a backend developer to confirm this). Our consultants have handled this in the Util lib, similar to what you propose:

I have also asked for any input that could have more than one to return as an array. But the developers say they can’t do it because of schema-less data.

The data isn’t really schema-less though, even though the storage of the data might be, since Enonic has content types defining what is possible variants of data for a certain key. If you didn’t have to think about the edge cases you could probably wrap all item-sets in an array as long as the occurrence tag indicated the possibility of more than one item.

It might “open a can of worms” to start looking at the content type when returning data though, so I guess we will have to do the ol’ util.forceArray for now.

This is indeed intentional, as we initially had arrays for everything.
We discovered that this made simple code very bloated, and that most values are “non-array” - so we made the desicion to place functionality for array handling in a library (util as mentioned by @tlo above).

Developers should have control over what properties will be arrays and not - if you’re unsure you can force-array for everything.

Finally - using the content API, things are schema enforced as you say, using the node api however - it is not…

Ah… yea, regarding the schema-thing. We don’t store the schema - so the data might actually differ from your currently loaded schema, thus schema-less :smile:

I recently ran into this, and its pretty frustrating and very unintuitive.

As a developer you cannot control if you will get an array or not from a itemset, unless you set minimum occurrences to 2… which you probably dont want.

The resourceful consultants just solved this by always using the lib-util and the data.forceArray function. If you use this every time you work with <item-set> and/or when maximum > 1 then it will just work. It will always be an array.

It doesn’t fix the problem, but since this is so complicated to solve in the backend (making output json “aware” of its config schema) it’s worth getting used to this pattern.

https://github.com/enonic/lib-util/blob/master/src/main/resources/site/lib/enonic/util/data.js

I understand.
It just seems so wierd, unintuitive and hacky, so i wanted to bump the post :slight_smile:

The concept was primarily made for basic variables, so we would’nt force arrays on single valued properties - as you know this complicates things a lot in javascript. It might be reasonable to always have arrays on item sets, but I’m not convinced yet…