Guide to swapping out embedded objects within a TypeScript data structure

I am in need of modifying a TypeScript object by conducting a key search. It is important to note that the key may be repeated within the object, so I must ensure it belongs to the correct branch before making modifications to the corresponding object. To illustrate, consider the following initial object:

{
   requirements: {
     general_info: {
       aircraft: {
         payload: { '@_unit': 'kg' },
         autopilot_ratio: '',
       },
       power: {
         number_of_engines: '',
       },
       geometrical: {
         payload: { '@_unit': 'kg' },
         design_approach: { target: '' },
       },
     },
   },
}

After modification, the object should appear as follows:

{
   requirements: {
     general_info: {
       aircraft: {
         payload: { '@_unit': 'hg', '#text': 3000},
         autopilot_ratio: '',
       },
       power: {
         number_of_engines: '',
       },
       geometrical: {
         payload: { '@_unit': 'kg' },
         design_approach: { target: '' },
       },
     },
   },
}

A recursive function is necessary to achieve this. I have attempted to write a function for this purpose, but I am facing difficulties in preventing nested objects from being inserted multiple times.

const updateObject = (json: any, searchKey: string, unit: string, value: number): Object => {
  return Object.keys(json).map((key: string) => {
    if (key !== searchKey && typeof json[key] !== 'string') {
      return updateObject(json[key], searchKey, unit, value);
    } else {
      if (typeof json[key] !== 'string') {
        json[key]['@_unit'] = unit;
        json[key]['#text'] = value;
        return json;
      } else {
        return json;
      }
    }
  });
};

console.dir(updateObject(json, 'payload', 'hg', 3000), { depth: null });

Additionally, it would be beneficial to pass

requirements.general_info.aircraft.payload
as the searchKey in order to modify only the desired instance.

EDIT The format of the object { '@_unit': 'kg' } is predetermined and I already know in advance that it will be replaced with { '@_unit': 'hg', '#text': 3000}. The challenge lies in replacing it at the correct position within the JSON structure, as it is not a distinct occurrence. A simple

