Creating a writer for nested JSON arrays in ExtJS 4

I'm currently tackling the challenge of working with JSON data that has a nested structure in ExtJS4. I kindly request not to provide responses similar to what can be found here as it is not the correct solution for me. My approach involves using expandData: true along with model mappings, which has been effective for me.

The specific issue I am encountering pertains to a field that consists of an array of objects. Here is a snippet of my code:

Ext.define('EdiWebUI.model.Document', {
  extend: 'Ext.data.Model',
  fields: [
    {name: 'document_header_documentReceiveDateTime', mapping: 'document.header.documentReceiveDateTime', type: 'string'},
    {name: 'document_header_documentProcessDateTime', mapping: 'document.header.documentProcessDateTime', type: 'string'},
    {name: 'document_header_documentID', mapping: 'document.header.documentID', type: 'string'},
    ...
    {name: 'lines', type: 'auto'},
    ...
    {name: 'attachments_documentFile_fileName', mapping: 'attachments.documentFile.fileName', type: 'string'},
    {name: 'attachments_documentFile_content', mapping: 'attachments.documentFile.content', type: 'string'}
  ],
  hasMany: [
    {model: 'DocumentLines', name: 'lines', associationKey: 'lines'}
  ],
  proxy: {
    type: 'rest',
    url: '/document',
    reader: {
      type: 'json',
      root: 'data'
    },
    writer: {
      expandData: true,
      writeAllFields: true,
      nameProperty: 'mapping'
    }
  }
});

