Check rows in repeater for duplicates



Hey, I have a table (repeater) with rows. These can be added or deleted (default). In the rows are only checkboxes. I would need to check these for duplicates… i.e. the same checkboxes must not be selected in 2 or more rows. In this case the affected lines should be marked red. I have attached screenshots to show the correct behavior and an .rp file with my attempts…

In a column also the case must not occur that no box is selected … but this works :slight_smile:

Thanks a lot

rowcheck.rp (133.3 KB)


@olli, could you please explain a bit more? I don’t understand the rules defining “duplicate rows”. If each row must have different checkboxes selected, then why wouldn’t rows 1, 3, 4, and 6 also be red? They all have identical checkboxes (all checkboxes) selected, so they would be duplicates, correct? I also don’t understand why a newly added row defaults to all checkboxes selected. What is the intent of the “Check entries columns” button?

In general, your approach looks very complicated and likely overly so. Also, using a ton of global variables adds complexity and likely not the best idea. The more complicated things are the more chance for mistakes and the harder it is to debug.

Off the top of my head, I would recommend using a hidden widget in the repeater cell, or a column in the dataset, to represent the state of all checkboxes (in a given row) with a single number, one digit per checkbox. This will make it much easier to test for duplicate rows.

  • Using your screenshots above, there are 9 checkboxes per row, so a 9-digit number
  • Row 1 would be: 111111111
  • Row 2 would be: 010110100
  • When a checkbox is changed it can automatically update its position value in this number via its Selected or Unselected event. Or, you could build this into the repeater’s Item Loaded event.

You could also have a column in the datasheet to represent “duplicate”. If its value is true, show the red background. To test for duplicates it might be easier to use filters to easily and quickly show duplicate rows, update all visible rows to “duplicate” status, then remove the filter. That should likely simplify and reduce your interaction code and logic.


oh, yes right, the screenshot is of course wrong, sorry.
The ones not highlighted in red should not have the same selection…
I already have the hidden widget, at the moment it saves true or false… true false true true true false etc…
Can I also change to 1 and 0, is perhaps better :slight_smile:
That at default everything is checked is not so important … :slight_smile: :slight_smile: What is difficult for me right now is the comparison of lines and to react in the case that 2 or more are equal. Can you explain the filters a little more? Sounds good so far, but I have not done anything with them yet…

Thank you already



I started making a demonstration of my approach and realized I didn’t really need filters. Determining duplicates can be done with the Update Rows action and same kind of rule used in a filter.

See the “check with button (2)” page in this updated .rp file
rowcheck.rp (188.0 KB)

Essentially my solution uses one datasheet column with one number–a kind of “numeric string”–to represent the states of all checkboxes in a row. It makes it much easier to compare two or more rows to see if they are duplicates–the same states for all checkboxes in those rows. The tradeoff is a bit more complicated string logic in the repeater’s Item Loaded event to set the selection state (checked, unchecked) for all the checkboxes. However, it is straightforward and the result is still less complex than your initial Item Loaded conditional cases.

Here is the datasheet for my repeater:

  • I kept your “num” and “studyDescription” columns
  • I collapsed the 9 “option” columns to one “options” column (with a 9-digit number where each digit represents the state of the corresponding checkbox; and all unchecked by default. To show them all checked by default, change the entry to “111111111”)
  • I added a column, “duplicate” to track which rows match other rows
  • I added a column, “ref” to track the current “reference row” where say row 1 is tested against all other rows, then row 2 is tested against all other rows, etc.

In the Item Loaded event, the “secret sauce” for setting the checkboxes uses a built-in method (function) named charAt() which extracts a single character from the string in the “options” column. You can find this function under the “String” category when you click on “Insert Variable or Function” in the fx “Edit Text” dialog:

Additionally, you can learn about all these built in functions by Googling them. For example, search for “javascript charAt()” …Or alternatively, whatever solution you are trying to do, like “javascript get single char from string”.

When a checkbox is clicked it can likewise set (change) its corresponding character in the options string. However, when a checkbox is in a repeater and tries to update the repeater based on its selection state things don’t work as you’d expect. I think it is a kind of conflict between the checkbox changing itself (unchecked to checked) and updating its own row in the repeater datasheet. So, I placed a hotspot in front of each checkbox that updates the rows only …then the Item Loaded event alone sets the checkbox. You can inspect the interaction code for the hotspots to see how this is done with the .substring() function.

In the repeater cell I removed your hotspots and hidden widgets. I added to temporary widgets to show the value of the “options” string and the “duplicate” value for each row. You can delete or hide these once you see how they work.

I hid your “check entries rows” and “check entries columns” buttons as they are not needed. I put the latter button and the “Add” button in a dynamic panel so they can be moved together when the repeater grows/shrinks–so they always appear below the repeater. To do this easily I also placed the repeater in a dynamic panel and use its Resized event to correctly place everything below it.

I removed all your global variables and replaced them with these:

  • referencerow : the current row being tested against, represented as its “options” string
  • checkCount : tracks the remaining number of rows to be tested
  • duplicateCount : tracks how many rows are duplicates of the reference row

To make things more efficient and flexible, I created a few “subroutine widgets” that can be repetitively called in recursive fashion–essentially once for each row in the repeater. These “subroutines” are dynamic panels with two blank states. When the state changes it performs its function. So, when the “Check entries” button is clicked, it initializes things then “calls” or fires the “Test Rows” subroutine. For good measure, it disables itself so it can’t be clicked again while the row tests are being processed.

  • Test Rows

    • Sets the current reference row in the repeater
    • Waits a tiny bit to ensure the repeater is updated before trying to update it again
    • Finds and updates all duplicates to this row, if any
      • The algorithm, or rule, for this is:
        [[Item.options == referenceRow && Item.ref != 'true']]
      • This highlights all rows matching the reference row but not the reference row itself. This is so there would be no rows highlighted if no duplicates. Otherwise, the reference row would be highlighted even if no duplicates found.
      • In the repeater’s Item Loaded event when the Item.duplicate column value is greater than zero it updates the duplicateCount variable–for the current reference row only.
    • Then fires “Cleanup Rows”
    • Else if no more rows to be tested, it enables the “Check entries” button and finishes.
  • Cleanup Rows :

    • If one or more duplicates are found, it then updates the reference row to mark it as a duplicate too
    • It decrements the checkCount value
    • It calls the “Test Rows” subroutine, so the next reference row can be tested
    • If no duplicates found for the current reference row, it just moves on–no repeater changes needed


Hello mbc66,
wow, that’s awesome :+1: … many many thanks
This is so in fact much clearer and I have learned a lot with your help, thanks for that.
And then also explained in such detail, really great :+1: :+1:
I can only thank you again for the help

Best regards


one more quick question…
Is it possible in your implementation to check a column to 0. That is, in a column no option may be 0…

With my thousand global variables I had managed it once :-), but here I somehow do not manage it anymore…


Thank you already


Hey, I have now solved it (again) with global variables…
So the perfect solution of mbc66 for the rows and my non-perfect solution for the columns…

Best regards