Mossito
Mossito

Reputation: 83

Dynamic map of objects in Typescript and angular 4

I'm trying to create a map structure to fill it dynamically with information from different sources:

export class VideoDataMap {
    [videoId: string]: {
        url: string,
        name: string
    };
}

The problem is that when i assign data to the object attributes, it says the object is undefined. If I assign a string and not the object, it works. Anyone knows what i am missing here?

  public videoDataMap = new VideoDataMap();

This does not throw an error (but we are not using the object attributes)

  this.videoDataMap[videoId] = url;      

This throws an error

   this.videoDataMap[videoId].url = url;  

   error: TypeError: Cannot set property 'url' of undefined

Thank you very much Best regards

Upvotes: 0

Views: 5828

Answers (2)

rbarriuso
rbarriuso

Reputation: 821

I think the confusion comes because you've defined a Typescript class with structure, but not real fields. That is, the after constructed, you'll get a Javascript empty object, which makes complete sense as initially it's a map with no keys set.

It's easy to see looking into the transpiled code (for example using http://www.typescriptlang.org/play/)

Typescript:

export class VideoDataMap {
    [videoId: string]: {
        url: string,
        name: string
    };
}

Generated Javascript:

var VideoDataMap = (function () {
    function VideoDataMap() {
    }
    return VideoDataMap;
}());
exports.VideoDataMap = VideoDataMap;

Which means, when you do:

let videoDataMap = new VideoDataMap();

You'll get something similar to:

var videoDataMap = {}

And hence when you do videoDataMap["myVideoId1"].anyProp, you'll get the TypeError because videoDataMap["myVideoId1"] hasn't been initialized.

An alternative would be defining it like:

class VideoDataItem{
    public url: string;
    public name: string;
    constructor(u: string, n: string){
        this.url = u;
        this.name = n;
    }
}

class VideoDataMap {
    [videoId: string]: VideoDataItem;
}

And using it like in the following running example: https://glot.io/snippets/ervh3vtbg9

I hope it helps.

Upvotes: 1

LLL
LLL

Reputation: 3771

How 'bout this

if (this.videoDataMap[videoId]) // check if there's an object
    this.videoDataMap[videoId]["url"] = url; // only assign this field
else // is unassigned
    this.videoDataMap[videoId] = {url : url}; // initialize new object  

Upvotes: 2

Related Questions