smartly
smartly

Reputation: 93

Liferay: AJAX call in configuration mode impossible?

Is it possible to use AJAX in configuration mode?

I am using custom class extending DefaultConfigurationAction to customize my portlet in the configuration mode. I override processAction and render methods, which work OK, but when I try to implement serveResource method, it is never called (returned status is 200 OK, but no data is fetched and no debug message is printed to the Liferay console).

My code for serveResource method:

public class TestConfigurationController extends DefaultConfigurationAction {
...
    @Override
    public void serveResource(PortletConfig portletConfig, ResourceRequest resourceRequest,
            ResourceResponse resourceResponse) throws PortletException, IOException, Exception {
        String resourceID = resourceRequest.getResourceID();
        System.out.println("Resource id=" + resourceID
                + " in TestConfigurationController.serveResource().");         // this message never prints, method is not invoked
        if (IMG_EDIT_ADD_NEW.equals(resourceID)) {
            // more code
            include(EDIT_NEW_IMAGE, context, resourceRequest, resourceResponse);    // uses PortletRequestDispatcher, returns a JSPF fragment
        } else {
            super.serveResource(portletConfig, resourceRequest, resourceResponse);
        }
    }
}

I tried all options on the JS side, including both JQuery and AUI. Here is relevant code in configuration.jsp:

<portlet:resourceURL var="newImageJsp" id = "<%=IMG_EDIT_ADD_NEW%>">
</portlet:resourceURL>

<aui:button name="addNewImage" type="button" value="${addImage}"/>
<div id="<portlet:namespace/>newImageContainer">
    <aui:field-wrapper name="newImageContainer" label="${addImage}">
    </aui:field-wrapper>
</div>

<script type="text/javascript" charset="utf-8">
// Even this simple AUI AJAX call does not trigger serveResource method!

//    AUI().ready('aui-base', 'aui-module', 'node', 'aui-io-request', function (A) {
//        A.io.request('<%=newImageJsp.toString()%>');
//    });

    jQuery(document).ready(function () {
        jQuery('#<portlet:namespace/>addNewImage').on('click', function (event) {
            console.log('addNewImage clicked, url: ${newImageJsp}');                   // returns correct url
            jQuery.ajax({
                dataType: 'text',
                url: '${newImageJsp}',
                success: function (data, status) {
                    console.log('returned resource: ' + data);          // returns empty string
                    console.log('returned status: ' + status);            // returns 200 OK, which is also in the Firebunetwork panel
                    $('#<portlet:namespace/>newImageContainer').html(data);
                }
            });
            return false;
        });
    });
</script>

Debugging in console revealed, JS is working fine, function was called and returned status was 200 OK. However, returned data was empty and serveResource method on the server was never called.

As an experiment, I also tried to set

<aui:form action="${newImageJsp}" method="get" name="fm1">

which didn't call the serveResource method either, instead, it returned the view.jsp of the configured portlet.

And finally my configuration, which is exactly as in this working case:

portlet.xml:

<portlet>
        <portlet-name>test-portlet</portlet-name>
        <portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
        <init-param>
            <name>contextConfigLocation</name>
            <value>/WEB-INF/spring-context/portlet/test-portlet.xml</value>
                </init-param>
                <init-param>
                    <name>config-template</name>
                    <value>/WEB-INF/jsp/carousel/configuration.jsp</value>
                </init-param>
        <expiration-cache>0</expiration-cache>
        <supports>
            <mime-type>text/html</mime-type>
                        <portlet-mode>view</portlet-mode>
                        <portlet-mode>edit</portlet-mode>
        </supports>
        <portlet-info>
            <title>Test</title>
        </portlet-info>
    </portlet>

and liferay-portlet.xml:

<liferay-portlet-app>
    <portlet>
        <portlet-name>test-portlet</portlet-name>
        <icon>/icon.png</icon>
                <configuration-action-class>com.test.TestConfigurationController</configuration-action-class>
                <requires-namespaced-parameters>false</requires-namespaced-parameters>
                <ajaxable>true</ajaxable>
        <header-portlet-css>/css/main.css</header-portlet-css>
                <header-portlet-javascript>/js/jquery-1.11.3.min.js</header-portlet-javascript>
        <header-portlet-javascript>/js/main.js</header-portlet-javascript>
    </portlet>
</liferay-portlet-app>

So, it seems I have a similar problem, as this unresolved issue

I was thinking, that maybe it is the window state? Configuration mode always uses 'pop-up', but in all examples I only found AJAX calls using 'normal' window state. Maybe that is the problem? Is it even possible to make asynchronous JSPF loadings in pop-up mode? And even in configuration window? I never found a working example of use of AJAX in configuration mode and official Liferay only has examples for view mode.

Last but not least, I tested the same code in view.jsp for view mode and the resource serving method in TestViewController was called OK. I used Spring annotations here (@ResourceMapping). So the problem must be with Liferay and configuration mode. A bug maybe?

Thank you!

Upvotes: 0

Views: 1793

Answers (2)

smartly
smartly

Reputation: 93

So, I tried both liferay-portlet:resourceURL portletConfiguration="true" and portlet:resourceURL, also with manual parsing and modifying the url before sending. The resource serving method (whether implementation of the serveResource, or completely new method using either Spring MVC or Liferay MVC (implementation class of MVCPortlet)), none worked in configuration mode. Seems like a bug to me, as there is nowhere even a mention about this peculiarity in official documentation.

The solution for me was to avoid resource serving at all and instead choose action phase (p_p_lifecycle=1). It is completely doable in AJAX, just had to override processAction method in my DefaultConfigurationAction implementation class.

Hope this saves someone the countless hours I spent with it.

Upvotes: 0

Dan Sin
Dan Sin

Reputation: 491

I did something similar and use the PrintWriter Object in resourceResponse:

PrintWriter writer = resourceResponse.getWriter();
writer.print([yourResult]);

http://liferayiseasy.blogspot.hk/2015/03/ajax-call-in-spring-mvc-portlet.html

You can also add a class extends MVCPortlet

Your previous view.jsp

<portlet:resourceURL var="newImageJsp" name="newImageResource"
</portlet:resourceURL>

...

// create a new class:
    public class CustomResourceController extends MVCPortlet {
    ...
        @Override(name="newImageResource") // <---- define the name attribute which match with view.jsp
        public void serveResource(PortletConfig portletConfig, ResourceRequest resourceRequest,
                ResourceResponse resourceResponse) throws PortletException, IOException, Exception {
            String resourceID = resourceRequest.getResourceID();
            System.out.println("Resource id=" + resourceID
                    + " in TestConfigurationController.serveResource().");         // this message never prints, method is not invoked
            if (IMG_EDIT_ADD_NEW.equals(resourceID)) {
                // more code
                include(EDIT_NEW_IMAGE, context, resourceRequest, resourceResponse);    // uses PortletRequestDispatcher, returns a JSPF fragment
            } else {
                super.serveResource(portletConfig, resourceRequest, resourceResponse);
            }
        }
    }

Upvotes: 0

Related Questions