Skip to content

Demo Silverstripe and JavaScript sources for Lightning Talk "FormField Mini Apps" at StripeCon EU 2022

Notifications You must be signed in to change notification settings

PlasticStudio/StripeConEU-2022_LT-FormField-Mini-Apps

 
 

Repository files navigation

FormField Mini Apps

Watch the Lightning Talk on Youtube 📺

Demo repository for Lightning Talk "FormField Mini Apps with the JavaScript framework/lib/style of your choice" @ StripeCon EU 2022 in Stockholm.


[tl:dr]

You can solve complex workflow and UX use cases with JavaScript-powered Silverstripe FormFields (or Mini Apps).

Advantages:

👍 Can be used within Silverstripe EditForms

👍 Full flexibility when talking to async APIs

👍 Hydrate Mini App with "backend data" (e.g. user id, api key, ...)

🤯 Not forced to use jQuery Entwine or React

Recipe

1. Create your JavaScript app

Use Vue, Angular, Svelte, ... or even just plain Vanilla JavaScript. The sky is the limit. The official recommendation is to create it in the client/ directory of your project/module:

"More complex projects can alternatively contain frontend assets in a common client folder"

Make sure that single files are being generated for your fields/Mini Apps.

A vite-generated Vue app is used in this demo.

2. Wire your JavaScript app to Silverstripe

My recommendation is to create a custom FormField as a descendant of LiteralField. The following shows a somewhat generic solution.

<?php

namespace L51\Sandbox;

use SilverStripe\Forms\LiteralField;
use SilverStripe\View\Requirements;

class AppField extends LiteralField
{
    public function __construct($fieldName, $appName, $payload = [])
    {
        Requirements::css('app/client/dist/style.css');
        Requirements::javascript("app/client/dist/$appName.js");

        parent::__construct(
            $fieldName,
            "<div
                id='AppField_$fieldName'
                class='app-field $appName'
                data-payload='" . json_encode($payload) . "'></div>"
        );
    }
}

Example Usage:

<?php

use L51\Sandbox\AppField;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Environment;

class Page extends SiteTree
{

    public function getCMSFields()
    {
        $fields = parent::getCMSFields();

        $fields->addFieldToTab(
            'Root.Main',
            AppField::create(
                'DemoGifField',
                'gif-field', // <--- will be used as css class selector and has to match first param of watchElement()
                [
                    'apiKey' => Environment::getEnv('TENOR_API_KEY'),
                    'topic'  => 'nerds'
                ]
            ),
            'Title'
        );

        return $fields;
    }
}

3. Data flows JavaScript app <---> Silverstripe

Silverstripe --> JavaScript app

As shown in the snippets above, AppField expects a third parameter $payload which should be an array. The JSON representation will be included in the wrapper-div's dataset scope (data-payload). This way the data will be accessible for the JavaScript app for hydration/configuration.

const render = (el: HTMLElement) => {
    const payload = JSON.parse(el.dataset.payload as string);

    createApp(GifField, {
        apiKey: payload.apiKey,
        topic: payload.topic
    }).mount(`#${el.id}`);;
}

JavaScript app --> Silverstripe

There are various ways to send data from the JavaScript app back to Silverstripe. You can easily create your own REST-style routes and make API requests or use the built-in GraphQL capabilities of Silverstripe.

One thing we should not forget about is the fact that FormFields are RequestHandlers and hence, siblings of Controllers (that's right!).

In our example:

AppField
 - LiteralField
  - DatalassField
   - FormField
    - RequestHandler 

Recommended reading: Zauberfisch was giving a nice talk about this topic ("SilverStripe FormFields and the magic beyond <input type=text/>") at StripeCon EU 2017 in Malta.

Hence, you can simply create actions on your custom FormField (e.g. AppField) and call them REST-style.

Another possible solution could be to take make your FormField getting picked up by an EditForms saveInto() traversal.

Feedback?

If you have comments or questions open an issue or reach out over the Silverstripe Slack to JZubero (me).

🖖

About

Demo Silverstripe and JavaScript sources for Lightning Talk "FormField Mini Apps" at StripeCon EU 2022

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • PHP 48.8%
  • TypeScript 32.0%
  • Vue 11.4%
  • Shell 7.8%