0

I am trying to create a script to automatically read data from a file and generate objects to generate HTML for each object then. Each object represents multiple data sequences, but this doesn't really matter here.

Since I haven't had much experience with javascript classes, I'm somewhat struggling to grasp their concept compared to other programming languages.

Say I have the following class:

class DataSet{
  title = String
  description = String
  attributes = []  

  constructor(title, description) {
    this.title = title
    this.description = description
  }
  setAttribute(a){this.attributes.push(a)}
}

From the data, I'm then creating an array of DataSet objects dataSets. Because of the input data's nature, I need to update the DataSet elements of my array iteratively.

Now, this is where I struggle because I cannot call functions, like setAttribute, as javascript doesn't know the type of an object within my array when iterating over it.

In case it's of interest, I'm simply doing a foreach loop:

for(let data in dataSets) {
  data.setAttribute(a)
}

A quick test for typeof dataSets.splice(-1) call returns object (understandably). Simply calling the function like dataSets[i].setAttribute('attribute') returns an Uncaught TypeError: dataSets[i].setAttribute is not a function.

But how can I manipulate the DataSet that is this object, and I cannot find anything similar here or mdn_web_docs?

Maybe I am completely off here, so I appreciate any help :)

  • `title = String` looks wrong. Either you meant to use TypeScript, then it should be `title: string;`, or in JS it should be just `title;` or `title = '';`. Or `title; // String`? – Bergi Mar 10 '23 at 12:24
  • "*I cannot call functions, like setAttribute, as javascript doesn't know the type of an object within my array when iterating over it.*" - no. `for(let data in dataSets) { data.setAttribute(a) }` should work just fine, if `dataSets` is actually an array of `DataSet` instances. You'll need to show us how you are constructing `dataSets` if you have trouble with this. – Bergi Mar 10 '23 at 12:27
  • @Bergi, I am basically initialising it, but you're right; It might be redundant, JS is not my main language :D. But I haven't had issues before. – Thomas Mildner Mar 10 '23 at 12:36
  • Also for testing I've been simply constructing two sample DataSet objects by `dataSets.push(new DataSet(title1, description1); dataSets.push(new DataSet(title2, description2);` and iterated as above – Thomas Mildner Mar 10 '23 at 12:38
  • Then it should work, provided there are no other objects in the `dataSets` array. Please [edit] your question to provide a runnable [mcve] – Bergi Mar 10 '23 at 12:39
  • The attributes of the DataSet object is initialised to be filled with Attribute objects themselves (due to the type of data), which is currently not the case because i didnt get as far yet. Thanks for your help already! I am too busy now but I'll update a minimal code later. Knowing that in theory it should work already helps a lot! :) – Thomas Mildner Mar 10 '23 at 12:55
  • Oh now I spotted the mistake - you're using `for … in` where you should be using `for … of`. That's why it doesn't work. – Bergi Mar 10 '23 at 14:53
  • As for `title = String`, yes it's redundant as you overwrite the property in the constructor anyway, but mostly it's wrong to assign a function (`String`) to a property should hold a string. You have the same problem in `setAttribute(a = Attribute)` - that makes the class itself the default value, not a new instance. Use `setAttribute(a = new Attribute())` if you want a default value or `setAttribute(a)` if you don't. Use a doc comment if you want to annotate the desired type of the parameter. – Bergi Mar 10 '23 at 14:55

1 Answers1

0

I tried a couple things and created the following example which mirrors the logic I use in my project.

The problem seems to lie in the way I iterate over my dataSets array. Interestingly, all works well using a for loop, but not with forEach.

Here's the complete code. If anyone could explain why for works but forEachdoes not, I would be more than happy to learn. Thanks!

class Attribute{
    constructor(height, width) {
        this.height = height
        this.width = width
    }
    get area() {
        return this.width * this.height
    }

}

class DataSet{
    attributes = []
    constructor(title, description) {
        this.title = title
        this.description = description
    }
    setAttribute(a = Attribute){this.attributes.push(a)}
    get getTitle() {return this.title}
    get getAttributes () {return this.attributes}
}

dataSets = []

dataSets.push(new DataSet("title1","description1"))
dataSets.push(new DataSet("title2","description2"))

// randomly set up attributes.
let c = 5
while (c>0) {
    dataSets[0].setAttribute(new Attribute(Math.floor(Math.random() * 10) + 1, Math.floor(Math.random() * 10) + 1))
    dataSets[1].setAttribute(new Attribute(Math.floor(Math.random() * 10) + 1, Math.floor(Math.random() * 10) + 1))
    c--;
}

// prints 'undefined'
for (data in dataSets){
    console.log(data.getTitle)
}

// prints actual data
for(let i=0; i<dataSets.length; i++){
    let data = dataSets[i]
    console.log(data.getTitle)

    for (let j=0; j<data.getAttributes.length; j++){
        console.log(data.getAttributes[j])
        console.log(data.getAttributes[j].area)
    }
}