Search code examples
jsonextjsextjs5sencha-architect

ExtJS 5: how to set up a store to gather remote data when a POST with JSON body is required?


I need a store to gather data from a URL, but the URL needs a POST of JSON data in order to create the correct response (in this example, a set of disclaimer questions the user must answer, based on the products in his shopping cart.)

Here's what I have so far. I want to send the cart and get the question set in response:

QuestionStore: {
            autoLoad: false,
            model: 'RefCig.model.Question',
            proxy: {
                type: 'ajax',
                url: '/refcig-services/questionsForCart',
                actionMethods: {
                    create: 'POST',
                    read: 'POST',
                    update: 'POST',
                    destroy: 'POST'
                },
                headers: {
                    'Content-Type': 'application/json; charset=utf-8'
                },
                reader: {
                    type: 'json'
                },
                writer: {
                    type: 'json'
                }
            }
        }

On submit:

var cartStore = Ext.getStore('CartStore');
cartItems = Ext.Array.pluck(cartStore.data.items, 'data');
var questionStore = this.getStore('QuestionStore');
questionStore.load({params:cartItems});

A console.log of Ext.encode(cartItems) is exactly what I want to send to the backend:

[{
    "id": 19,
    "pricePerUnit": 20,
    "denominationsPerUnit": 1,

    "blahblahblah": 1, 

    "unitQuantity": 1,
    "total_item_count": null,
    "subtotal": 20
}]

Yet the request is malformed:

{
    "0": {
        "id": 19,
        "pricePerUnit": 20,
        "denominationsPerUnit": 1,

        "unitQuantity": 1,
        "total_item_count": null,
        "subtotal": 20
    },
    "page": 1,
    "start": 0,
    "limit": 25
}

How should I be telling my QuestionStore to form its request body the way I want?

Thanks in advance.


Solution

  • Technically your requirement can be met by using a custom proxy. You implement your own buildRequest method in there, which is a stripped down version of the original one:

    Ext.define('MyProxy', {
        extend: 'Ext.data.proxy.Ajax',
        alias: 'proxy.my',
        paramsAsJson: true,
        buildRequest: function(operation) {
            var me = this,
                params = operation.getParams(),
                request, operationId, idParam;
            operationId = operation.getId();
            idParam = me.getIdParam();
            if (operationId !== undefined && params[idParam] === undefined) {
                params[idParam] = operationId;
            }
            request = new Ext.data.Request({
                params: params,
                action: operation.getAction(),
                records: operation.getRecords(),
                url: operation.getUrl(),
                operation: operation,
                proxy: me
            });
            request.setUrl(me.buildUrl(request));
            operation.setRequest(request);
            return request;
        }
    });
    

    Then, in the store definition, you simply use the proxy:

    proxy: {
        type: 'my',
        // .....
    

    However, I would recommend another way.

    Do something like:

    questionStore.load({params: {cartItems: cartItems}});
    

    instead of

    questionStore.load({params:cartItems});
    

    That will make the request body look like this:

    {
        "cartItems": [{
            "id": 19,
            "pricePerUnit": 20,
            "denominationsPerUnit": 1,
            "blahblahblah": 1, 
            "unitQuantity": 1,
            "total_item_count": null,
            "subtotal": 20
        }],
        "page": 1,
        "start": 0,
        "limit": 25
    }
    

    You would need to adjust your server side to retrieve the cartItems array from the payload.