Is it possible to display form results in admin or a frontend page?

Hello Grav Community!

I’m new here and i’m currently doing a small website with some pages and forms.

I have a form that asks visitors to subscribe (like a newsletter for example but with more fields).
For this form I would like to be able to see the results either in the admin or on a specific front page.
It’s possible ? If yes, can you guide me on the procedure to follow?

Thanks for your help!

@eskah,

Two options:

  • Have a look at FlexObjects. Chapter Introduction shows an example.
  • Or get some DIY inspiration from plugin Comments which lists data from /user/data/comments/[pageslug].yaml into Admin and front-end.

@eskah

Also look at the save-process on Frontend Forms | Grav Documentation

        save:
          fileprefix: feedback-
          dateformat: Ymd-His-u
          extension: txt
          body: "{% include 'forms/data.txt.twig' %}"

You can customize the forms/data.txt.twig according to your needs. You can find the according documentation on Reference: Form Actions | Grav Documentation

Thanks for your help guys!
@pikim i’ve already have the data saved in a txt file but is not an effective solution for viewing the results.
@pamtbaau i think i’m going to do it with flexobjects, it seems the best option. My need look similar with the contacts directory with more informations!

But now I have another problem, there is no part on flex forms in flexobjects documentation ? Can i connect any form to my contacts directory in flex objects ?

@eskah,

But now I have another problem, there is no part on flex forms in flexobjects documentation ?

That’s because there are no “flex forms”. Your form saves its data into a file and FlexObjects will pick up the contents of the file.

ok got it but how? There is a documentation somewhere for an example?

Oh i think i’ve the solution… The save method works for save the data in right place.
But (yes another problem…) how can i save in json format? For now it’s just a .txt file…

@eskah

I see. When you find a solution for storing the frontend form values in a json file I would be very interested in it. I could use it for my own page where people can register for a specific event and I could view the participants, then.

For testing purposes I already ported the guestbook plugin to flex-objects. But there I also would need to be able to store frontend form data (not on admin interface) as json.

Edit:
This one may help me: Json filetype in (Contact)form with flex - #3 by epb

Unfortunately it doesn’t work when adding data to a single file, but only for one dedicated file per entry.

@eskah,

I have no prior hands-on experience with FlexObjects, but the following seems to be working:

  • Follow the Introduction on FlexObjects
    • Enable ‘Contacts’ directory in FlexObjects plugin.
    • Install sample data.
    • Have a look at the Contacts in Admin
  • Create a plain plugin using $ bin/plugin devtools new-plugin.
    • Subscribe to event onFormProcessed
    • Add function onFormProcessed
      public function onFormProcessed(Event $event)
      {
        /** @var Form */
        $form = $event['form'];
        $action = $event['action'];
      
        if ($form->name == 'contacts' && $action == 'addContact') {
          /** @var Flex */
          $flex = $this->grav['flex'];
          /** @var FlexDirectory */
          $dir = $flex->getDirectory('contacts');
          /** @var FlexObjectInterface */
          $object = $dir->createObject(
            [
              'first_name' => $form->data['first_name'],
              'last_name' => $form->data['last_name'],
              'email' => $form->data['email'],
            ],
          );
          $object->save();
        }
      }
      
  • Create a page with the following form:
    form:
      name: contacts
      fields:
        first_name:
          type: text
        last_name:
          type: text
        email:
          type: email
      buttons:
        submit:
          type: submit
      process:
        addContact:
    
  • Browse to the new page, enter some data and save the form.
  • Refresh the Contacts listing in Admin. The form’s data should be listed.

Note:

  • Off course, you will have to create your own Subscribers flex definitions using smart copy/paste of Contact definitions.

@eskah

I started to revise the guestbook plugin to use flex-objects instead of the conventional admin interface. You can find a first version on GitHub - pikim/grav-plugin-guestbook: Grav Guestbook Plugin. It already reads and displays existing entries and allows their deletion. Also new entries can be added. The included flex-blueprint is based on the one from the contacts example, so you can compare the both and see what has (to be) changed.

Currently, writing the form data into the json-file doesn’t work. I tried it with

{% macro render_field(form, fields) %}
{% set array = [ ] %}
{% for index, field in fields %}
{% set key = field.name %}
{% set value = form.value(field.name) %}
{% set array = array|merge({ (key): value}) %}
{% endfor %}
{% set array = array|merge({ "moderated": 0}) %}
{% set code = random_string(15)|md5 %}
{{ { (code): array }|json_encode|raw }}
{% endmacro %}
{{ _self.render_field(form, form.fields) }}

as standard save/add action which creates nicely formatted json, but appends each entry as a root entry. So, in the end the json file has an invalid format and a custom action like the one above from @pamtbaau is necessary.

@pamtbaau i’ll keep your solution for plan B.

For now i’ve tried the @pikim solution and i think it’s almost good…

But when i submit data with the form, the data in my json file still null… :

{“09a2261bee76488a0649f65117223693”:{“columns”:null,“moderated”:0}}

How can i “subscribe to event”? And where i paste this code? Sorry i’m not really at ease with php …

@eskah

Search for onFormProcessed in guestbook.php of my repo above. This is the function being called when the form is transmitted. You’ll have to put your custom code to store data there, as the standard save/add action doesn’t work with json files because of the root brackets {}.

