Search code examples
jqueryjsonajaxliferayliferay-7

Getting json data from AJAX in MVC Resource Command (Liferay 7.4)


I am unable to get the JSON data from AJAX in MVC Resource Command because I am getting null value in the request parameter.

I have searched for several Stackoverflow answers to solve the problem, and I am not clear where I am going wrong.

Code snippet and screenshots will be provided below.

Controller portlet

@Component(
    immediate = true,
    property = {
        "com.liferay.portlet.display-category=Demo",
        "com.liferay.portlet.header-portlet-css=/css/main.css",
        "com.liferay.portlet.footer-portlet-javascript=/js/main.js",
        "com.liferay.portlet.instanceable=true",
        "javax.portlet.display-name=Empleado",
        "javax.portlet.init-param.template-path=/",
        "javax.portlet.init-param.view-template=/view.jsp",
        "javax.portlet.name=" + EmpleadoPortletKeys.EMPLEADO,
        "javax.portlet.resource-bundle=content.Language",
        "javax.portlet.security-role-ref=power-user,user",
        "javax.portlet.version=3.0"
    },
    service = Portlet.class
)
public class EmpleadoPortlet extends MVCPortlet {
    
    public void render(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException {
        
        List<Empleado> empleados = EmpleadoLocalServiceUtil.getEmpleados(-1, -1);
        
        renderRequest.setAttribute(EmpleadoPortletKeys.EMPLEADO_ID_TABLE_HEADER, EmpleadoPortletKeys.EMPLEADO_ID_TABLE_HEADER);
        renderRequest.setAttribute(EmpleadoPortletKeys.DNI_TABLE_HEADER, EmpleadoPortletKeys.DNI_TABLE_HEADER);
        renderRequest.setAttribute(EmpleadoPortletKeys.NOMBRE_TABLE_HEADER, EmpleadoPortletKeys.NOMBRE_TABLE_HEADER);
        renderRequest.setAttribute(EmpleadoPortletKeys.APELLIDOS_TABLE_HEADER, EmpleadoPortletKeys.APELLIDOS_TABLE_HEADER);
        renderRequest.setAttribute(EmpleadoPortletKeys.CARGO_TABLE_HEADER, EmpleadoPortletKeys.CARGO_TABLE_HEADER);
        renderRequest.setAttribute(EmpleadoPortletKeys.ACCIONES_TABLE_HEADER, EmpleadoPortletKeys.ACCIONES_TABLE_HEADER);
        renderRequest.setAttribute(EmpleadoPortletKeys.EMPLEADOS, empleados);
        
        super.render(renderRequest, renderResponse);
    }
    
}

view.jsp

<%@ include file="/init.jsp" %>

<portlet:resourceURL id="empleado-resource" var="empleadoResourceURL"/>

<div id="empleado-portlet">
    <div class="container">
        <table class="table table-hover">
            <thead>
                <tr>
                    <th scope="col">${fn:toUpperCase(dni)}</th>
                    <th scope="col">${nombre}</th>
                    <th scope="col">${apellidos}</th>
                    <th scope="col">${cargo}</th>
                    <th scope="col" class="text-center">${acciones}</th>
                </tr>
            </thead>
            <tbody>
                <c:forEach var="employee" items="${employees}"> 
                    <tr>
                        <td>${employee.dni}</td>
                        <td>${employee.nombre}</td>
                        <td>${employee.apellidos}</td>
                        <td>${employee.cargo}</td>
                        <td>
                            <div class="btn-actions d-flex justify-content-center">
                                <div class="mr-1">
                                    <button type="button" id="${employee.empleadoId}" class="btn btn-primary btn-update">
                                        <i class="icon-pencil"></i>
                                    </button>
                                </div>
                                <div class="ml-1">
                                    <button type="button" id="${employee.empleadoId}" class="btn btn-danger btn-remove">
                                        <i class="icon-remove"></i>
                                    </button>
                                </div>
                            </div>
                        </td>
                    </tr>
                </c:forEach> 
            </tbody>
        </table>
    </div>
</div>

<script>
    let empleadoResourceURL = '${empleadoResourceURL}';
</script>

main.js

function ajaxCall(data) {

    $.ajax({
        beforeSend : function() {
            /*showSpinner();*/
        },
        url: empleadoResourceURL,
        type: "POST",
        data: JSON.stringify(data),
        contentType: "json",
        success: function(data) {
            console.log("Respuesta de la solicitud: " + data);
            
            switch(data){
            
                case 'updateEmployee':
                    console.log('Empleado actualizado: OK');
                break;
            
            }   
        },
        error: function(xhr, status) {
            console.log("La solicitud ha fallado: " +  status);
        },
        complete: function(xhr, status) {
            /*hideSpinner();*/
        }
    });

}

$(document).ready(function(){
  
    $('#empleado-portlet .btn-actions').on('click','.btn-update',function() {
        var data = {};
        
        data.action = 'updateEmployee';
        data.selectedEmployee = $(this).attr('id');
        
        console.log(data);
        console.log('JSON.stringfy: ' + JSON.stringify(data));
        
        ajaxCall(data);
    });
  
});

MVC Resource Command

@Component(
    property = {
        "javax.portlet.name=" + EmpleadoPortletKeys.EMPLEADO,
        "mvc.command.name=empleado-resource",
        "javax.portlet.version=3.0"
    },
    service = MVCResourceCommand.class
)
public class EmpleadoResource extends BaseMVCResourceCommand{

    @Override
    public void doServeResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws Exception {
        System.out.println("I HAVE PASSED");
        
        ResourceParameters resourceParameters = resourceRequest.getResourceParameters();
        PrintWriter printWriter = resourceResponse.getWriter();
        
        //Alternative 1
        String action_1 = resourceParameters.getValue(EmpleadoPortletKeys.ACTION);
        System.out.println("ACTION_1: " + action_1);
        
        //Alternative 2
        String action_2 = ParamUtil.getString(resourceRequest, EmpleadoPortletKeys.ACTION);
        System.out.println("ACTION_2: " + action_2);
        
        printWriter.print(EmpleadoPortletKeys.ACTION_REMOVE_EMPLEADO);
        
    }

}

The problem

Once the portlet is deployed, the update button is selected in the table on the page.In the image below you can see through the browser console that the AJAX function makes the request and the response.

AJAX request/response

On the other hand, in the eclipse console, you can see that the MVC Resource Command "doServeResource" method is executed because it prints "I have passed" on the screen. However, the value of the "action" key is not obtained.

The first alternative prints "null" and the second alternative prints blank.

Eclipse IDE console

- Why can't I get the json data from AJAX in MVC resource command?

- What am I doing wrong?


Solution

  • My best guess: Portlet parameters typically need to be namespaced, so that it's obvious, to which portlet they are targeted. (e.g. in a JSP, prepend <portlet:namespace/> to the parameter name)

    If you don't want to do this this, you can either add the com.liferay.portlet.requires-namespaced-parameters=false property to your portlet, or you can access the raw HttpServletRequest for the raw parameter value (not recommended).