cancel
Showing results for 
Search instead for 
Did you mean: 

Mixin AlfSelectedItemsMenuItem Payloads to DialogService Submit Payload

keithb_dtech
Champ on-the-rise
Champ on-the-rise

I am having trouble constructing a payload for a DialogService form submission event. The use case is when a user selects the items in a custom search, the AlfSelectedItemsMenuItem populates with the currently selected items and the user can next choose to operate on the selected items. Before the user operates on those items, we display a dialog to the user for additional information. The dialog, upon completion, sends the collected information to a repository webscript using a CrudService POST. However, the Dialog will not mixin with the selected items at all, the selectedItems array is not present in the payload passed to the webscript.

The first thing we tied was to use the PROCESS payload type on the AlfSelectedItemsMenuItem as well as supplying a "selectedItems" field in the formSubmissionPayloadMixin with the publishPayloadModifier containing "processCurrentItemTokens" but that did not work. We assumed it was due to there being no "currentItem" on the AlfSelectedItemsMenuItem. Next, we tried to get the selectedItems to populate themselves with the service mixin by supplying the CONFIGURED payload type on the AlfSelectedItemsMenuItem with the publishPayloadItemMixin set to true. That also did not work. I believe what is going on is that the DialogService does not have a handle on the selectedItems and needs to be overridden with the alfresco/lists/SelectedItemStateMixin. I am skeptical that this will work since the SelectedItemStateMixin may not be able to publish to the Dialog since it is created AFTER the user clicks the AlfSelectedItemsMenuItem. I also thought this solution was overkill since we receive the selectedItems field when we publish to the CrudService directly from the AlfSelectedItemsMenuItem to our webscript (no Dialog) without specifying the payload type or any other mixins. Is there any way to solve this problem without potentially re-building the DialogService?

Here is a snippet of the code we currently have:

{

    name: "alfresco/documentlibrary/AlfSelectedItemsMenuBarPopup",

    config: {

        label: "Selected Items...",

        itemKeyProperty: "nodeRef",

        widgets: [

            {

                id: "SELECTED_ITEMS_ACTIONS_MENU_GROUP",

                name: "alfresco/menus/AlfMenuGroup",

                config: {

                    widgets: [

                        // ... other widgets

                        {

                            name: "alfresco/menus/AlfSelectedItemsMenuItem",

                            config: {

                                id: "SELECTED_ITEMS_NDS_ACTION",

                                label: "Process NDS",

                                iconImage: url.context + "/res/components/documentlibrary/actions/document-download-16.png",

                                // iconImage: url.context + "/res/components/social-email-16.png",

                                publishTopic: "ALF_CREATE_FORM_DIALOG_REQUEST",

                                publishPayload: {

                                    cancelPublishScope: "",

                                    cancelPublishTopic: "DIALOG_CANCELLED",

                                    //showOkButton: false,

                                    dialogId: "FCTSRCH_NDS_DIALOG",

                                    dialogTitle: "Process NDS",

                                    dialogConfirmationButtonTitle: "Process",

                                    dialogCancellationButtonTitle: "Cancel",

                                    formSubmissionTopic: "ALF_CRUD_CREATE",

                                    formSubmissionPayloadMixin: {

                                        url: "/processnds",

                                    },

                                    widgets: [

                                        {

                                            name: "alfresco/forms/controls/SimplePicker",

                                            config: {

                                                label: "Choose New Handler",

                                                description: "Choose a User to Attach the NDS.",

                                                name: "user",

                                                loadDataPublishTopic: "ALF_CRUD_GET_ALL",

                                                loadDataPublishPayload: {

                                                    url: "api/people"

                                                },

                                                itemsProperty: "people",

                                                itemKey: "userName",

                                                propertyToRender: "userName",

                                                availableItemsLabel: "Available Users",

                                                pickedItemsLabel: "Currently Selected Users"

                                            }

                                        },

                                        {

                                            name: "alfresco/forms/controls/TextBox",

                                            config: {

                                                name: "location",

                                                label: "New Location",

                                                description: "New Location for NDS?"

                                            }

                                        }

                                    ]

                                }

                            }

                        }

                    ]

                }

            }

        ]

    }

}

If line 20 is instead ALF_CRUD_CREATE and the payload on line 21 contains "url: /processnds", we get the selectedItems just fine returned to our webscript.

1 ACCEPTED ANSWER

Hello Axel,

