Gen
New Creator

Sorting an array by order of adding

Jump to solution

Somewhere between FirstSpirit 4 and 5 the default behavior for sorting of arrays changed.

We have a template for a form, and editors click the form elements to include them.  Items such as Salutation, Title, First Name, Last Name.  These items are checkboxes in the template.  The generated form, in 4.2, presented those items correctly in the order they were listed in the template.  The For-loop looks like this:

$CMS_FOR(myFor,stFields.toArray)$

    $CMS_SET(myVal,myFor.toString())$

    $CMS_VALUE(myVal)$<br>

$CMS_END_FOR$

For the purposes of illustration, stFields now contains:

1

2

3

4

5

In FirstSpirit 4.2, the code above listed the items in the order they'd been added to the array.

In FirstSpirit 5.1.507.70194, the code above lists the exact same items in this order:

3
2
1
5
4

In FS 5.2.717.75840 the items are listed

1

2

3

4

5

only if they are also numbered 1,2,3,4,5.  As soon as the values are words (salutation, title, etc.), they are listed in an order that we can't figure out: not alphabetical, not the order they were added, not by length... they came out 1,2,3,5,4 at one point.

Clearly back in 4.2 no sort command was necessary, and we have screenshots of the form having been generated as intended.

1. What changed?  (Is it the Java version or the FirstSpirit version?)

2. What kind of .sort command do we have to implement to get the items to be listed in the order they were added, without having to rename all our checkboxes?

0 Kudos
1 Solution

Accepted Solutions
mbergmann
Crownpeak employee

Hi Genevieve,

Hannes is right concerning the statement that the order is not guaranteed by definition and may be changed (theoretically even between subsequent calls).

The section of the ODFS cited by Fidel only states that the order of the entries is respected when displaying them in the form - but not when reading the checked values.

So basically what you have to do is create a "mapping" which is used to order the values depending on the order of the entries in the form definition.

If your INPUT_CHECKBOX has the name "st_checkbox", you can achieve that with the following code:

$-- first, get the option model containing the options from the form definition --$

$-- important: put the name of the INPUT_CHECKBOX in the .findEditor(...) call --$

$CMS_SET(set_optionModel,

  #this.template.gomProvider

  .findEditor("st_checkbox")

  .optionFactory

  .getOptionModel(#global,#global.language,false)

)$

$-- create a list of option values in the order like in the form definition --$

$CMS_SET(set_options,[0..set_optionModel.size()-1].map(x->set_optionModel.getElementAt(x)))$

$-- create a list of the selected checkbox entries ordered by their index in the form definition --$

$CMS_SET(set_st_checkboxSorted,st_checkbox.toArray.sort(x->set_options.indexOf(x))$

$-- now, instead of iterating through st_checkbox, just use set_st_checkboxSorted --$

$CMS_FOR(for_entry, set_st_checkboxSorted)$

  $CMS_VALUE(for_entry.key)$ <br />

$CMS_END_FOR$

By the way: I noticed you use .toString() to output the value where you should rather use .key because usually .toString() is intended to be used for stuff like debugging unless explicitly stated otherwise in the API.

Michael

View solution in original post

0 Kudos
4 Replies
tenter
I'm new here

Hi,

the checkbox component returns a set datastructure, which is unordered by definition. There's no guaranteed order and index access for elements in the set, which is why you should never rely on it, whether there are internal changes happening in FirstSpirit or not.

You could simply sort the array you get from the set via toArray. For example use Java's built-in Arrays.sort(array) in order to achieve an ascending numerical order. Since there really is no default order with sets, there's no chance to restore the old behaviour in any way, because it is undefined. You could only sort it afterwards, based on element content or name or something.

I'm afraid that you would have to use alternative input components otherwise.

Could these be solutions for your problem?

Regards,

Hannes

0 Kudos

Hi Hannes,

Laut Dokumentation help/odfs/vorlagenentwick/formulare/eingabekomponen/checkbox/index.html?#s0_11 soll die Reihenfolge der Einträge in der Reihenfolge angezeigt, wie sie im Formular über die Definition mittels ENTRIES / ENTRY vom Vorlagen-Entwickler vorgegeben ist.

Was hier nicht der Fall ist.

Viele Grüße,

Fidel

0 Kudos
mbergmann
Crownpeak employee

Hi Genevieve,

Hannes is right concerning the statement that the order is not guaranteed by definition and may be changed (theoretically even between subsequent calls).

The section of the ODFS cited by Fidel only states that the order of the entries is respected when displaying them in the form - but not when reading the checked values.

So basically what you have to do is create a "mapping" which is used to order the values depending on the order of the entries in the form definition.

If your INPUT_CHECKBOX has the name "st_checkbox", you can achieve that with the following code:

$-- first, get the option model containing the options from the form definition --$

$-- important: put the name of the INPUT_CHECKBOX in the .findEditor(...) call --$

$CMS_SET(set_optionModel,

  #this.template.gomProvider

  .findEditor("st_checkbox")

  .optionFactory

  .getOptionModel(#global,#global.language,false)

)$

$-- create a list of option values in the order like in the form definition --$

$CMS_SET(set_options,[0..set_optionModel.size()-1].map(x->set_optionModel.getElementAt(x)))$

$-- create a list of the selected checkbox entries ordered by their index in the form definition --$

$CMS_SET(set_st_checkboxSorted,st_checkbox.toArray.sort(x->set_options.indexOf(x))$

$-- now, instead of iterating through st_checkbox, just use set_st_checkboxSorted --$

$CMS_FOR(for_entry, set_st_checkboxSorted)$

  $CMS_VALUE(for_entry.key)$ <br />

$CMS_END_FOR$

By the way: I noticed you use .toString() to output the value where you should rather use .key because usually .toString() is intended to be used for stuff like debugging unless explicitly stated otherwise in the API.

Michael

0 Kudos
marza
I'm new here

Hello Genevieve, 

do you need further help or did Michael's reply already help you? If so, it would be great if you marked his reply as "correct answer" so that other community users find the solution easily. If you have already found a solution by yourself, it would be very kind of you, if you posted it here. 

Best regards

Marian

0 Kudos