You can find some documentation here: Reference: Form Actions | Grav Documentation

I think there is some mistake in the flex-blueprint or the form page which leads to columns=null. Try to output some debug information at the code section where it’s created.

@eskah,

In function onPluginsInitialized, add the subscription as follows:

// Enable the main events we are interested in
$this->enable([
    // Put your main events here
    'onFormProcessed' => ['onFormProcessed', 0]
);

@pamtbaau

Do you know why in some older plugins the subscription is split into getSubscribedEvents and onPluginsInitialized? Was this the former state of the art?

@pikim, I’m sorry to say that I’m not a fan of your forked Guestbook plugin. It is based on a 7 years old plugin using a structure from the early days of Grav. Please have look at how a proper plugin skeleton is generated using $ bin/plugin devtools new-plugin.

Just see our posts have crossed…

Was this the former state of the art?

Yes.

@pamtbaau

I already used the plugin on my site as it is, but the admin interface doesn’t work. So it was just a first draft to see whether I understand the principle of flex-objects as I may have some more use cases in the future. I’ll think about updating it to a recent skeleton.

it is possible i’ve null in results because of my form?

I’ve multiple columns inside “fields” like that :

form:
name: flex-objects
fields:
columns:
type: columns
fields:
column1:
type: column
classes: ‘flex flex-auto justify-center gap-10’
fields:
my fields

@eskah, Please help the community help you…

Formatting:
If the layout of your form is as you’ve shown, it is incorrect… If the form definition is not as shown, then please add some proper formatting:

  • we might then see if there are issues with the form definition.
  • and as a courtesy to the reader. Should the reader put effort in understanding the form, or should the author put effort in showing a proper form definition?

Context:
There should always be some context.

  • Is this a front-end form definition, or a form definition inside a flex-object blueprint, or …
  • If it is a font-end form, how is the form being processed:
    • Using a save action?
    • Or a custom action processed by a custom plugin?

Suggestion, if this is a front-end form and you are using a custom plugin to process the form, what are the values of $form->data['your-field-name']?

yes obviously i forgot some context… My apologies for this…

Here is some more informations about what i need to do :

I’ve one page (homepage) who contains some sections with the last one is a form section. This form is used for register people who participate at the event.

For now i’ve no custom plugin to do this, it’s juste a form with save action (see in md below)

Here is the correct md file for this page :

---
body_classes: "modular header-image fullwidth"
menu: Home
content:
  items: "@self.modular"
  order:
    by: default
    dir: asc
    custom:
      - _intro
      - _ceremonie
      - _reception
      - _countdown
      - _contact
title: Home
onepage_menu: true
by: default
dir: asc
form:
  name: flex-objects
  fields:
    columns:
      type: columns
      fields:
        column1:
          type: column
          classes: "flex flex-auto justify-center gap-10"
          fields:
            - name: presence
              default: "yes"
              label: Presence
              display_label: false
              type: radio
              options:
                "yes": "Je serai présent.e"
                "no": "Je ne serai malheureusement pas présent.e"
        column2:
          type: column
          classes: "flex flex-auto justify-center gap-10"
          fields:
            - name: last_name
              label: Nom
              type: text
              placeholder: " "
              validate:
                required: true
            - name: first_name
              label: Prénom
              type: text
              placeholder: " "
              validate:
                required: true
            - name: email
              label: "Adresse email"
              placeholder: " "
              type: text
              validate:
                required: true
        column3:
          type: column
          classes: "flex field-yes flex-auto justify-center gap-10"
          fields:
            - name: more
              label: "Invités supplémentaires"
              type: select
              options:
                - 0
                - 1
                - 2
                - 3
        column4:
          type: column
          classes: "flex field-yes hidden more-fields more-fields-1 more-fields-2 more-fields-3 flex-auto justify-center gap-10"
          fields:
            - name: last_name_1
              label: Nom
              type: text
              placeholder: " "
            - name: first_name_1
              label: Prénom
              type: text
              placeholder: " "
        column5:
          type: column
          classes: "flex field-yes hidden more-fields more-fields-2 more-fields-3 flex-auto justify-center gap-10"
          fields:
            - name: last_name_2
              label: Nom
              type: text
              placeholder: " "
            - name: first_name_2
              label: Prénom
              type: text
              placeholder: " "
        column6:
          type: column
          classes: "flex field-yes hidden more-fields more-fields-3 flex-auto justify-center gap-10"
          fields:
            - name: last_name_3
              label: Nom
              type: text
              placeholder: " "
            - name: first_name_3
              label: Prénom
              type: text
              placeholder: " "
        column7:
          type: column
          classes: "flex field-yes flex-auto justify-center gap-10"
          fields:
            - name: alergie
              label: "Préférences alimentaires"
              type: select
              validate:
                required: true
              options:
                aucune: Aucune
                vegetarien: Végétarien
                vegan: Vegan
                hallal: Hallal
  buttons:
    - type: submit
      value: Envoyer
  process:
    - reset: true
    - message: "Merci pour votre réponse !"
    - save:
        filename: contacts.json
        dateformat: Ymd-His-u
        extension: json
        body: "{% include 'forms/data.json.twig' %}"
        operation: add
custom:
  - _intro
  - _ceremonie
  - _reception
  - _countdown
  - _contact

---