Ata Mohammadi
Ata Mohammadi

Reputation: 3550

Javascript: variable is not undefined but while returning, being returned undefined

In the snippet below, before return(res) , I log it, and it's not undefined

but somehow, it's being returned as undefined.

What am I doing wrong?

filterData = (inputData, searchedKey) => {
  inputData.forEach((data, index) => {
    if(data){
      if(data.hasOwnProperty(searchedKey)){
        const res = data[searchedKey]
        console.log(res) /// logs the results
        return(res) /// returns undefined
      }
      var dataToProcess = [];

      var fieldKeys = Object.keys(data)
      fieldKeys = fieldKeys.filter((field, index) => !field.includes("#"))
      fieldKeys.forEach((key, index) => {
        dataToProcess.push(data[key]);
      })
      this.filterData(dataToProcess, searchedKey)
    }
  })
}

console.log(this.filterData([{"#name": "foo", "#type": "bar"}], "#type"))

Upvotes: 1

Views: 77

Answers (2)

trincot
trincot

Reputation: 350272

Some issues:

  • forEach does not return anything else than undefined, so returning a value in its callback function does not do anything useful.
  • Your function does not return a value
  • The return value of the recursive call is not used.
  • if (data) is not good enough to make sure data is an object. For instance, it would also be true for a non-zero number. Use Object(data) === data instead.
  • Since there could be multiple matches (in a nested input object), your function should return an array, which is also what someone would expect when seeing your function name. Also the standard array filter method returns an array. So it would be in line with that.

Here is how you could make it work:

var filterData = (inputData, searchedKey) => {
    inputData = inputData.filter( data => Object(data) === data );
    return !inputData.length ? [] :
        inputData.filter( data => data.hasOwnProperty(searchedKey) )
            .map( data => data[searchedKey] )
            // Add the results from recursion:
            .concat(filterData([].concat(...
                inputData.map( data =>
                    Object.keys(data)
                        .filter( key => !key.startsWith("#") )
                        .map( key => data[key] )
                )
            ), searchedKey));
};

var data = [{
    "#name": "foo", 
    "#title": "mr",
    "deeper": [{
        "#nope": "bad",
        "deepest": [{
            "nothing_here": null,
            "#type": "deeper bar",
        }]
    }, {
        "#type": "bar",
    }]
}];

console.log(filterData(data, "#type"));

If you need only the first match, then use this variant:

var filterData = (inputData, searchedKey) => {
    inputData = inputData.filter( data => Object(data) === data );
    var res = inputData.find( data => data.hasOwnProperty(searchedKey) );
    return res !== undefined ? res[searchedKey] :
        // Try in nested objects:
        filterData([].concat(...
            inputData.map( data =>
                Object.keys(data)
                    .filter( key => !key.startsWith("#") )
                    .map( key => data[key] )
            )
        ), searchedKey);
};

var data = [{
    "#name": "foo", 
    "#title": "mr",
    "deeper": [{
        "#nope": "bad",
        "deepest": [{
            "nothing_here": null,
            "#type": "deeper bar",
        }]
    }, {
        "#type": "bar",
    }]
}];

console.log(filterData(data, "#type"));

Upvotes: 1

PeterMader
PeterMader

Reputation: 7285

Is this what you want to achieve?

filterData = (inputData, searchedKey) => {
  return inputData.map((data, index) => {
    if(data){
      if(data.hasOwnProperty(searchedKey)){
        const res = data[searchedKey]
        console.log(res) /// logs the results
        return(res) /// returns undefined
      }
      var dataToProcess = [];

      var fieldKeys = Object.keys(data)
      fieldKeys = fieldKeys.filter((field, index) => !field.includes("#"))
      fieldKeys.forEach((key, index) => {
        dataToProcess.push(data[key]);
      })
      this.filterData(dataToProcess, searchedKey)
    }
  })
}

console.log(this.filterData([{"#name": "foo", "#type": "bar"}], "#type"))

Use Array#map(), it's pretty useful in many cases.

Upvotes: 0

Related Questions