This solution occurred to me as well and unfortunately, it does not work as intended. The processInstanceTokens modifier does indeed retrieve the objects and place them into the field inside the payload with the "{publishPayload.selectedItems}" token. However, when CrudService sends the payload to the repository, I find that the objects are not correctly converted to JSON as it does with processCurrentItemTokens. I receive "[object Object]" for each of the selected items, when I should receive the normal nodeRef object in JSON form. It also seems to strip the objects from the array, returning "[object Object],[object Object],[object Object]" for three objects. In short, there seems to be a bug in the way that the processInstanceTokens returns the array. This is strange since the behavior should also affect processCurrentItemTokens since that modifier uses the same method call on the backed as processInstanceTokens. Perhaps it would be helpful to wrap the response in a dojo/json.stringify as a customization of the ObjectProcessingMixin.

The approach I've taken to solve the problem is to override the DialogService with CustomDialogService, which turned out to be easier than I thought.

First, I created a new extension module pointing to the location which I will place the new CustomDialogService:

<module>

    <id>Custom NDS Dialog Service</id>

    <version>1.0</version>

    <auto-deploy>true</auto-deploy>

    <configurations>

        <config evaluator="string-compare" condition="WebFramework" replace="false">

            <web-framework>

                <dojo-pages>

                    <packages>

                        <package name="nds" location="js/nds"/>

                    </packages>

                </dojo-pages>

            </web-framework>

        </config>

    </configurations>

</module>

Then, I created the CustomDialogService.js and placed it in the proper directory, I subscribed to item selections similar to the AlfSelectedItemsMenuItem and added the accumulated selectedItems directly to the payload in the form submission method:

