1

I'm developing in Angular 6. I want to know if there is a simple way to deal with a bunch of models describing the format of the structured sets of values in a bunch corresponding arrays. I am looking for a simple cookie-cutter approach, not custom creating code to bring in each individual element of each array into a model instance using For-loops. Some of the models are more complex, and would have several levels of nesting.

A simple case:

Model:

export class User {
    firstName = '';
    lastName = '';
    userName = '';
    email = '';
}

Array:

[
["Adam","Richardson","AdMan","[email protected]"],
["Ahmad","Ali","MarketMan","[email protected]"],
["Feng","Trunk","SuperMan","[email protected]"],
["Chris","Garcia","SmartMan","[email protected]"] 
]

Is there some way to magically overlay a model onto a values only array?

2
  • Shall I take it that you're hoping to create an array of User objects? Commented May 10, 2018 at 2:21
  • @kshetline, Actually an object with essentially arrays of objects with perhaps further levels of arrays of objects. Commented May 10, 2018 at 2:23

3 Answers 3

2

If you want a generic way of filling any object with data from an array of values, you can do the following (as long as you declare the properties in the class in the same order as the data comes in the array):

class User {
    firstName = '';
    lastName = '';
    userName = '';
    email = '';
}

const data = [
    ["Adam", "Richardson", "AdMan", "[email protected]"],
    ["Ahmad", "Ali", "MarketMan", "[email protected]"],
    ["Feng", "Trunk", "SuperMan", "[email protected]"],
    ["Chris", "Garcia", "SmartMan", "[email protected]"]
];

function fromDataArray<T>(klass: new () => T, data: any[]) {
    const obj = new klass();
    Object.keys(obj).forEach((k, i) => obj[k] = data[i]);

    return obj;
}

const users = data.map(d => fromDataArray(User, d));

One of the problems you have with making a generic method that works on nested objects is that all of the types are lost once the TypeScript is transpiled to JavaScript. The only way to eliminate that problem is to have initial objects in your classes that instantiate the properties that are supposed to be objects with an instance of that type to use.

Here is an example that would work with a nested object of such data arrays to show you that it can be done:

function fromDataArray<T>(klass: new () => T, data: any[]) {
  const obj = new klass();
  Object.keys(obj).forEach((k, i) => {
    if (Array.isArray(obj[k])) {
      if (obj[k].length && typeof obj[k][0] === "object") {
        obj[k] = data[i].map(d => fromDataArray(obj[k][0].constructor, d));
      }
      else {
        obj[k] = data[i];
      }
    }
    else if (typeof obj[k] === "object") {
      obj[k] = fromDataArray(obj[k].constructor, data[i])
    }
    else {
      obj[k] = data[i];
    }
  });

  return obj;
}

class SubClass3 {
  email = '';
}

class SubClass2 {
  userName = '';
  stuffz = [new SubClass3()];
}

class SubClass1 {
  lastName = '';
  subClass2 = new SubClass2();
}

class Class1 {
  firstName = '';
  subClass1 = new SubClass1();
}

const data = [
  ["Adam", ["Richardson", ["AdMan", [ [ "[email protected]"] ]]]],
  ["Ahmad", ["Ali", ["MarketMan", [ [ "[email protected]"] ]]]],
  ["Feng", ["Trunk", ["SuperMan", [ [ "[email protected]"] ]]]],
  ["Chris", ["Garcia", ["SmartMan", [ [ "[email protected]"] ]]]]
];

const crazyData = data.map(d => fromDataArray(Class1, d));

This will give an array of objects that look like the following.

As a note, this is the JSON representation, but they are objects of the appropriate type.

{
    "firstName": "Adam",
    "subClass1": {
        "lastName": "Richardson",
        "subClass2": {
            "userName": "AdMan",
            "stuffz": [
                {
                    "email": "[email protected]"
                }
            ]
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

How about using Array.prototype.map to transform each item in the outer array:

function userFromDataRow([firstName, lastName, userName, email]) => {
    const user = new User();

    user.firstName = firstName;
    user.lastName = lastName;
    user.userName = userName;
    user.email = email;

    return user;
});

// Assuming the array of arrays is called "data"
data.map(userFromDataRow);

1 Comment

Alternatively, you could map it into an Object then Object.assign to the User prototype. See stackoverflow.com/questions/8736886
0

The following code may give you the result that you want (see this stackblitz for a demo). It maps the properties of the User object to the values in the corresponding array, in their order of appearance.

export class User {
  firstName = '';
  lastName = '';
  userName = '';
  email = '';
}

export class AppComponent {

  users = new Array<User>();

  values = [
    ["Adam", "Richardson", "AdMan", "[email protected]"],
    ["Ahmad", "Ali", "MarketMan", "[email protected]"],
    ["Feng", "Trunk", "SuperMan", "[email protected]"],
    ["Chris", "Garcia", "SmartMan", "[email protected]"]
  ];

  createUsers() {
    this.values.forEach((value) => {
      let user = new User();
      Object.keys(user).map((key, index) => {
        user[key] = value[index];
      });
      this.users.push(user);
    });
  }
}

Comments

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.