0
votes

I'm on a mission to create a dynamic form system. We are using another CRM type platform which has an API that makes it possible to get a form with fields through API.

I have followed the apostrophe-pieces-submit-widgets tutorial to do this but I have hit some brick walls.

I am transforming the fields from the other platform to correct schema fields without a problem. The first load after an app restart is good. I save the fields from the other platform in the aposCache collection so I can load them faster. This works fine.

Problem 1)

When the fields (form) is updated in the other platform, that platform sends a web hook call, which I have configured in a route inside the widgets which then does an internal Apostrophe call to the piece module, which recaches and re-generates the fields by emptying options.addFields.

It seems, through debugging, that I am getting all that right, but I am struggling with getting this new schema fully applied for the next load without reloading the app. My initial load works fine (including posting data back to the CRM), as I mentioned, but is also doing things in beforeConstruct and construct. My internal call from the widgets happens to a function inside the construct. I'm thinking it's about self.load etc. but I am really stuck making this work.

Problem 2)

Part of the feature list is that once a form is filled in, I then want to send an email to both the site owner and the person that filled in the form, using apostrophe-email which works fine with a template inside the afterInsert of the piece module.

But I want this to be more dynamic and possible to control by the site manager (non dev person). For that I added various fields to the widget, which the site manager can fill in and by that modify the mails to his liking. The problem is, that the mail is sent in the afterInsert part of the piece module, and that module seems not to know what content I have inside fields in the widget that submitted it. Any way to load that from inside the afterInsert?

Problem 3)

The CRM platform has "apps". This is forms with fields, which can be web forms, and those forms can be loaded through API. The idea is that on just one site, you can have 2-3 or 10 forms with different fields, connected to different apps in the CRM platform.

The idea is that the site manager can copy/paste two credentials from the CRM platform into the widget and with those two credentials, Apostrophe will fetch the fields and generate the form, and post back to that app when the user submits data. This means I need to be able to have several dynamic schemas, without having more than my two (or if more is needed for this) modules that runs this, the piece module and the piece-widget module. As it appears to me now, my current approach is one site, one form total. Adding multiple widgets, will overwrite all the rest. As I am stuck in other parts, I have postponed worrying about this a bit, but it may be that this will not be possible, without a dev creating another piece and/or widget module on the site, extending the base modules, but that would take away the dynamics in the this and require dev time to add a new form on a site, which we would like to avoid.

Appreciate any hints on either or all of the above challenges I'm facing and thanks again for a great platform!

1

1 Answers

1
votes

The more I think about your problem, the more I think that backing it with apostrophe-pieces is a "force fit." apostrophe-pieces are designed to "boot up" with a particular schema that stays in place, or perhaps changes occasionally if you get clever by modifying self.schema and manage to push that to all processes, but in any case a piece has one schema at a time.

And, you don't even need storage for the submissions in Apostrophe, from the sound of it. So pieces aren't paying for their weight here.

A better fit would be to use the apostrophe-schemas module directly and implement your storage, if needed, in a collection of your choice or just send the data straight back to the other app on submission. This frees you from the life cycle of apostrophe modules and its relationship to schemas staying the same. One module can then implement many "apps."

On the server side, you can just generate a schema array entirely yourself, or use apos.schemas.compose to handle an object with addFields and arrangeFields options, etc. and return a schema array, at any time. And you can use apos.schemas.newInstance to get a new object with default values per the schema given to it.

You can then use apos.schemas.convert to accept submissions, with the data type parameter set to form. Then you have a clean object to insert into your own collection or send to the API as you see fit.

On the browser side, you can use apos.schemas.populate to fill a form with current (including default) values, and apos.schemas.convert to prep an outgoing submission in the format that apos.schemas.convert on the server side expects.

You can still hook up the plumbing for all this with apostrophe-widgets. It just won't be part of the schema of the widget itself - that will just have the administrative fields you mentioned. (As you know, you definitely need to use the playerData option to that module to avoid those being pushed into browserland except for editors.)

To actually generate the markup for the form, this is the critical bit:

{% import "apostrophe-schemas:macros.html" as schemas %}

<div class="my-form">
  {{ schemas.fields(data.widget._schema) }}
</div>

So what's with "data.widget._schema"? What I'm envisioning here is that in the load method of your widget module you'll be determining the schema by talking to your other app's API. At that point you would attach it to the widget object as _schema, with the leading underscore so it doesn't inadvertently wind up in the database at any point.