How do I enable a reapeat within a repeat without adding a variable for each child repeat?

I hope this makes sense!

I have repeat within a repeat to create a poll question and answer text fields in a form.

At the top level the repeat is to create a question to create the questions.
There is an answer repeat within this question repeat used to create an answer text field to create the answer options.

Like this

[Add question Button]

1. Question (repeat1)

[Add answer Button]

  • Answer (repeat2)
  • Answer (repeat2)
  • Answer (repeat2)

At the moment I am using a variable “Question” and “Answer” to progress the value of the variables +1 to add the repeat rows.

This is all fine at the question level, so every-time the “Question” variable + 1 it creates a new question text field row. Within this row is another repeat which allows you add Answer options.

However, when you add second question “question” variable progresses = “2” it works but the problem is that it pre-populates the “Answers” because of course it is using the same “Answers” variable so it will just add the number of Answer rows based on what that variable was set in question 1.

My question.

Other than adding additional variables for each answer set for each question, is there a way to create a a variable or similar option on the go so I can create independent answer sets without having to hard code a variable for ever answer set??

I think what I am asking is can I set a dynamic variable at each “Question” repeat level based on the row index as the assigned name?

Thanks!

Hi there @StevenM!

I hope life is treating you well!

Am a bit short of time to look at the full details of your example, but if I understand correctly, this is something I do with two data stores rather than with variables…

So adding a new question is done with a flow which creates the new question data store item and the appropriate number of answer data store items for your needs, each of which reference the $id or a manually created id of the respective question.

I can explain some more if you need it when am at my computer rather than replying on a little phone screen!

Best wishes,
Antony.

Hi @Antony

Getting there! I think :stuck_out_tongue_winking_eye:

If you could point me in the right direction it would be great, bit stuck on this one!

Thanks!

Steven

Hi Steven!

So something like this…

datastore questions
   question_id
   question_text

datastore answer_options
   answer_id
   question_id
   question_answer  (concatenation of question_id and answer_id)
   answer_text
[Add Question Button] dmx-on:click"questions.insert({question_id: questions.data.count()})"

variable this_question_id.setValue(question_id)
repeat questions.data
   <input id="this_question" ... dmx-on:update="questions.update({question_id: this_question_id.value}, {question_text: this_question.value})".../>
   [Add Answer Button] dmx-on:click"answers.insert({question_id: this_question_id.value, answer_id: answers.data.where(question_id=this_question_id.value).count(), question_answer: this_question_id.value+' '+answers.data.where(question_id=this_question_id.value).count()})"
   repeat answers.data.where(question_id=this_question_id.value)
         <input id="this_answer" ... dmx-on:update="answers.update({question_answer: this_question_id.value+'_'+answe_id}, {answer_text: this_answer.value})".../>

It’s the end of the day, so I may have some of the syntax a bit wrong! But here are the key points:

  • Datastores for questions and answers
  • In this simple example, question_id/answer_id are just the next sequential number from the existing count. You may need a .count()+1 depending how you work and something more sophisticated to insert and delete questions/answers.
  • You are updating the answer datastore on the value of question_id AND answer_id, and the only way to do that right now is to combine the two into another field question_answer. So if question_id=5 and answer_id=2 then question_answer=“5_2”.
  • Each datastore’s question/answer text is updated using dmx-on:update

Drop me a line if any of it is confusing! :slight_smile:

Good luck,
Antony.

1 Like

Great!

Thank you!

I have today to work on this so will let you know how I go. :grinning:

HI @Antony

How and where are you adding the variables to the repeats to capture the question_id?

Cheers!

This is what I am trying to create, and not sure this method will work with multiple questions?

Well this is a good question…

So part of your design will be how you manage the question_id… and it will depend on what functions you have such as the ability to insert / delete / manage the order of questions… the most important thing is that it is unique. I sometimes have a variable outside of the repeats called next_question_id which is questions.data.sort(question_id).last(1)[0].question_id + 1 (or something like that…) to return me the highest question_id plus one.

This variable you need as you have a fieldname called question_id in both questions and answers… so it is to make sure you are using the value in the outer loop.

I hope that all makes sense and answers your questions!
Antony.

You will also need this to save it all to the database…

Hi @Antony

Just checking but should I be using Flows for this?

Well I mentioned flows before because sometimes, when the design gets “real world”, it can be easier to put the on-click commands in a flow rather than listing them directly in the on-click entry for the button. You have all the power of if-the-else, variables etc to play with.

