wind_kind
wind_kind

Reputation: 611

mapping data gives correct results but ends up as undefined in final method

I have three different arrays. Posts, Categories and Tags. I want to get values from Categories and Tags and merge it with it's Post in the Posts array. Hopefully my code will make it clear what I am trying to achieve.

So after all is done, I am returned a new array with my _.merged data but all the values are undefined. I can't figure out what I am doing wrong here. I'm sure it's a simple mistake I am making.

Posts array

[
{
    "id": 79,
    "slug": "checkbox-code",
    "type": "post",
    "title": {
        "rendered": "Checkbox code"
    },
    "categories": [
        6
    ],
    "tags": [
        7
    ],
},
{
    "id": 77,
    "slug": "checkbox-style",
    "type": "post",
    "title": {
        "rendered": "Checkbox style"
    },
    "categories": [
        6
    ],
    "tags": [
        8
    ],
},
{
    "id": 75,
    "slug": "checkbox-usage",
    "title": {
        "rendered": "Checkbox usage"
    },
    "categories": [
        6
    ],
    "tags": [
        9
    ],
},
]

Categories array

[
{
    "id": 6,
    "name": "checkbox",
    "slug": "checkbox",
    "taxonomy": "category",
},
{
    "id": 5,
    "name": "buttons",
    "slug": "buttons",
    "taxonomy": "category"
}
]

Tags array

[
{
    "id": 7,
    "name": "code",
    "slug": "code",
    "taxonomy": "post_tag",
},
{
    "id": 8,
    "name": "style",
    "slug": "style",
    "taxonomy": "post_tag",
},
{
    "id": 9,
    "name": "usage",
    "slug": "usage",
    "taxonomy": "post_tag",
}
]

My Code

getTagName = (id) => {
  this.tags.map(tag => {
    if(id == tag.id) {console.log('tag name ' + tag.name)}
    return id == tag.id ? tag.name : null
  })
}

getCatName = (id) => {
  this.cats.map(cat => {
    if(id == cat.id) {console.log('category name ' + cat.slug)}
    return id == cat.id ? cat.slug : null
  })
}

componentWillMount() {
  let arr = [];
  for(let i=0; i<this.posts.length; i++) {
    let tagName = this.getTagName(this.posts[i].tags[0]);
    let catName = this.getCatName(this.posts[i].categories[0]);
    let newObj = {
      "tag_name": tagName,
      "category_name": catName
    }

    _.merge(this.posts[i], newObj);
    arr.push(this.posts[i]);
  }
}

What I get back

[
{
    "id": 79,
    "slug": "checkbox-code",
    "type": "post",
    "title": {
        "rendered": "Checkbox code"
    },
    "categories": [
        6
    ],
    "category_name": undefined,
    "tag_name": undefined,
    "tags": [
        7
    ],
},
{
    "id": 77,
    "slug": "checkbox-style",
    "type": "post",
    "title": {
        "rendered": "Checkbox style"
    },
    "categories": [
        6
    ],
    "category_name": undefined,
    "tag_name": undefined,
    "tags": [
        8
    ],
},
{
    "id": 75,
    "slug": "checkbox-usage",
    "title": {
        "rendered": "Checkbox usage"
    },
    "categories": [
        6
    ],
    "category_name": undefined,
    "tag_name": undefined,
    "tags": [
        9
    ],
},
]

when I log the returned values in the getCatName and getTagName methods I get back the correct data. It just doesn't make it to componentWillMount. Thanks for any help.

Here is a fiddle

Upvotes: 0

Views: 45

Answers (4)

gtrenco
gtrenco

Reputation: 375

I think your problem is in your getTagName & getCatName functions...

First, functions are not returning any value out of they own scope

getCatName = (id) => {
  return cats.map(cat => {
    if(id == cat.id) {console.log('category name ' + cat.slug)}
    return id == cat.id ? cat.slug : null
  })
}

But remember, map iterates over all the array length, so it will return full sized array, with matches only on certain indexes, like this:

tag_name: (3) […] 0: "code", 1: null, 2: null, length: 3

So maybe you want to change the map for a filter, or work with your mapped data before the return

Hope it helps!

Upvotes: 0

Ben West
Ben West

Reputation: 4596

getTagName and getCatName don't return anything, so tagName and catName will be undefined.

The return statement in getTagName belongs to the function you passed to map (tag => {}). It doesn't make the outer function (id => {}) return.

Looks like you're expecting it to work like a for loop, where the return would stop the loop early and return tag.name. map doesn't work like that, it always iterates over the whole array, and returns a new array the same length. If you added a return statement into getTagName and called getTagName(8), you would get [ null, 'style', null ] - that's the result of the inner function for each item in the array.

The method you want to use is Array.find.

getTagName = id => {
    return this.tags.find( tag => tag.id === id ).name;
}

Upvotes: 2

Nicolas Gehlert
Nicolas Gehlert

Reputation: 3253

the .map() in your getTagName() and getCatName() functions do not really make sense. If you look for a specific Entry it makes sense to use Array.find().

Also you need to return the value. I updated your jsfiddle. https://jsfiddle.net/3pLj20nd/14/

getTagName = (id) => {
    return tags.find(tag => {
      return id == tag.id;
    })
}

getCatName = (id) => {
    return cats.find(cat => {
      return id == cat.id;
    })
}

componentWillMount = () => {
    let arr = [];
    for(let i=0; i<posts.length; i++) {
      let tagName = getTagName(posts[i].tags[0]).name;
      let catName = getCatName(posts[i].categories[0]).name;
      let newObj = {
        "tag_name": tagName,
        "category_name": catName
      }
      console.log(newObj);

      _.merge(posts[i], newObj);
      arr.push(posts[i]);
    }

    console.log(arr);
}

componentWillMount();

Upvotes: 1

Randy Casburn
Randy Casburn

Reputation: 14165

The return statements in both methods are returning from the Array.map() method. You are not returning a value from your getTagName() or getCatName() functions.

Keep in mind that if you return the results of the map method (ie. return this.cats.map(...)), those results will be in the form of an array.

Upvotes: 2

Related Questions