Exploring various layers of nested data

I am currently developing a comprehensive global data storage system for my application (specifically an Angular JS app - although this question pertains to JavaScript in general).

I have established a 'service' that is responsible for setting the data, retrieving the data, and other related functions.

Here is how it looks:

angular.module('core').factory('dataService', function(callsService) {
  let properties = {
    globalData: {}
  };

  properties.insertData = function(data) {
    for (let x in data) {
      this.globalData[x] = data[x];
    }
    return;
  }

  properties.getData = function(data) {
    return this.globalData[data];
  }

  return properties;
});

The usage of the service would be like this:

dataService.insertData({foo: 'bar'});
dataService.getData('foo'); // 'bar'

However, issues arise when dealing with nested data structures, for example:

dataService.insertData({foo: {bar: 'hello world'}});
dataService.getData('foo'); // {bar: 'hello world'}

While this behavior is expected due to object references, how can I achieve something like:

dataService.getData('foo.bar'); // 'hello world'

or

dataService.getData('[foo][bar]'); // 'hello world'

When revisiting my 'properties.getData' method, is there a way to recursively access nested objects or employ another technique?

properties.getData = function(data) {
  return this.globalData[data]; // should be able to retrieve nested objects
}

Answer №1

New Answer:

This concise recursive function is designed to meet your specific requirements:

retrieveData = (args, data) => args.length ? this.getData(args.slice(1), data ? data[args[0]] : this.globalData[args[0]]) : data ? data : this.globalData

Simply provide an array of property arguments or array indices to fetch the desired value:

dataService.retrieveData(['arrayOfData', 2, 'propOnArrElement', 'subProp', 'desiredValue'])

Explanation:

The function's signature looks like this:

getData(args: Array, data?: any): any
,

With the following characteristics:

  1. It expects an Array as the first argument (containing the path to the nested data)
  2. An optional second argument represents the data structure being queried (either an Object or Array)
  3. The function returns the requested data in any format.

Functionality Overview:

Upon invocation,

  • Ensure no definition for the second argument, allowing access to the globalData object.
  • Check the length of the args Array (args.length ?),
    • If elements exist, initiate a recursive call (this.getData(),
      • Omit the first arg from args Array (args.slice(1),),
      • Reintroduce the data argument if applicable (data ?).
        • Accessible properties/indices are identified on the data Object/Array using the first arg element in the latest recursive call (data[args[0]] :),
        • In instances where it remains undefined (initial function call), utilize the globalData property instead (this.globalData[args[0]])).
    • Through further recursion, the data structure narrows to deeper levels while args list diminishes.
      • Once args length evaluates to false (exhausted exploration!), the function merely returns the current data object (: data ? data).
      • For calls with an empty array, the entire globalData will be returned instead (: this.globalData).

I trust you find this helpful or engaging to read. It was quite satisfying when this solution emerged while showering tonight. :P

Bonus Content:

An alternative method utilizing ES6 rest parameters and Array.reduce goes even further (enabling function calling without passing an array):

retrieveData = (...args) => args.reduce((data, arg) => data[arg], this.globalData)

Invocation example:

dataService.retrieveData('firstarg', 'secondarg', 'onemorearg', 'desireddata')

Initial Discouraging Response:

To directly fetch the data property, simply access it during function invocation:

const result = dataService.getData(‘foo’).bar

Alternatively:

const result = dataService.getData(‘foo’)[‘bar’]

Answer №2

It seems like you're asking two questions at once.

To address your first query about passing something similar to dataService.getData('foo.bar');

You have the ability to access object properties using strings in this manner:

var property = foo['bar'];

If desired, you can make this recursive like so:

var property = foo['bar']['baz'];

As for your second question, it might be related to another discussion found at this link?

Answer №3

Utilize the $parse service:

  var object = { 'a': [{ 'b': { 'c': 3 } }] };
  var accessor= 'a[0].b.c';

  var result = $parse(accessor)(object);
  console.log("result =>",result);

  // Output: 3 

A Sneak Peek at The DEMO

angular.module("app",[])
.run(function($parse) {

  var object = { 'a': [{ 'b': { 'c': 3 } }] };
  var accessor= 'a[0].b.c';
  
  var result = $parse(accessor)(object);
  console.log("result =>",result);
  
  // Output: 3 
})
 <script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
</body>

For further details, check out AngularJS $parse Service API Reference.

Answer №4

In my opinion, using an arrow function as a selector would be beneficial. Here is how you can implement it:

dataService.getData(storage => storage.foo.bar);

The corresponding function in your service should look like this:

properties.getData = function (dataSelector) {
    return dataSelector(this.globalData);
} 

Here is a practical example to demonstrate how it works:

const data = {
  prop1: {
    prop2: 1
  }
};

function getData(dataSelector) {
  return dataSelector(data);
}

const prop2 = getData(data => data.prop1.prop2);

console.log(prop2);

If you prefer not to use arrow functions as selectors, you could also use regex to split the string. Here's an alternative approach:

