Searching recursively for keys with empty values in an array using Javascript

I've written a function that recursively locates empty values in a nested array.

The function initially produces the correct value, but it seems to reset it to the input value before returning the result.

What could I be overlooking?

Below is my code snippet:

const obj = [
  {
    mainContact: true,
    contactName: "",
    emailId: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0f6e6d6c4f68626e6663216c6062">[email protected]</a>",
    contactAddress: [
      {
        addressType: "",
        county: "U.K.",
        postCode: "MK7 6BZ",
        houseFlatNumber: 1
      },
      {
        addressType: "def",
        county: "France",
        postCode: "123MKO",
        houseFlatNumber: "223"
      }
    ],
    phoneDetails: [
      {
        notes: "",
        phoneNumber: "1234567899",
        countryCode: "44",
        priority: "1"
      },
      {
        notes: "Lorem ipsum",
        phoneNumber: "1112223331",
        countryCode: "48",
        priority: "2"
      }
    ]
  }
];

function validateObject(obj, isValid) {
  for (var propName in obj) {
    if (typeof obj[propName] === "object") {
      this.validateObject(obj[propName], isValid);
    } else if (
      obj[propName] === null ||
      obj[propName] === undefined ||
      obj[propName] === ""
    ) {
      isValid = false;
      break;
    }
  }
  return isValid;
}

console.log(validateObject(obj), true);
// The expected output should be false, yet it returns true even though it first encountered and set isValid to false

Any assistance would be highly appreciated.

Thank you.

Answer №1

When it comes to recursion, one important thing to remember is that you must always ensure to return the value from your recursive call. This involves calling the function from within itself and then handling the return value appropriately.

Upon analyzing your function, I have made some adjustments by introducing a basic base case to verify if the input value is null, undefined, or an empty string.