So basically the flow just allows you to do more clever things in your on-click.

But as far as my simple example is concerned, doing them directly in the on-click works just fine as there are only 1-2 commands to execute.

If i understand your idea correctly, here’s a little test page i created quickly, so you can play with it.

<body is="dmx-app" id="test">
    <dmx-datastore id="datastore1"></dmx-datastore>
    <dmx-datastore id="datastore2"></dmx-datastore>

    <div class="container pt-5 pb-5">
        <button class="btn btn-success mb-3" dmx-on:click="datastore1.insert({question: 'my question'})">Add Question</button>
        <div class="row" is="dmx-repeat" id="repeat1" dmx-bind:repeat="datastore1.data" key="$id">
            <div class="col-12 mb-4">
                <div class="d-flex justify-content-between">
                    <p>Question {{$index+1}}</p>
                    <button class="btn btn-danger btn-sm" dmx-on:click="datastore1.delete({$id: $id});datastore2.delete({parent_id: $id})">Remove Question</button>
                </div>
                <button class="btn mb-3 btn-sm btn-primary" dmx-on:click="datastore2.insert({answer: 'my answer', parent_id: $id})">Add Answer</button>
                <div class="row" is="dmx-repeat" id="repeat2" dmx-bind:repeat="datastore2.data.where(`parent_id`, $id, '==')" key="$id">
                    <div class="col-11 offset-1">

                        <div class="d-flex justify-content-between">
                            <p>Answer {{$index+1}}</p>
                            <button class="btn btn-danger btn-sm" dmx-on:click="datastore2.delete({$id: $id})">Remove Answer</button>
                        </div>

                    </div>
                </div>
            </div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF" crossorigin="anonymous"></script>
</body>

datastore1 schema:

datastore2 scema:

You can extend it as per your needs.
Let me know if that helps.

1 Like

That’s great @Teodor.

Can you remind me the difference between how $id and $index are assigned in a data store?

There is no $index in data store, $index comes from the repeat.

Oh yes! :rofl:

Thanks @Teodor

Much appreciated!!

Starting to gel.

If I understand this correctly, you can also just create a variable inside the repeat, and use that variable as the repeat expression for answer.
Not sure why is there a need for data store here.
Each variable created inside the question repeat, will be unique in its own scope.

Naming of input elements will have to be done carefully… so that it creates a repeatable structure on the server side when sent from POST.
There, just use nested repeat steps to insert into DB.

Thanks @sid

Can you show how you define the variable inside the repeat to do this?

    <dmx-value id="varQuestionCount" dmx-bind:value="1"></dmx-value>
    <div class="row">
        <div class="col-12">
            <button id="btnAddQ" class="btn btn-primary" dmx-on:click="varQuestionCount.setValue(varQuestionCount.value + 1)">Add Question</button>
            <button id="btnRemoveQ" class="btn btn-secondary" dmx-on:click="varQuestionCount.setValue(varQuestionCount.value - 1)" dmx-bind:disabled="varQuestionCount.value == 1">Remove Question</button>
        </div>
        <div class="col-12">
            <div id="repeatQuestions" is="dmx-repeat" dmx-bind:repeat="varQuestionCount.value">
                <h4>Question {{$index + 1}}</h4>
                <input id="textQuestion" dmx-bind:id="textQuestion{{$index}}" name="textQuestion[]" type="text" class="form-control">
                <dmx-value id="varAnswerCount" dmx-bind:value="1"></dmx-value>
                <div class="row">
                    <div class="col-12">
                        <button id="btnAddA" class="btn btn-primary" dmx-on:click="varAnswerCount.setValue(varAnswerCount.value + 1)">Add Answer</button>
                        <button id="btnRemoveA" class="btn btn-secondary" dmx-on:click="varAnswerCount.setValue(varAnswerCount.value - 1)" dmx-bind:disabled="varAnswerCount.value == 1">Remove Answer</button>
                    </div>
                    <div class="col-12">
                        <div id="repeatAnswers" is="dmx-repeat" dmx-bind:repeat="varAnswerCount.value">
                            <div class="col">Answer {{$index + 1}}</div>
                            <div class="col">
                                <input id="textAnswer" dmx-bind:id="textAnswer{{$parent.$index}}{{$index}}" name="textAnswer[]" type="text" class="form-control">
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

The name of the elements should be done carefully as that will define how you will insert this data on the API side.

1 Like

Great!

Thanks @sid

Learning lots!

Appreciated it. getting close to the desired result.