Search code examples
adobeaemaem-6

AEM6 - How can I edit a component in place without a dialog?


I've been trying to edit a Table component in place (without needing to open the dialog), for i.e.: add new rows or columns.

The component has its dialog properly configured, so you can select the number of columns and rows from there, although to improve the UX I've added a button next to the table that's only visible in edit mode to add a new row programatically from the clientlib.edit javascript. But don't know what's the way to actually persist the data (save changes).

Any ideas that could take me on the right path will be massively appreciated!


Solution

  • One possible solution is 3 component based -

    1. Table Container component (Allows to add only Row Component or you could allow for drag and drop to keep things simpler)
    2. Row Component (Another simple container component) follows row specific styling (allows to add column component, use component editbar introduce custom '+' sign that allows to add column component)
    3. Column component with parsys (containing text component, use template based implementation to achieve this, refer to blog here for reference)

    To achieve the '+' sign functionality and persistence do following -

    Create a cq:ClientLibraryFolder and specify its property categories="cq.authoring.dialog", to this client library add JS as -

    /* global Granite, $ */
    $(document).on('cq-page-info-loaded', function() {
        'use strict';
    
        // initialisation for Mysite
        window.mysite = window.mysite || {};
        window.mysite.app = window.mysite.app || {};
        window.mysite.app.auth = window.mysite.app.auth || {};
    
        (function(window, ns, undefined) {
            /**
             * Adds a child component of a specified type to a parent editable component.
             * (event handler for clicking the 'add' button in the edit interface on the sections or questions component)
             *
             * @param {Granite.author.Editable}     parentEditable      The editable parent component
             * @param {string}                      componentName       Name of the child component to add e.g. 'mysite-app/ui/components/content/link'
             * @param {boolean}                     componentTemplate   If true, call the low level interface directly. If false, call higher level Granite.author.edit methods.
             */
            var createChildComponent = function(parentEditable, componentName, componentTemplate) {
                return (
                    new ns.persistence.PostRequest()
                        .prepareCreateParagraph({
                            resourceType: componentName,
                            parentPath: parentEditable.path,
                            relativePosition: 'last',
                            templatePath: componentTemplate
                        })
                        .send()
                ).done(function() {
                    parentEditable.refresh();
                });
            };
    
            window.mysite.app.auth.component = (function() {
                return {
                    tablerow: {
                        add: function(editable) {
                            createChildComponent(editable, '/apps/mysite-app/ui/components/<path to row component>', false);
                        }
                    },
                    rowcell: {
                        add: function(editable) {
                            createChildComponent(editable, '/apps/mysite-app/ui/components/<path to column cell>', false);
                        }
                    }
                };
            })();
        })(window, Granite.author);
    
    });
    

    Next is to setup your actionConfigs in editConfig for individual components and point it to the above script's handler.

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
        cq:actions="[edit,delete]"
        jcr:primaryType="cq:EditConfig">
        <cq:actionConfigs jcr:primaryType="nt:unstructured">
            <addCell
                jcr:primaryType="nt:unstructured"
                handler="mysite.app.auth.component.rowcell.add"
                icon="coral-Icon--add"
                text="Add column to table row"/>
        </cq:actionConfigs>
    </jcr:root>
    

    On your component editbar you will start seeing the '+' sign that allows you to add configured component and persist its node(s).

    EditBar

    Refer here to add custom action to edit bar if you need more details.


    In case you dont want to follow this approach, the first script has the logic that allows you to persist the component nodes, you can reuse it and embed it in your own implementation.