Retrieve the value of a nested JSON object using the name of an HTML form field, without the use of eval

I am facing a similar issue to Convert an HTML form field to a JSON object with inner objects, but in the opposite direction.

Here is the JSON Object response received from the server:

{
    company : "ACME, INC.",
    contact : {
        firstname : "Daffy", 
        lastname : "Duck"
    }
}

Below is the structure of the HTML form:

<form id="myform">
    Company: <input type="text" name="company" />
    First Name: <input type="text" name="contact.firstname" />
    Last Name: <input type="text" name="contact.lastname" />
</form>

This is the (pseudo)code currently being used:

var formFields; 

for (var i = 0, iMax = formFields.length; i < iMax; i++) {

    var fieldName = formFields[i].getAttribute('name');
    eval("fieldValue = responseObject."+fieldName);

}

Although my solution works, I am seeking a method to eliminate using eval. Furthermore, the solution should be able to handle form fields with multiple dots in the field name.

Answer №1

Instead of:

eval("sFieldValue = oResponse."+sFieldName); 

For singular dotted fields, you can use:

sFieldValue = oResponse[sFieldName];

This method retrieves the value using its key.

If you require more complex actions, follow these steps:

  1. Split sFieldName at each occurrence of .
  2. Iterate over the array and navigate within oResponse until you find the desired value

A sample code implementation is as follows:

var node = oResponse, parts = sFieldName.split('.');
while(parts.length > 0) {
   node = node[parts.shift()];
}
// The variable 'node' now contains the desired value

For more insights on "Member Operators":
https://developer.mozilla.org/en/JavaScript/Reference/Operators/Member_Operators

Answer №2

To effectively handle a single property, you can use the following code snippet:

sFieldValue = oResponse[sFieldName]

However, when dealing with nested data like contact.firstname, you need to split the name by dots and iterate through each part using a loop:

var aFormFields; 

for (var i = 0, iMax = aFormFields.length; i < iMax; i++) {

    var aFieldNameParts = aFormFields[i].getAttribute('name').split(".");
    var oFieldValue = oResponse;
    for(var j=0; j<aFieldNameParts.length; j++) {
        oFieldValue = oFieldValue[aFieldNameParts[j]];
    }
    var sFieldValue = oFieldValue;
}

Keep in mind that if a property doesn't exist, an error will be thrown. It's advisable to verify the existence of

oFieldValue[ aFieldNameParts[j] ]
before accessing it.

Answer №3

Instead of iterating over the input fields, a more efficient approach would be to loop through the JSON object directly:

function populateForm(form, jsonData, namespace) {
  namespace = namespace ? namespace + "." : "";
  for (var key in jsonData) {
    if (typeof jsonData[key] === "string") {
      var inputField = form.elements[namespace + key];
      if (inputField)
        inputField.value = jsonData[key];
    } else
      populateForm(form, jsonData[key], namespace + key);
  }
}

populateForm(document.getElementById("myform"), responseObject);

(not tested yet)

Answer №4

If your naming convention is consistent, you can transform the dot-notation into subscripts. Start by breaking down the field name with periods and then iterate or use recursion to convert each token into a subscript. Keep in mind that this method assumes that oResponse has a value for every field.

for (var i = 0; i < aFormFields.length; i++) {
    var sFieldName = aFormFields[i].getAttribute('name');
    var tokens = sFieldName.split('.');
    var cur = oResponse;

    for (var j = 0; j < tokens.length; j++) {
        cur = cur[tokens[j]];
    }

    sFieldValue = cur;
}

Answer №5

Consider this as a fusion of an answer and a question :)

At the moment, I am in the process of configuring my server to convert the data received from a form into JSON format, just like you...

In my scenario, the form will ultimately generate a JSON object with multiple subobjects that can have their own subobjects, leading to potential infinite recursion.

The current "solution" that I'm using feels somewhat off, but it does get the job done. The getRequestBody function takes input from req.body object in express.js, which essentially follows this structure:

{
  "ridic-ulously-deep-subobject": "value",
  "ridic-ulously-deep-subobject2": "value",
  "ridic-ulously-deep2-subobject3": "value"
}

The HTML code being utilized is:

<form>
    <input name="ridic-ulously-long-class-string" value="my value" />
  </form>

And here's the JavaScript function (designed to be generic - simply supply it with a req.body object like the one above and it should return a JSON object):