properties.getData = function(data) {  
  var props = data.replace(/\]/g,'').split(/\.\[/g);

 return props.reduce((obj, prop) => obj[prop], this.globalData);

} 

For more information, you may find this article helpful.

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

Is there a way to automatically close one menu when another is opened by clicking?

When all other search results have failed to solve my issue, I resort to posting my own question. My problem involves opening hidden submenus in a website's main menu. However, when I open multiple submenus, they just stack above each other. Ideally, ...

The issue of ng-checked not functioning correctly in conjunction with ng-change and ng-model

There is a checkbox that should only be checked if a certain property is false. The HTML code for this checkbox is as follows: <input type="checkbox" ng-model="list.IsProject" ng-checked="list.IsProject==false" name="IsProject" id="IsProject" ng-chang ...

The baffling quirks of variables within a Jquery loop

Unfortunately, I'm struggling to come up with a more fitting title for my question, but I'll do my best to provide a clear explanation of my issue. Here is the code snippet I am working with: let pdfInvoice_sub_template = [ {text: '{ ...

Live search bar feature with jQuery更新

I am currently working on creating a dynamic search bar that updates a list of items from the database based on the input value. Below is the code I have developed for this search bar: $(document).ready(function(){ $('#search').keyup(function ...

After changing pages, the checkbox's state is reset to empty

I am currently working with an array of objects structured as follows: const columns = [ { key: "Source_campname", title: "TS Camp Name", customElement: function (row) { return ( <FormControlL ...

Two interdependent select fields

I am currently working on creating two select fields where, upon selecting an option in the first field, some options in the second field should be hidden. I have almost achieved this, but my script is unable to locate certain options in the first select f ...

constructing a nested container using XMLHttpRequest

I am working on creating a nested div-container structure using AJAX and adding the text "Hello World" to the inner container. The outer container serves as a holder for the inner container in this case. Below is the code I have written: index.html: ...

Select elements from a PHP loop

As part of my school project, I am developing a basic webshop. Currently, I am using a while loop to display featured products on the homepage. However, I now need to implement a shopping cart functionality. After a user clicks the "add to cart" button, th ...

What methods can be used to authenticate the user's input?

I am facing an issue with my program where it breaks if there is a space behind the last number entered. I want to prevent the function from breaking when a space is entered. I tried using $.trim but couldn't get it to work. I also attempted using an ...

What is the best way to determine the count of elements in an array that have the active property set to true?

Can anyone help me figure out the most efficient way to solve this problem? (Filter, ng-repeat, or another method?) <div>Number of active items: {{product.length}} </div> //total number of items <div>Number of inactive items: {{product.l ...

Within jQuery lies the power to perform multiplication operations effortlessly

I'd like to accomplish this using jQuery: var menuItems = document.getElementsByTagName("li"); for (var k = 0; k < menuItems.length; k++) { if (menuItems[k].className == "menu") { var child = menuItems[k].firstChild; if ...

What is the best way to implement switchMap when dealing with a login form submission?

Is there a better way to prevent multiple submissions of a login form using the switchMap operator? I've attempted to utilize subjects without success. Below is my current code. import { Subject } from 'rxjs'; import { Component, Output } ...

The error message "gaq is not defined in opencart 2.0" indicates

While attempting to monitor transactions in OpenCart, I encountered the following error message: Uncaught ReferenceError: _gaq is not defined(anonymous function) This is the method I am using for tracking in my catalog/view/theme/default/template/commo ...

Having trouble getting rid of the border-bottom?

I have been attempting to customize the appearance of the React Material UI tabs in order to achieve a design similar to this: https://i.stack.imgur.com/tBS1K.png My efforts involved setting box-shadow for the selected tab and removing the bottom border. ...

Pug does not have access to computed properties within the dynamic class attribute of a Vue component

After attempting to dynamically toggle the className based on computed property and encountering issues in Pug, I found that manually setting 'true' to a className was the solution. Even after trying to reassign the computed property to a Pug var ...

Verify the password by checking each character as you type

Currently, I am trying to implement a real-time password matching feature. Is there anyone who can provide me with the code that verifies whether the entered passwords match character by character as they are being typed, and also checks the length upon ...

Making an AJAX call to a PHP script to add data

Could you assist me in understanding why my code is resulting in a double insert? I have a JavaScript function that makes an AJAX request to a save.php file to insert data into a database. However, each time I submit it, it performs the insertion twice, al ...

How to Create a Speech Bubble in SVG Using SnapSVG

In the process of developing a chat program, I have animated figures moving across the screen engaging in conversations. One crucial aspect I am yet to implement is creating scalable speech bubbles for when users interact. Being relatively new to SVG and ...

React JS does not allow TextField and Select to change

I am relatively new to full stack development and I am currently working on a project to enhance my understanding of frontend development with React JS. While working on this project, I have been using Redux without any issues so far. However, I am facing ...

Using AngularJS to update attributes in an HTML tag within a string

My string contains HTML tags : var str = "<div><p></p><p><i>blabla</i></p><p><i><b>blaaaaaablaaaaa</b></i></p><iframe src='urlAAA' height='400' width=&ap ...