How Can I Pass an Array to a Server Action to Write to the Database?

I am creating a booking form. It can manage up to 6 attendees, and each attendee can be asked any number of questions.

I want to find the most efficient way to write the question responses to the database. The responses have the following fields:

contact_id (integer)
question_id (integer)
response (text paragraph including line breaks)
comment  (text paragraph including line breaks)
various number fields (integer)

and I expect to have 10-100 individual responses which need writing to the database as individual rows to a table called responses.

I have been planning to store the responses on the client side in a Data Store ds_responses as they are entered by the user.

I would like to minimise the amount of database resources that are used in getting this done.

These seem to be my options, along with some questions:

  1. Write a flow that repeats through the records in the ds_responses Data Store and calls a server action to save each response individually.
    This I can do but seems expensive in terms of server and database usage.

  2. Pass the entire contents of the ds_responses Data Store to a single server action call and then either repeat through the records or send the whole record set to a stored procedure.
    This seems more efficient.

QUESTION - How can I pass the entire contents of the ds_responses Data Store in one go? Can I do it in some way via JSON? What Wappler feature would I use to do this?

Best wishes,
Antony.

Hi Antony

I may have misunderstood your task, but if I understood correctly, I would send all the responses in one form as an array with an unlimited number of responses.

I helped Neil with a similar task: Need help with Multiple UPDATE and INSERT Server Action Steps

Unfortunately, I closed the domain where there was a demonstration of how it looks live. But if you describe it in words, this is a form in which you can create any number of inputs. And when you send it to the database, an array is sent, which is then stored in the database.

PS Posted on your domain for tests. Domain without ssl, but enough for demonstration. Here’s what it looks like: https://howitisdone.cy65837.tmweb.ru/arrayinsc.html

1 Like

Just a quick thought, if you’re concerned about storing 10’s or 100’s of rows per question/attendee, you could store their response as JSON in a single row in your db instead

Thanks for your responses folks! :slight_smile:

@max_gb, Maybe a dumb question, but how do I create a JSON format from all the data in the data store?

@Antony - I’m working on a complex query at the moment to pass data (29 + filters, each can have multiple data points) via a SC form to an API. So, while not exactly the same - the intent of passing data from a form to SC so you can then action has similarities and you might find the following useful, and a way to avoid using side data store.

SC forms can output as nested JSON depending on how you name the input.

Take a look at:


and
https://www.w3.org/TR/html-json-forms/

I’d say you could nest the questions and answers using the implementation options used in w3 examples above, create the nested $POST parameters and then use that data how you wish for repeats / inserts.

Okay folks… thanks for your input so far!

So I am close, but not quite close enough for it to work… can any of you show me where I have gone wrong?

So here is my (updated) responses data store structure:

attendee_number
response
question
comment

Here is a hidden field of my form I am submitting:

<input id="h_responses_question" name="responses[question]" class="form-control" type="hidden" dmx-bind:value="responses.data.question">

And here is the post variable structure of my server action:

responses

But when I output from the server action responses[0].question then the value is null…

How should I change the hidden input to pass the values of the data store through?

did you try serialize / deserialize (custom formatter ) ?

No, I have never heard of those… how do you suggest I use them?

I assume you have a hidden form field per variable? If that’s the case you’ll need to bind the name of the field, for example:

<input dmx-bind:name="responses[{{index}}][attendee_number]">

Server Side Serialize

<?php $data = serialize(array("Red", "Green", "Blue")); echo $data; ?>

you can use server side with custom formatter

example output

Hi there @max_gb

Well I really don’t know if I need a hidden field per variable or not, but after trying lots of options that is the direction I am going in unless someone shows me I can use just one field for the whole array.

In my case, my form is not within a repeat loop (which creates a $index). I just have one hidden form with hidden inputs which I submit with a formname.submit() command.

I am just wanting to output the entire contents of the responses data store, so responses.data.

So I can try your example, but I’m not sure where the value of {{index}} is going to come from.

But yes, I realise do need to have dmx-bind:name= rather than just name=. Thanks for getting me straight on that!

@s.alpaslan, I’m not sure how your last message helps me… my issue is how to specify the dmx-bind:name="" field in my HTML in order to get the data store to pass to the server action.

@patrick, do you know how I can specify the name field in my form input to pass my array over to the server action?

:slight_smile: ohh ok! I got you wrong.

Hi Antony

In the example that I gave you at the very beginning, I parse the binding of a dynamic name for passing an array.

Hi Antony,

I think I’m with you now. So if you’re expecting to receive an array (responses) on the server side you’re going to need to use a repeat to cycle through the multiple records from datastore, that’s why $index is used to determine the record (repeat) id.

If it’s just a single record (response) being posted to your server action then all you need is the variables in your POST globals.

Edit: It’s very similar to the shopping cart scenario where you may have multiple cart lines in datastore that you need to insert to the db, and each line contains variables such as product_id, product_price, qty, etc…

Aaaahhh… so you are saying that I need a flow with a repeat and to make a separate submit to the form for each record in the data store?

I was hoping to just make one call to the server action and to send it everything at once.

I know I can do that by just encoding the content into a complex text string such as:

1|response1|444|comment1^
1|response2|445|comment2^
2|response3|444|comment3^
2|response4|445|comment4

and then use .split('^') and .split('|') to create my arrays within the server action.

I was hoping to find a Wappler way of doing it without needing to resort to creating my own encoding language!

You can do this using Wappler and send the entire array of responses in one action.

Great!

So what do I put in the name attribute of my input?

Where responses.data is my data store, I have tried these two options and neither of them work…

<input id="h_responses" dmx-bind:name="responses" class="form-control" type="hidden" dmx-bind:value="responses.data">
<input id="h_responses" dmx-bind:name="[responses]" class="form-control" type="hidden" dmx-bind:value="responses.data">

With the server action post inputs like this…

responses

Static input names (required):

name=“responses”
name=“attendee_number”
name=“question”
name=“comment”

Dynamic input names (required):

dmx-bind:name=“responses[{{$index}}][responses]”
dmx-bind:name=“responses[{{$index}}][attendee_number]”
dmx-bind:name=“responses[{{$index}}][question]”
dmx-bind:name=“responses[{{$index}}][comment]”

And even better, if you carefully study the materials on the link from my first post. :wink:

There I am solving a task very similar to yours.

Thanks for this! :slight_smile:

So in your example, do I have 8 hidden inputs then?