Ext.define('DocumentLines',{
  extend: 'Ext.data.Model',
  fields: [
    {'name': 'line_lineItem_lineNumber', mapping: 'line.lineItem.lineNumber', type: 'string'},
    {'name': 'line_lineItem_orderedQuantity', mapping: 'line.lineItem.orderedQuantity', type: 'string'},
    {'name': 'line_lineItem_orderedUnitPackSize', mapping: 'line.lineItem.orderedUnitPackSize', type: 'string'},
    ...
});

Reading JSON data in this format works efficiently:

{
  "data": {
    "document": {
      "header": {
        "documentReceiveDateTime": "2014-03-25T08:34:24",
        "documentProcessDateTime": "2014-03-25T08:44:51",
        "documentID": "83701540",
        ...,
        "lines": [
          {
            "line": {
              "lineItem": {
                "lineNumber": "1",
                "orderedQuantity": "5.000",
                "orderedUnitPackSize": "1.000"
              }
            }
          },
          {
            "line": {
              "lineItem": {
                "lineNumber": "2",
                "orderedQuantity": "4.000",
                "orderedUnitPackSize": "1.000"
              }
            }
          }
        ]
        ...

However, I am facing issues with the writer when attempting to save the document. My output appears as follows:

{ lines: 
   [ { line_lineItem_lineNumber: 1,
       line_lineItem_ean: '4352345234523',
       line_lineItem_orderedQuantity: '45'} ],

(other parts of the document are expanded correctly)

Therefore, I pose the following question: Is there a way to make it function according to my requirements? ...or should I resort to implementing a workaround on the server side (which I am currently doing)...

Thank you in advance.

Answer №1

When faced with this decision, you have two paths to choose from:

  • The recommended method involves utilizing the store's capabilities: define your dataWriter and implement a custom function to generate the desired json.
  • If you prefer an alternative approach, you can bypass the store for updating records by creating the json yourself and using an Ajax request to update specific records.

Both options involve the use of Ajax, but the first option is typically preferred.

To implement the data writer, consider defining it within the same file as the store, like so:

Ext.define('MyApp.custom.Writer',{
    /*
     * Formats the data for each record before sending it to the server. 
     * Override this method to customize the data format.
     */
    getRecordData: function(record) {
        var data = {};
        /*
         * Analyze and structure your record data as needed here...
         */
        data.lines = [];
        return data;
    }
});

It appears that there may be an extra layer of complexity in your Json data, as the "lineItem" may not be necessary given the existing one-to-one relationships between line -> lineItem and lineItem -> corresponding object. This could be a separate issue to address.

Answer №2

I have utilized the solution provided previously, but I would like to simplify the process for others attempting the same task.

Although Dr. Leevsey's code above was effective for me, it had a drawback of encapsulating everything within an array. In my project, it proved more beneficial to have the function return an object (with child objects) instead of always returning an array, especially when the base object is not an array.

Below is the revised code:

Ext.define('MyApp.util.customWriter',
{
    extend: 'Ext.data.writer.Json',
    getRecordData: function (record, operation) {
        var data = record;
        var me = this;
        
        var toObject = function (name, value) {
            var o = {};
            o[name] = value;
            return o;
        };
        
        var itemsToObject = function (item) {
            for (prop in item) {
                if (Array.isArray(item[prop])) {
                    me.getRecordData(item[prop]);
                }
                else {
                    if (item.hasOwnProperty(prop)) {
                        var nameParts = prop.split('.');
                        var j = nameParts.length - 1;
                        if (j > 0) {
                            var tempObj = item[prop];
                            for (; j > 0; j--) {
                                tempObj = me.toObject(nameParts[j], tempObj);
                            }
                            item[nameParts[0]] = item[nameParts[0]] || {};
                            Ext.Object.merge(item[nameParts[0]], tempObj);
                            delete item[prop];
                        }
                    }
                }
            }
        };

        if (!Array.isArray(data)) {
            data = data.getData();
            itemsToObject(data);
        }
        else {
            var dataLength = data.length;
            for (var i = 0; i < dataLength; i++) {
                itemsToObject(data[i]);
            }
        }

        return data;
    }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using jQuery to implement translation on scroll

Help needed with the translate-animate attribute. I have an image that I want to move upwards when scrolling down on the page. I understand how to use translateY(px) to shift it, but I'm unsure how to perform this translation while scrolling. I aim to ...

Retrieve data from Laravel's configuration files located in the app/config/package directory

Hi there, I am currently utilizing a Laravel package called https://github.com/greggilbert/recaptcha. I have already published the configuration files where I am supposed to store my public and private keys for the reCAPTCHA. My intention is to call this i ...

Get the name of the array using JavaScript

Here is an example of my situation: var list1 = ['apple', 'banana', 'orange']; var list2 = ['carrot', 'lettuce', 'tomato']; When I use: alert(list1) I get: apple, banana, orange. This is corre ...

What is the best way to implement or disable a function when toggling a switch in pure JavaScript?

I'm currently facing an issue with my transliteration function that is supposed to be executed only when the checkbox is checked. The problem is, even after unchecking the checkbox, the function still continues to run. const checkBox = document.que ...

Sign up with identical username and email on WordPress

I'm currently facing a challenge with implementing http://jsfiddle.net/67BUG/2/ in wordpress registration, but I have experimented with various approaches without success. Within the wp-login.php file, you can find the code here - http://pastebin.com ...

Tips for editing events in the "react-big-calendars" component

I am looking to implement a feature where users can click on events in a calendar and then edit either the dates or event titles. Can this functionality be achieved using "react-big-calendar"? If not, are there any other packages you can recommend? <Cal ...

iOS Group object persistence issue persists

I am having an issue with adding groups and events to my application. When I persist the Event object, it is added successfully without any problems. However, when I try to persist the Groups object, it does not pass over correctly. I suspect that there ma ...

What is the reason behind the sudden "explosion" in this simulation?

Trying to create a simulation of a steerable vehicle, like a plane, hovercraft, or boat, in either a gas or liquid fluid (such as air or water). The JavaScript code is based on the 3D rigid body airplane simulator from Physics for Game Developers, adapted ...

Modify HTML by replacing two consecutive tags using JavaScript

Currently working on a React project and struggling with a particular issue. My text editor seems to have trouble with certain HTML syntaxes, making the package less than ideal for my needs. The main goal is to convert the following syntax from: <p> ...

Generating a dynamic form by utilizing a JavaScript JSON object

I need assistance with creating an html form based on a JSON object’s properties. How can I target multiple levels to generate different fields and also drill down deeper to access field details? I am open to suggestions for alternative formats as well. ...

Reactivity in Vue on dynamically generated HTML elements

Experimenting with Vue 2, I attempted to generate DOM elements in the mounted hook as shown below: <div id="app"> <div id="container"> <label for="static_name">Existing field</label> <input ...

What could be causing my variable to not be stored correctly by my useState hook?

In my current setup, I have a basic form displayed within a modal window. The purpose of this form is to update my redux store with the text entered into the textbox field. I am attempting to utilize the useState hook in order to properly set the value of ...

JavaScript: Utilize MooTools to extract a string containing a specific class and then pass it through a parent function

I am facing a major issue and struggling to find a solution for it. My problem involves returning values, mostly strings, that I can utilize in various contexts. For instance, I need to verify whether something is 0 or 1 in an if/else statement, or insert ...

Exploring the power of async/await in combination with map or foreach

I am facing a challenge in retrieving multiple product prices from my database. I had initially thought of using the map or forEach methods to iterate through them and add up the prices to a variable as shown below: // Get Total exports.getTotal = (req,re ...

Ways to retrieve the final appearance of element m in array n

As a beginner in programming, my goal is to access the last position of element m within array n. The following code displays all positions of element m: var n = []; while (true) { let input = prompt("Please enter a number for the ...

Exploring the World of Google API JSON Parsing Using jQuery

I'm trying to retrieve Google search results using the Google Ajax API and then display them in a DIV element. Google presents its results in JSON format, but unfortunately, I am unsure how to handle it. I have searched extensively but have not foun ...

JavaScript - Clear the localStorage when closing the final tab of a website

Currently, I am working with AngularJS and utilizing $window.localStorage to store the username of a logged-in user. Since localStorage needs to be explicitly deleted, I have implemented an event listener for $(window).on('unload', function(){}) ...

Using Node.js to implement GET, POST, and DELETE functionalities

I have embarked on the journey of learning Node.js and I find myself in a state of confusion. Could you please guide me on how to construct effective HTTP requests for the following scenarios: 1) Retrieve all galleries from the gallerySchema using a GET ...

What are the steps to showcase a webcam stream in GLSL by leveraging Three.js?

One method of displaying a webcam video using ThreeJS involves creating a video texture, as shown below: video = document.getElementById( 'video' ); const texture = new THREE.VideoTexture( video ); texture.colorSpace = THREE.SRGBColorSpace; const ...

When nodemon is executed, it encounters an "Error: Cannot find module" issue, indicating that it may be searching in the incorrect directory

I recently encountered an issue with my Node.js project that utilizes nodemon. Despite having the package installed (located in /node_modules), I am experiencing an error when trying to start my Express server with nodemon through a script in my package.js ...