JSON.parse(JSON.stringify(json).replace()
operation would not suffice in this scenario.

Answer №1

After taking into consideration the suggestions from T.J. Crowder and derpirscher, I developed a non-recursive function to address the issue:

const dataPath = 'info.data.airline.passenger';
const updatedJson = updateDataObject(jsonData, dataPath, 'kg', 5000);

const updateDataObject = (data: any, path: string, unit: string, value: number): Object => {
  const keys = path.split('.');

  if (allDataPaths(data).includes(path)) {
    let tempData = data;
    keys.forEach((key: string) => {
      tempData = tempData[key];
    });
    tempData['@_unit'] = unit;
    tempData['#value'] = value;
    return data;
  } else {
    throw new Error('Invalid data path provided');
  }
};

Answer №2

Consider implementing lodash in your code.

import _ from 'lodash'

function modifyData(obj: any, path: _.PropertyPath, unit: string, value: number) {
  if (_.has(obj, path)) {
    _.setWith(obj, path, { '@unit': unit, '#text': value })
  }
  return obj
}

let dataPath = 'records.data.info.payload'
// or use array notation:
// dataPath = ['records', 'data', 'info', 'payload']
console.log(modifyData(dataObj, dataPath, 'kg', 5000), { depth:null })

Don't forget to install lodash library and its type definitions for TypeScript.

npm -i lodash
npm -i --save-dev @types/lodash

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

Leverage the specific child's package modules during the execution of the bundle

Project Set Up I have divided my project into 3 npm packages: root, client, and server. Each package contains the specific dependencies it requires; for example, root has build tools, client has react, and server has express. While I understand that this ...

The method beforeEach in angular2/testing seems to be failing as it is not

Currently, I am utilizing Gulp, Gulp-Jasmine, and SystemJS to conduct tests on an Angular2 demo application. The setup is fairly straightforward. I have successfully implemented a System.config block and loaded the spec file. However, I encounter an error ...

Using TypeScript with .env file variables: a step-by-step guide

I stored my secret jwt token in the .env file. JWT_SECRET="secretsecret" When I attempt to retrieve the value using process.env.JWT_SECRET, I encounter an error: Argument of type 'string | undefined' is not assignable to parameter of t ...

Typescript encountering issues with addEventListener

const [status, setStatus] = useState<string>("pending"); const updateStatus = (newStatus: string) => { setStatus(newStatus); }; useEffect(() => { window.addEventListener("updateProtocol", updateStatus); return () =&g ...

Customize back button functionality in Ionic 2

Is it possible to modify the behavior of the back button shown in this image? I would like to specify a custom destination or perform an action before navigating back, instead of simply returning to the previous page. https://i.stack.imgur.com/EI2Xi.png ...

What is the correct way to integrate knex using inversify?

Is there a way for me to set up knex and utilize the Inversify dependency injector to inject it wherever it is required? ...

Is it possible to utilize useEffect for verifying the existence of the user token within the localStorage?

I am in the process of developing a web application that requires authentication. I am wondering if it is effective to create a private route by adding a condition in the useEffect hook of one of my pages. The idea is to check if a token is present before ...

"Encountering issues with DefinePlugin when using the combination of Ionic, Angular, Webpack,

I'm trying to incorporate my process.env variable into the webpack Bundle using DefinePlugin. Here's the snippet of code in my webpack config: plugins: [ new webpack.DefinePlugin({ 'process.env': JSON.stringify(process.env) ...

Encountered an error while trying to access an undefined property in Angular

Trying to perform a basic import, but encountering a significant stack trace issue. Extensive search efforts have been made to address this problem, yet the stack trace lacks sufficient information for resolution. UPDATE: When setting a variable not sour ...

Ways to switch up the titles on UploadThing

Recently, I started working with the UploadThing library and encountered a situation where I needed to personalize some names within the code. Here is what I have so far: Below is the snippet of code that I am currently using: "use client"; imp ...

Is there a way to trigger a custom event from a Web Component and then intercept it within a React Functional Component for further processing?

I'm facing an issue with dispatching a custom event called "select-date" from a custom web component date picker to a React functional component. Despite testing, the event doesn't seem to be reaching the intended component as expected. Below is ...

Tips on clearing and updating the Edit Modal dialog popup form with fresh data

This code snippet represents my Edit button functionality. The issue I am facing is that I cannot populate my Form with the correct data from another component. Even when I click the (Edit) button, it retrieves different data but fails to update my form, ...

Issue with Typescript - Node.js + Ionic mobile app's Angular AoT build has encountered an error

Currently, I am in the process of developing an Android application using Node.js and Ionic framework. The app is designed to display random text and images stored in separate arrays. While testing the app on Chrome, everything works perfectly fine. Upon ...

Ways to reload a page in Angular using routerLink and ID

I am working on an Angular application that involves navigation using routerlinks. My goal is to navigate to a specific user page by ID if the page is already open and meets certain conditions. In my .component.ts file, I have the following code snippet: ...

What is the method for retrieving the name of an object's property within an Angular template

I am trying to display the name of a nested object's property using Angular interpolation <ng-container ngFor="let item of saleDetailsAggegater.productMap | keyvalue"> <tr *ngFor="let qtyMap of item.value | keyvalue"&g ...

Issue encountered with TypeORM and MySQL: Unable to delete or update a parent row due to a foreign key constraint failure

I have established an entity relationship between comments and posts with a _many-to-one_ connection. The technologies I am utilizing are typeorm and typegraphql Below is my post entity: @ObjectType() @Entity() export class Post extends BaseEntity { con ...

Double Calling of Angular Subscription

I am currently working with a series of observables that operate in the following sequence: getStyles() --> getPrices() Whenever a config.id is present in the configs array, getStyles() retrieves a style Object for it. This style Object is then passed ...

Ensuring uniqueness in an array using Typescript: allowing only one instance of a value

Is there a simple method to restrict an array to only contain one true value? For instance, if I have the following types: array: { value: boolean; label: string; }[]; I want to make sure that within this array, only one value can be set to t ...

React.js: You cannot call this expression. The type 'never' does not have any call signatures

Could someone help me troubleshoot the error I'm encountering with useStyles? It seems to be related to Typescript. Here's the line causing the issue: const classes = useStyles(); import React from "react"; import { makeStyles } from & ...

The html-duration-picker is not being displayed in the proper format

I've been working on integrating an external library that allows for inputting document length. Specifically, I'm using the html-duration-picker library, but it seems like the input functionality is not quite right for durations. Could it be th ...