0

I have a function that takes in an object as a prop and needs to add arrays to it using a for loop. My problem is that it only works if a single array is added when it is called. If more than one array is to be added, I receive the error linkLineItems.push is not a function, but I thought .push could be used to add arrays to objects.

Here is the function:

function PrepareSuccessorActivityLinkData(data, existingLinks, linkSetter) {
  for (let [key, value] of Object.entries(data)) {
    let linkLineItems;
    let linkLineItem;
    if (data.activitiesafter[0] != "DEFAULT") {
      for (var i = 0; i < data.activitiesafter.length; i++) {
        linkLineItem = {
          source: data.itemname,
          target: data.activitiesafter[i],
          type: "activity-activity-after"
        };
        if (!linkLineItems) {
          linkLineItems = linkLineItem;
        } else {
          linkLineItems.push(linkLineItem);
        }
      }
    } else {
      continue;
    }
    return linkSetter(linkData => [...existingLinks, linkLineItems]);
  }
}

Any help on how to add multiple arrays to an object?

Edit #1: Sample data for the existingLinks or object that I'm trying to add items to

var linksData = [
 {"source": "Do Something", "target": "My Document", "type": "Activity Output"},
 {"source": "My Document", "target": "Operator", "type": "Object Responsible"},
 {"source": "Operator", "target": "Do Something", "type": "Role Activity"}
];

Edit #2: Sample data that's being passed into the function as data

[{
 itemname: "Hello World", 
 itemtype: "activity", 
 activitiesafter: ["Do Stuff", "Do Other Stuff"]
}]

10
  • 2
    You can't push onto an object. Set a property instead linkLineItems.something = [] Commented Apr 5, 2020 at 20:45
  • 1
    push can only be used on Arrays. It would be helpful if you add some example input/output data. It's a little difficult to tell exactly what your desired behavior is here Commented Apr 5, 2020 at 20:46
  • @schu34 I added sample data. The function needs to be able to add more than one array at a time (based on the activitiesafter for loop. Commented Apr 5, 2020 at 20:55
  • 1
    @usernick I am not discussing your problem, I am stating that calling linkSetter and so on is not what you have trouble with. The difficulty you encounter is just to build linkLineItems out of data passed as argument. All the context is not that useful. The two things which matter (and that we miss) are the content of data (if need be console.log(JSON.stringify(data)) and the expected linkLineItems which should be constructed Commented Apr 6, 2020 at 12:34
  • 1
    @grodzi I added edit #2 to the main post to show the data being passed into the function Commented Apr 6, 2020 at 13:46

2 Answers 2

1

Some self proclaimed best practices:

  1. Avoid if possible for-loops when you don't need indices. (see forEach and alike). This allows less variables which pollute your eyes.
  2. Make early "continue" or "return" to avoid nesting stuff (e.g return links comes first)
  3. Try to reduce at max the scope of your variables. This is also achieved here by using forEach

function nameTooLong(data, existingLinks, linkSetter) {
  const moreLinks = data.reduce((links, item) => {
    if (item.activitiesafter[0] === "DEFAULT") {
      return links
    }
    item.activitiesafter.forEach(activity => {
      links.push({
        source: item.itemname,
        target: activity,
        type: "activity-activity-after"
      })
    })
    return links
  }, [])
  return linkSetter(_ => existingLinks.concat(moreLinks))
}

nameTooLong([{
 itemname: "Hello World", 
 itemtype: "activity", 
 activitiesafter: ["Do Stuff", "Do Other Stuff"]
},{
 itemname: "shold be ignored", 
 itemtype: "activity", 
 activitiesafter: ["DEFAULT", "nothing there"]
}], ['toto'], (fn) => console.log('newlinks: ', fn()))

If you read 3., we can do better and even avoid manipulating the variable links by using flatMap

function nameTooLong(data, existingLinks, linkSetter) {
  const moreLinks = data.flatMap(item => {
    if (item.activitiesafter[0] === "DEFAULT") {
      return []
    }
    return item.activitiesafter.map(activity => ({
      source: item.itemname,
      target: activity,
      type: "activity-activity-after"
    }))
  })
  return linkSetter(_ => existingLinks.concat(moreLinks))
}

nameTooLong([{
 itemname: "Hello World", 
 itemtype: "activity", 
 activitiesafter: ["Do Stuff", "Do Other Stuff"]
},{
 itemname: "shold be ignored", 
 itemtype: "activity", 
 activitiesafter: ["DEFAULT", "nothing there"]
}], ['toto'], (fn) => console.log('newlinks: ', fn()))

Sign up to request clarification or add additional context in comments.

3 Comments

This is awesome, I didn't know about flatMap. However, I'm getting the error data.flatMap is not a function when plugging the function into my app. It's weird because I can console.log(data), store it as a variable in the console, and data.flatMap works there. Any ideas?
Answering my own question from my last comment. I got it to work if I instantiated the array by wrapping data in [ ]. So the function starts with const moreLinks = [data].flatMap(item => {
@userNick if data is not an array (in your real work case), then you don't need to iterate over data, just process the plain object!
0

The push function only works on arrays, not on objects.

And since I don't see any reason linkLineItems needs to be an object I would suggest you just make it an array by initialising it with let linkLineItems = [];.

1 Comment

I made some updates to the original post to provide more context, but initializing the array with [ ] does not seem to result in the desired result of adding multiple arrays to a parent object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.