define(["dojo/_base/declare",

        "alfresco/services/DialogService",

        "alfresco/documentlibrary/_AlfDocumentListTopicMixin",

        "dojo/_base/lang",

        "dojo/_base/array",

        "dojo/when",

        "jquery"],

    function(declare, _DialogService, _AlfDocumentListTopicMixin, lang, array, when, $) {

        return declare([_DialogService, _AlfDocumentListTopicMixin], {

//... then

registerSubscriptions: function nds_services_CustomDialogService__registerSubscriptions() {

    this.inherited(arguments);

    this.alfSubscribe(this.selectedDocumentsChangeTopic, lang.hitch(this, this.onItemsSelected));

},

// same as in AlfSelectedItemsMenuItem

onItemsSelected: function nds_services_CustomDialogService__onItemsSelected(payload) {

    if (payload.selectedItems)

    {

        if (!this.publishPayload)

        {

            this.publishPayload = {};

        }

        this.publishPayload.selectedItems = payload.selectedItems;

    }

},

// same as in DialogService except added selected items in the payload

onFormDialogConfirmation: function nds_services_CustomDialogService__onFormDialogConfirmation(payload) {

    if (payload &&

        payload.dialogContent)

    {

        when(payload.dialogContent, lang.hitch(this, function(dialogContent) {

            if (dialogContent && dialogContent.length)

            {

                var data = {};

                var formData = dialogContent[0].getValue();

                // See AKU-846 - If the dialog has been configured with an enablement topic then we can disable

                // all the buttons in the dialog, in the knowledge that they will be re-enabled if form submission

                // fails.

                if (payload.dialogEnableTopic && payload.dialogRef)

                {

                    when(payload.dialogRef.getButtons(), lang.hitch(this, function(buttons) {

                        array.forEach(buttons, function(button) {

                            button.set("disabled", true);

                        });

                    }));

                }

                // Destroy the dialog if a reference is provided...

                if (payload.dialogReference && typeof payload.dialogReference.destroyRecursive === "function")

                {

                    payload.dialogReference.destroyRecursive();

                }

                // Mixin in any additional payload information...

                // An alfResponseScope should always have been set on a payload so it can be set as the

                // responseScope, but a responseScope in the formSubmissionPayloadMixin will override it

                lang.mixin(data, {

                    responseScope: payload.alfResponseScope,

                    selectedItems: this.publishPayload.selectedItems // added selected items here

                });

                payload.formSubmissionPayloadMixin && lang.mixin(data, payload.formSubmissionPayloadMixin);

                // Using JQuery here in order to support deep merging of dot-notation properties...

                $.extend(true, data, formData);

                // Publish the topic requested for complete...

                var customScope;

                if (payload.formSubmissionScope || payload.formSubmissionScope === "")

                {

                    customScope = payload.formSubmissionScope;

                }

                var topic = payload.formSubmissionTopic,

                    globalScope = payload.hasOwnProperty("formSubmissionGlobal") ? !!payload.formSubmissionGlobal : true,

                    toParent = false;

                this.alfPublish(topic, data, globalScope, toParent, customScope);

            }

            else

            {

                this.alfLog("error", "The format of the dialog content was not as expected, the 'formSubmissionTopic' will not be published", payload, this);

            }

        }));

    }

},

Next, I added the CustomDialogService to my widget as a service, in this case, I was overriding faceted-search so I made a loop to search and replace the old DialogService in the array of services:

//add custom service for navigation

for(var i=0; i < model.jsonModel.services.length; i++) {

    if(model.jsonModel.services[i] == "alfresco/services/DialogService") {

        model.jsonModel.services[i] = "nds/services/CustomDialogService";

        break;

    }

}

Last, I tested the solution with the faceted-search and it worked well, injecting the selectedItems array and sending to the CrudService as expected.

Thanks for the help!

View answer in original post

5 REPLIES 5

afaust
Legendary Innovator
Legendary Innovator

Let me see if I understand correctly: You need the selectedItems to be present in the call to the webscript which the form will submit to when the user completes the dialog.

So in that case the selectedItems would need to be set inside of the formSubmissionPayloadMixin to be transferred. Unfortunately, the AlfSelectedItemsMenuItem always sets the selectedItems on the top-level of the publishPayload.

You are right to assume the DialogService does not handle this specific property (as countless others that could potentially be set by a widget dynamically). But the _PublishPayloadMixin process modifier "processInstanceTokens" should support this use case - simply use "{publishPayload.selectedItems}" as the token for a configuration property inside of formSubmissionPayloadMixin and you should be able to re-map the top-level selectedItems value inside of the mixin data that will be submitted to the web script.

Hello Axel,

This solution occurred to me as well and unfortunately, it does not work as intended. The processInstanceTokens modifier does indeed retrieve the objects and place them into the field inside the payload with the "{publishPayload.selectedItems}" token. However, when CrudService sends the payload to the repository, I find that the objects are not correctly converted to JSON as it does with processCurrentItemTokens. I receive "[object Object]" for each of the selected items, when I should receive the normal nodeRef object in JSON form. It also seems to strip the objects from the array, returning "[object Object],[object Object],[object Object]" for three objects. In short, there seems to be a bug in the way that the processInstanceTokens returns the array. This is strange since the behavior should also affect processCurrentItemTokens since that modifier uses the same method call on the backed as processInstanceTokens. Perhaps it would be helpful to wrap the response in a dojo/json.stringify as a customization of the ObjectProcessingMixin.

The approach I've taken to solve the problem is to override the DialogService with CustomDialogService, which turned out to be easier than I thought.

First, I created a new extension module pointing to the location which I will place the new CustomDialogService:

<module>

    <id>Custom NDS Dialog Service</id>

    <version>1.0</version>

    <auto-deploy>true</auto-deploy>

    <configurations>

        <config evaluator="string-compare" condition="WebFramework" replace="false">

            <web-framework>

                <dojo-pages>

                    <packages>

                        <package name="nds" location="js/nds"/>

                    </packages>

                </dojo-pages>

            </web-framework>

        </config>

    </configurations>

</module>

Then, I created the CustomDialogService.js and placed it in the proper directory, I subscribed to item selections similar to the AlfSelectedItemsMenuItem and added the accumulated selectedItems directly to the payload in the form submission method:

define(["dojo/_base/declare",

        "alfresco/services/DialogService",

        "alfresco/documentlibrary/_AlfDocumentListTopicMixin",

        "dojo/_base/lang",

        "dojo/_base/array",

        "dojo/when",

        "jquery"],

    function(declare, _DialogService, _AlfDocumentListTopicMixin, lang, array, when, $) {

        return declare([_DialogService, _AlfDocumentListTopicMixin], {

//... then

registerSubscriptions: function nds_services_CustomDialogService__registerSubscriptions() {

    this.inherited(arguments);

    this.alfSubscribe(this.selectedDocumentsChangeTopic, lang.hitch(this, this.onItemsSelected));

},

// same as in AlfSelectedItemsMenuItem

onItemsSelected: function nds_services_CustomDialogService__onItemsSelected(payload) {

    if (payload.selectedItems)

    {

        if (!this.publishPayload)

        {

            this.publishPayload = {};

        }

        this.publishPayload.selectedItems = payload.selectedItems;

    }

},

// same as in DialogService except added selected items in the payload

onFormDialogConfirmation: function nds_services_CustomDialogService__onFormDialogConfirmation(payload) {

    if (payload &&

        payload.dialogContent)

    {

        when(payload.dialogContent, lang.hitch(this, function(dialogContent) {

            if (dialogContent && dialogContent.length)

            {

                var data = {};

                var formData = dialogContent[0].getValue();

                // See AKU-846 - If the dialog has been configured with an enablement topic then we can disable

                // all the buttons in the dialog, in the knowledge that they will be re-enabled if form submission

                // fails.

                if (payload.dialogEnableTopic && payload.dialogRef)

                {

                    when(payload.dialogRef.getButtons(), lang.hitch(this, function(buttons) {

                        array.forEach(buttons, function(button) {

                            button.set("disabled", true);

                        });

                    }));

                }

                // Destroy the dialog if a reference is provided...

                if (payload.dialogReference && typeof payload.dialogReference.destroyRecursive === "function")

                {

                    payload.dialogReference.destroyRecursive();

                }

                // Mixin in any additional payload information...

                // An alfResponseScope should always have been set on a payload so it can be set as the

                // responseScope, but a responseScope in the formSubmissionPayloadMixin will override it

                lang.mixin(data, {

                    responseScope: payload.alfResponseScope,

                    selectedItems: this.publishPayload.selectedItems // added selected items here

                });

                payload.formSubmissionPayloadMixin && lang.mixin(data, payload.formSubmissionPayloadMixin);

                // Using JQuery here in order to support deep merging of dot-notation properties...

                $.extend(true, data, formData);

                // Publish the topic requested for complete...

                var customScope;

                if (payload.formSubmissionScope || payload.formSubmissionScope === "")

                {

                    customScope = payload.formSubmissionScope;

                }

                var topic = payload.formSubmissionTopic,

                    globalScope = payload.hasOwnProperty("formSubmissionGlobal") ? !!payload.formSubmissionGlobal : true,

                    toParent = false;

                this.alfPublish(topic, data, globalScope, toParent, customScope);

            }

            else

            {

                this.alfLog("error", "The format of the dialog content was not as expected, the 'formSubmissionTopic' will not be published", payload, this);

            }

        }));

    }

},

Next, I added the CustomDialogService to my widget as a service, in this case, I was overriding faceted-search so I made a loop to search and replace the old DialogService in the array of services:

//add custom service for navigation

for(var i=0; i < model.jsonModel.services.length; i++) {

    if(model.jsonModel.services[i] == "alfresco/services/DialogService") {

        model.jsonModel.services[i] = "nds/services/CustomDialogService";

        break;

    }

}

Last, I tested the solution with the faceted-search and it worked well, injecting the selectedItems array and sending to the CrudService as expected.

Thanks for the help!

afaust
Legendary Innovator
Legendary Innovator

The behaviour of getting a stringified value of "[object Object]" sounds familiar. I think I may have patched ObjectProcessingMixin to address this in one of my previous projects and contributed it to Aikau in May of this year (see alfresco/core/ObjectProcessingMixin processObject function converts array to string when it is insid... ). Can you please check which Aikau version you are using?

Axel Faust wrote:

The behaviour of getting a stringified value of "[object Object]" sounds familiar. I think I may have patched ObjectProcessingMixin to address this in one of my previous projects and contributed it to Aikau in May of this year (see alfresco/core/ObjectProcessingMixin processObject function converts array to string when it is insid... ). Can you please check which Aikau version you are using?

Yes, I think this may be exactly the case.  I am using the Alfresco Maven SDK version 2.2 and I have not run the command "mvn clean install -U" to force updating. Out of curiosity, if I did force the update using that command, would it actually update to the latest version of Aikau, or would I need to add the dependency to the Share pom to get the latest version?

afaust
Legendary Innovator
Legendary Innovator

You always have to specify the AIkau dependency yourself. The SDK does nothing automatically here. The platform distribution POM will always provide a fixed version of Aikau that was released with a specifc Alfresco version, but Aikau can be independently updated since Alfresco 5.0.d.

Getting started

Tags


Find what you came for

We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.