function isValidObject(obj) {
  // Base case
  if (obj[propName] === null || obj[propName] === undefined || obj[propName] === '') {
    return false;
  }
  
  // Recursively check each item in object
  if (typeof obj === "object") {
    for (var propName in obj) {
      if (!isValidObject(obj[propName]) {
        return false;
      }
    }
  }
  return true;
}

It's worth noting that this modification eliminates the need for a boolean parameter in your function by simply returning false when the first invalid condition is encountered.

Answer №2

The main issue at hand is the failure to return the value of the recursive call. This means that you are essentially creating an inline recursive loop and then returning the result from the higher callable.

Furthermore, due to isOk being a primitive boolean, it follows pass by value behavior rather than pass by reference. Consequently, any changes made to isOk within a nested function do not affect the variable in the parent context.

It's important to note that this rule does not extend to obj[propName], which operates on pass by reference principles. As a result, any alterations made to the data inside the function will be reflected outside of its scope.

function validateObject(obj) {
  for (var propName in obj) {
    if( typeof obj[propName] === "object" ) {
      if( validateObject(obj[propName]) === false ) {
        // The updated status will be passed up through the call stack
        return false;
     }
   } 
   else if (
     obj[propName] === null      || 
     obj[propName] === undefined || 
     obj[propName] === ''
   ) {
     return false;  // no variable required here
   }
 }
 return true;  // logic dictates - if nothing is false, it must be true
}

Answer №3

A different approach involves creating a versatile function that recursively checks the validity of object properties based on a given predicate.

It's not complex, in my opinion, and is often easier than directly writing a specialized function. Applying it to a specific scenario is also straightforward.

Here's an example:

const checkValidity = (predicate) => (object) =>
  Object.values(object).every(
    value => (value && typeof value === 'object') ? checkValidity(predicate)(value) : predicate(value)
  )

const noEmptyValues = checkValidity(val => val !== '' && val != null)

const objectExample = [{mainContact: true, contactName: "", emailId: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bedfdcddfed9d3dfd7d290ddd1d3">[email protected]</a>", contactAddress: [{addressType: "", county: "U.K.", postCode: "MK7 6BZ", houseFlatNumber: 1}, {addressType: "def", county: "France", postCode: "123MKO", houseFlatNumber: "223"}], phoneDetails: [{notes: "", phoneNumber: "1234567899", countryCode: "44", priority: "1"}, {notes: "Lorem ipsum", phoneNumber: "1112223331", countryCode: "48", priority: "2"}]}]

console.log(noEmptyValues(objectExample))

Answer №4

Big shoutout to James McGuigan for helping me refine this piece of code:


isValidObject(obj) {

    for (var propName in obj) {
        if( typeof obj[propName] === "object" ) {
            if( this.isValidObject(obj[propName]) === false || 
                obj[propName] === null || 
                obj[propName].length === 0 ) 
            {
                return false;
            }
        } 
        else if (
                obj[propName] === null      || 
                obj[propName] === undefined || 
                obj[propName] === '' 
                ) {
                    return false;  
                }
    }
    return true;  

}

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

Ways to extract a single digit from the total sum of a date in the format of 15-06-2015

Is there a way to extract a single digit from the sum of a number in date format, such as 15-06-2015? My goal is to convert the date format 15-06-2015 into a single-digit value by adding up the numbers. For instance: In the case of 15-05-2015, the output ...

What is the best way to incorporate an exception for the printThis() element?

Is there a way to exclude a specific div from being printed when using the printThis() function? For example: <div id="print-it"> <div>hello</div> <div id="no-print-this"> <button>must be show on page but not print</but ...

Empty Data Table Search After Refresh While Filter Remains Active

After testing the data tables library using their example code in a jsfiddle, it seems like there might be a bug. To recreate the issue, follow these steps: Open the JS Fiddle link https://jsfiddle.net/t4rphnuc/ Click "Run" In any footer search box, fil ...

Sending Data in Angular JS

Looking for guidance on Angular JS as a newcomer. I have set up a form on my index.html page, and when the user fills in the details and hits submit, I want it to redirect to a details.html page where all the filled-in information can be displayed. HTML ...

Stop $watchCollection from initializing on start

I have an array called "$scope.postits" that I want to persist every time it changes. To achieve this, I added a $scope.$watchCollection on this element to monitor changes and save the data. The issue is that the $watch function gets triggered 3 times when ...

"Need help passing an API key in the header of a Vue.js project? I recently encountered this issue while using a

How can I include an API key in the header of a Vue.js request? I am using DRF pagination. methods: { getPostData() { axios .get("http://192.168.43.126:8000/api/?page=" + this.currentPage, { headers: { &q ...

The drop-down menu appears to be falling behind the 'content' div element

Whenever I try to hover over the dropdown menu, it frustratingly appears behind the content div that I painstakingly created. Despite all my efforts with z-index adjustments, the issue still persists. Below you'll find all the code for my website, but ...

Generate visual representations of data sorted by category using AngularJS components

I am facing an unusual issue with Highcharts and Angularjs 1.6 integration. I have implemented components to display graphs based on the chart type. Below is an example of the JSON data structure: "Widgets":[ { "Id":1, "description":"Tes ...

The function call to 'import firebase.firestore()' results in a value

I recently set up a Vue App with the Vuefire plugin. Here is an example of my main.js file, following the documentation provided at: : import Vue from 'vue' import App from './App.vue' import router from './router' import sto ...

I am facing difficulties accessing an element within a controller in Angular

Struggling to access an element inside an AngularJS controller, I attempted the following: var imageInput = document.getElementById("myImage"); Unfortunately, this approach was unsuccessful as the element returned null. Curiously, when placing the statem ...

Comparison between setTimeout for this.state and useState

When working with a class component, the code looks like this: setTimeout(() => console.log(this.state.count), 5000); Whereas when using hooks: const [count, setCount] = useState(0); setTimeout(() => console.log(count), 5000); If the setTimeout fun ...

Express application receiving repetitive post requests

Recently, I have been working on developing a YouTube video conversion app that utilizes youtube-dl for streaming videos from YouTube and saving them. Everything was going smoothly until I encountered an issue when trying to stream a video that exceeded on ...

The functionality of the Protractor right click feature is smooth, however, there seems to be an issue with selecting

Even though I can locate the button within the context menu, I am facing difficulty in clicking it. The code mentioned below is successfully able to click the button, but an error message pops up indicating: Failed: script timeout (Session info: chr ...

Retrieving values from multiple Select components in Material-UI is key

I have encountered an issue with my two MUI Select components on the page. I am attempting to set values based on the id of the Select component. Initially, when I check (id === "breed-select") in the console, it returns true, but shortly after ...

What is the best way to present JSON data retrieved from an API on different pages using Next.js?

I am currently working on two pages that are connected: one is an API page called secured.js (where user session data is processed) and the other is a normal page also named secured.js (which displays the processed content from the API page). This is the ...

Utilize mapping function to merge arrays

Currently facing an issue with no clear solution in sight. When making API calls via a map, I am able to successfully log all results individually. However, my challenge lies in combining these results into a single array. var alpha = ['a', &apo ...

Testing the updated version 18 of Create React APP index.js using Jest

Previously, I had this index.js file created for React version <= 17. import React from 'react'; import ReactDOM from 'react-dom'; import App from './views/App'; import reportWebVitals from './reportWebVitals'; im ...

Setting up the customized filename for precompiled Handlebars templates

When compiling Handlebars templates with the NPM package, is there a way to manually adjust the name/index that is generated? In my experience using Handlebars in various environments like Rails, NodeJS, and PHP, I've observed that the generated temp ...

express-validator: bypass additional validation in a user-defined validator

Utilizing the express-validator package for validating my request data. As per the documentation, we need to declare them in this manner: app.use(expressValidator({ customValidators: { isArray: function(value) { return Array.isArray(value); ...

Warning: Non-power of two image detected in Three.js

Encountering an issue with a warning in three.js that says: THREE.WebGLRenderer: image is not power of two (600x480). Resized to 512x512. Attempted to resolve it by adding THREE.LinearFilter, but no luck. var texture = new THREE.TextureLoader().load(data[ ...