Expand my Community achievements bar.

SOLVED

How to rename the nodes in multifield in a numerical order after deleting a node

Avatar

Level 2

Hi All,

I have a multifield component and saving the node value based on the highest index but i have the problem let us assume we have three nodes (field_0, field_1, field_2) at the time, we are removing the 2nd node and try to add one more node, at this time its saving as field_3 but i need as field_2.

Also when a node is deleted, it should rearrange or rename the nodes and provide it in a numerical order as field_0, field_1, field_2.

 

Do we need to make this through custom js or do we have any AEM default functionality to fix this.

 

All suggestions are welcome.

 

Thanks in advance!! 

Nirmal

1 Accepted Solution

Avatar

Correct answer by
Level 10

Hi @Nirmal_Kumar1 ,

To achieve renaming nodes in a multifield component to maintain numerical order after deleting a node, you will need to implement custom JavaScript as AEM does not provide built-in functionality to handle this automatically.

Here is a step-by-step approach to implement this custom JavaScript solution:

Step 1: Add Custom JavaScript to Your Component

You need to create or update a client library to include the custom JavaScript for your multifield component.

  1. Create/Update Client Library

    • Ensure you have a client library defined for your component. If not, create one under /apps/your-project/clientlibs/your-component.

 

<!-- /apps/your-project/clientlibs/your-component/.content.xml -->
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
          xmlns:jcr="http://www.jcp.org/jcr/1.0"
          jcr:primaryType="cq:ClientLibraryFolder"
          categories="[your-component-category]"
          dependencies="[cq.jquery]"/>
​

 

 

Include JavaScript File

  • Create a JavaScript file in your client library, for example, multifield-reorder.js.

 

// /apps/your-project/clientlibs/your-component/multifield-reorder.js
(function ($, document) {
    "use strict";

    // Function to renumber the multifield items
    function renumberMultifieldItems(multifield) {
        multifield.children('.coral-Multifield-item').each(function (index, element) {
            var item = $(element);
            var oldName = item.find("[data-cq-multifield-item-name]").attr("data-cq-multifield-item-name");
            if (oldName) {
                var newName = oldName.replace(/field_\d+/, 'field_' + index);
                item.find("[data-cq-multifield-item-name]").attr("data-cq-multifield-item-name", newName);
                item.find("input, textarea, select").each(function () {
                    var input = $(this);
                    var inputName = input.attr("name");
                    if (inputName) {
                        inputName = inputName.replace(/field_\d+/, 'field_' + index);
                        input.attr("name", inputName);
                    }
                });
            }
        });
    }

    // Event listener for multifield add/remove actions
    $(document).on('click', '.coral-Multifield-add, .coral-Multifield-remove', function () {
        var multifield = $(this).closest('.coral-Multifield');
        setTimeout(function () {
            renumberMultifieldItems(multifield);
        }, 500); // Slight delay to allow the DOM to update
    });

})(jQuery, document);
​

 

Include the JavaScript in the Dialog

  • Ensure your dialog includes this client library.

 

<!-- /apps/your-project/components/your-component/_cq_dialog/.content.xml -->
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
          xmlns:cq="http://www.day.com/jcr/cq/1.0"
          jcr:primaryType="nt:unstructured"
          cq:dialogMode="floating"
          jcr:title="Your Component"
          sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/container">
        <items jcr:primaryType="nt:unstructured">
            <yourField
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                fieldLabel="Your Multifield">
                <field jcr:primaryType="nt:unstructured" name="./yourField">
                    <items jcr:primaryType="nt:unstructured">
                        <!-- Your multifield item configuration -->
                    </items>
                </field>
            </yourField>
        </items>
    </content>
    <cq:clientlibs
        jcr:primaryType="cq:ClientLibrary"
        categories="[your-component-category]"/>
</jcr:root>
​

 

Step 2: Deploy and Test

  1. Deploy the changes to your AEM instance.

 

mvn clean install -PautoInstallPackage

 

  1. Test the functionality:

    • Open the dialog of the component with the multifield.
    • Add and remove items from the multifield.
    • Verify that the names of the fields are renumbered correctly after each add/remove action.

 

By adding this custom JavaScript to your AEM project, you ensure that the fields within the multifield are renumbered correctly after an item is removed, preventing gaps in the numbering sequence. This approach ensures a consistent and predictable order for the multifield items.

View solution in original post

4 Replies

Avatar

Community Advisor

As far as I understand your requirement is, you have saved a dialog with multifield, on save it creates some node for all the authored multifield data as node_1, node_2 and so on so you have deleted one node then again saving it so why it is not creating a node as perviously deleted node name right?