function getRequestBody(reqB){

  var reqBody = {};

  for(var keys in reqB) {

    var keyArr = keys.split('-');

    switch(keyArr.length){
      case 1:
        if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
        reqBody[keyArr[0]] = reqB[keys];
      break;

      case 2:
        if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
        if(!reqBody[keyArr[0]][keyArr[1]]) reqBody[keyArr[0]][keyArr[1]] = {};

        reqBody[keyArr[0]][keyArr[1]] = reqB[keys];
      break;

      case 3:
        if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
        if(!reqBody[keyArr[0]][keyArr[1]]) reqBody[keyArr[0]][keyArr[1]] = {};
        if(!reqBody[keyArr[0]][keyArr[1]][keyArr[2]]) reqBody[keyArr[0]][keyArr[1]][keyArr[2]] = {};

        reqBody[keyArr[0]][keyArr[1]][keyArr[2]] = reqB[keys];
      break;

      case 4:

      // ...
      //and so on, always one line longer
  }

    return reqBody;
}

Although this solution covers only 5 levels of subobjects currently, there may be instances where applications require reaching seven or even ten levels. It seems like a common predicament, yet my search yielded no results within a 10-minute span, hinting at possible missing keywords or absence of a suitable solution [as of now].

Is there someone out there with enough creativity and logic to streamline this complexity, or will I have to add further clutter to accommodate up to 10 sublevels?

I believe that the performance impact might not be significant in the end, but I genuinely prefer steering clear of creating such a monstrous function :D

Enjoy experimenting!

Jascha

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

Creating a Drop-Down Button Using HTML, CSS, and JavaScript

I am currently working with the following code: <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=PT+Sans ...

The server encountered an unexpected error while processing the request, possibly due to a

My JavaScript file includes an interval function that calls the following code: setInterval(function() { $.getJSON('/home/trackUnreadMsgs', function(result) { $.each(result, function(i, field) { var temp = "#messby" + result[i].from; ...

Validating Responses in RESTful APIs

As I work on creating a RESTful API, I find myself pondering the ideal format for validation error messages. Take, for instance, my account creation endpoint which accepts a JSON object: user: { first_name: string, last_name: string, address: { ...

Exploring the world of Node.js and the power of 64-bit var

Currently, I am developing a Node.js application that communicates via TCP with a C++ server. The server utilizes a binary protocol similar to Protocol Buffers but not identical. One of the data types returned by the server is an unsigned 64-bit integer ( ...

Using Ajax and JSON to fetch data and create multiple divs based on the number of notes retrieved from a database (using PHP and SQL)

Struggling to find a tutorial or explanation that addresses the PHP array to jQuery issue from this perspective. (Being new to all of this doesn't help!) Functional code, but not generating individual divs for each note I have functional SQL within a ...

Exploring nested objects within Vue components

Is there a way to access the arrays of objects branches and report in the response when I only have access to currentView and subTask, but not subTasks2? I am following the same approach, but can't seem to access those specific elements. Any guidance ...

JavaScript Click Event Not Functioning

I am attempting to create an interactive feature where clicking on any image will either reveal a clear version of the picture if it is blurred, or blur the picture if it is clear. The current issue I am facing is that when I click on a blurred image, it ...

What is the best way to extract information from a Django database and save it in a JSON file on my personal computer

I recently developed a school management website for a local institution near my residence, utilizing Django as the backend framework. I have successfully stored student details in the Django database. My next goal is to extract all the data from the Djang ...

Tips for inserting a property into an array of objects when it matches the specified ID

As someone new to Angular, I am encountering an issue and would appreciate some help. Here is an array of objects I am working with: signals = [{ 'signalID': '123' },{ 'signalID': '233' },{ 'signalID': &apo ...

"Using Vue 3 to teleport content to a specific element and swap out existing

I've successfully implemented the use of Vue 3 teleport to display elements within a div. Although teleport adds items to the specified element, it doesn't replace existing elements in the div. Is there a way to configure teleport to replace th ...

Updating class after refresh of ng-repeat in AngularJS/Javascript

I am currently using angularJs in conjunction with cordova. Within my ng-repeat loop, each item has an ng-click event that stores the value of the item in an array. Additionally, when I click on an item, it toggles a class on the corresponding div (using ...

"Notification: The marker element has been eliminated" encountered while attempting to restore text ranges using Rangy within a Vue component

I have a rather intricate Vue component that includes a contenteditable div. My goal is to highlight words within this div using the Rangy library and add extra markup while retaining this markup even after editing the text. Initially, I planned on asking ...

The Node.js JSON string displays as "[object Object]" in the output

Front End // js / jquery var content = { info : 'this is info', extra : 'more info' } $.ajax({ type: 'POST', url: '/tosave', data: content }); Node // app.js app.post('/tosave', funct ...

Field for user input along with a pair of interactive buttons

I created a form with one input field and two buttons - one for checking in and the other for checking out using a code. However, when I submit the form, it leads to a blank page in the php file. What could be causing this issue? UPDATE After changing fro ...

My Node.Js app refuses to run using my computer's IP address, yet works perfectly with localhost

My Node.js application is set up to listen on port 5050 of my machine: Visiting http://localhost:5050/myapp loads the app successfully. I am using the Express framework, so my listening framework looks like this: var server = app.listen(5050, '0.0.0 ...

Facilitating JSON functionality with Jersey and Grizzly

While experimenting with Jersey hosted using Grizzly, I encountered an issue where I am unable to consume and produce JSON. When making a GET request, the server returns a 500 error, and when making a POST request, it says that the media type is unsupporte ...

Is it possible to dynamically load JSON files using fetch after a component has been mounted in React?

I am faced with the challenge of handling a large number of small .json files in a directory, making it impossible to load them all into memory simultaneously due to their size. As a solution, I am looking for a way to load each .json file individually whe ...

Restrict page scrolling to the vertical position of a specified div [Using jQuery, javascript, and HTML]

Currently, I am in the process of developing a personal website that features numerous expandable items. My goal is to restrict the page scrolling to the height of the expanded item once it is opened. I do not want users to be able to scroll above or below ...

Issue with Vue.js where the v-if directive placed inside a v-for loop does not properly update when

I want to dynamically show elements from an array based on boolean values. However, I am facing an issue where the element does not disappear even after the boolean value changes. <li v-for="(value, index) in list"> <span> {{ value[0] }} & ...

Creating a constant in an AngularJS module: The definitive guide to defining module-specific constants

Within a page, numerous Angular modules are present. I have set up a constant for each module containing the version number. var module1 = angular.module('module1').constant('version', '1.2.3'); var module2 = angular.module(& ...