If this is so called issue you are facing, before answering your question, can you please tell me why this is an issue for you to have different node name ?

Ideally any node name should be fine, as reading data from multifield we do the node iteration. If you have any logic to do some operation on node name then this is going to be a big problem for you as you don't have control on it. AEM will put any name for nodes.

For node deletion you should take help from Java api but it should be used with extra care.

Hope this helps

Umesh Thakur

 

Avatar

Level 8

@Nirmal_Kumar1 

There is no out-of-the-box functionality in AEM to automatically rename or reorder the nodes created by a multifield component when nodes are added or removed. The node names are generated sequentially (item0, item1, item2, etc.) based on the order they are created.
 
So, yes you should go with custom js for this.

Avatar

Correct answer by
Level 10

Hi @Nirmal_Kumar1 ,

To achieve renaming nodes in a multifield component to maintain numerical order after deleting a node, you will need to implement custom JavaScript as AEM does not provide built-in functionality to handle this automatically.

Here is a step-by-step approach to implement this custom JavaScript solution:

Step 1: Add Custom JavaScript to Your Component

You need to create or update a client library to include the custom JavaScript for your multifield component.

  1. Create/Update Client Library

    • Ensure you have a client library defined for your component. If not, create one under /apps/your-project/clientlibs/your-component.

 

<!-- /apps/your-project/clientlibs/your-component/.content.xml -->
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
          xmlns:jcr="http://www.jcp.org/jcr/1.0"
          jcr:primaryType="cq:ClientLibraryFolder"
          categories="[your-component-category]"
          dependencies="[cq.jquery]"/>
​

 

 

Include JavaScript File

  • Create a JavaScript file in your client library, for example, multifield-reorder.js.

 

// /apps/your-project/clientlibs/your-component/multifield-reorder.js
(function ($, document) {
    "use strict";

    // Function to renumber the multifield items
    function renumberMultifieldItems(multifield) {
        multifield.children('.coral-Multifield-item').each(function (index, element) {
            var item = $(element);
            var oldName = item.find("[data-cq-multifield-item-name]").attr("data-cq-multifield-item-name");
            if (oldName) {
                var newName = oldName.replace(/field_\d+/, 'field_' + index);
                item.find("[data-cq-multifield-item-name]").attr("data-cq-multifield-item-name", newName);
                item.find("input, textarea, select").each(function () {
                    var input = $(this);
                    var inputName = input.attr("name");
                    if (inputName) {
                        inputName = inputName.replace(/field_\d+/, 'field_' + index);
                        input.attr("name", inputName);
                    }
                });
            }
        });
    }

    // Event listener for multifield add/remove actions
    $(document).on('click', '.coral-Multifield-add, .coral-Multifield-remove', function () {
        var multifield = $(this).closest('.coral-Multifield');
        setTimeout(function () {
            renumberMultifieldItems(multifield);
        }, 500); // Slight delay to allow the DOM to update
    });

})(jQuery, document);
​

 

Include the JavaScript in the Dialog

  • Ensure your dialog includes this client library.

 

<!-- /apps/your-project/components/your-component/_cq_dialog/.content.xml -->
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
          xmlns:cq="http://www.day.com/jcr/cq/1.0"
          jcr:primaryType="nt:unstructured"
          cq:dialogMode="floating"
          jcr:title="Your Component"
          sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/container">
        <items jcr:primaryType="nt:unstructured">
            <yourField
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                fieldLabel="Your Multifield">
                <field jcr:primaryType="nt:unstructured" name="./yourField">
                    <items jcr:primaryType="nt:unstructured">
                        <!-- Your multifield item configuration -->
                    </items>
                </field>
            </yourField>
        </items>
    </content>
    <cq:clientlibs
        jcr:primaryType="cq:ClientLibrary"
        categories="[your-component-category]"/>
</jcr:root>
​

 

Step 2: Deploy and Test

  1. Deploy the changes to your AEM instance.

 

mvn clean install -PautoInstallPackage

 

  1. Test the functionality:

    • Open the dialog of the component with the multifield.
    • Add and remove items from the multifield.
    • Verify that the names of the fields are renumbered correctly after each add/remove action.

 

By adding this custom JavaScript to your AEM project, you ensure that the fields within the multifield are renumbered correctly after an item is removed, preventing gaps in the numbering sequence. This approach ensures a consistent and predictable order for the multifield items.

Avatar

Level 2

Hi @HrishikeshKa 

 

This works  fine after few changes made in the class and attributes used in it.

 

Thanks,

Nirmal