How to map JSON data to a class - javascript

I created a ES6 class by Babel and I want to map JSON data which is gotten from a server to the ES6 class.
Is there anything common way to do that?
User.js
export default class User {
constructor() {
this.firstName;
this.lastName;
this.sex;
}
}
app.js
import User from "./classes/User";
var data = JSON.parse(req.responseText);
console.log(data.firstname); //Bob
//now...just set data one by one?

I would merge the JSON object into this using Object.assign, as follows:
class User {
firstName;
lastName;
sex;
constructor(data) {
Object.assign(this, data);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
}
}
var data = JSON.parse(req.responseText);
new User(data);

you can use this npm package https://www.npmjs.com/package/class-converter to map all JSON to a class.
it looks like following one:
import { property, toClass } from 'class-convert';
class UserModel {
#property('i')
id: number;
#property()
name: string;
}
const userRaw = {
i: 1234,
name: 'name',
};
// use toClass to convert plain object to class
const userModel = toClass(userRaw, UserModel);
// you will get a class, just like below one
{
id: 1234,
name: 'name',
}

Related

How to get the value of the keys in an array of objects?

I have an array of objects that is structured like this:
import icon1 from '!!raw-loader!../../../icon1.svg';
import icon2 from '!!raw-loader!../../../icon2.svg';
import icon3 from '!!raw-loader!../../../icon3.svg';
import icon4 from '!!raw-loader!../../../icon4.svg';
import icon5 from '!!raw-loader!../../../icon5.svg';
export const CustomIcons = [
{
home: 'icon1',
homeIcon: (icon)
},
{
series: 'icon2',
seriesIcon: (icon2)
},
{
explorer: 'icon3',
explorerIcon: (icon3)
},
...
];
In the constructor of my module I want to use the values like this:
export class IconRegistryModule {
constructor(iconRegistry: MatIconRegistry, sanitizer: DomSanitizer) {
CustomIcons.forEach(icon => {
iconRegistry.addSvgIconLiteral(Object.keys(icon)[0], sanitizer.bypassSecurityTrustHtml(Object.keys(icon)[1]));
});
}
}
So the addSvgIconLiteral method should look like this for the first run of the forEarch:
iconRegistry.addSvgIconLiteral('the value of the key home', sanitizer.bypassSecurityTrustHtml('the value of the key homeIcon');
Use this for get object keys in array.
CustomIcons.map((data) => {
console.log(Object.keys(data));
});
Object.keys(icon)[0] just gives you the key. You can use the key as index on the icon object.
You can do icon[Object.keys(icon)[0]] to get the value.
(Of course you will need to make sure that the first property is always the one holding the url. In that sense it would probably be better to base the structure on an interface with consistent naming like suggested in the comments.)
Edit:
Using an interface should look somewhat like this:
export interface CustomIcon {
name: string;
icon: string;
}
export const CustomIcons: CustomIcon[] = [
{
name: 'icon1',
icon: (icon1)
},
{
name: 'icon2',
icon: (icon2)
},
...
]
Then in the constructor (Object.keys not required anymore):
constructor(iconRegistry: MatIconRegistry, sanitizer: DomSanitizer) {
CustomIcons.forEach(icon => {
iconRegistry.addSvgIconLiteral(icon.name, sanitizer.bypassSecurityTrustHtml(icon.icon));
});
}
Use Object.keys to get the values from each object
var keys = Object.keys(CustomIcons[i])
And then iterate through each element in the array with a for loop.
You can append each of these elements to a seperate 'key array' at the end of each
loop.

How use Active Record pattern in TypeORM using JavaScript

TypeORM provides examples for implementation in JavaScript (without typescript) here.
The problem is, that only the Data Mapper pattern is described. In my current project, I want to use the Active Record pattern.
I have tried adding the extend or target properties pointing to BaseEntity (as string or object), but this is not working.
What do I need to do?
Define model and schema
(models/Nugget.js)
import typeorm from 'typeorm'
const { BaseEntity, EntitySchema } = typeorm
// "model"
export class Nugget extends BaseEntity {
id;
name;
}
// "schema"
export const NuggetSchema = new EntitySchema({
name: "Nugget",
target: Nugget, // the class above
columns: {
id: {
primary: true,
type: "int",
generated: true
},
name: {
type: "varchar"
},
}
})
Pass the schemas in entities when connecting
(dbConnect.js)
import typeorm from 'typeorm'
const { createConnection } = typeorm
import { NuggetSchema } from './models/Nugget'
const connection = await createConnection({
type: db_type, // e.g. mysql
host: db_host,
port: db_port,
database: db_database,
username: db_user,
password: db_pass,
synchronize: false, // set to true to modify database to match schema
logging: false,
entities: [
NuggetSchema
]
})
Import the model and use it to add/delete/query for that item (Active Record pattern)
(index.js)
import './dbConnect.js'
import { Nugget } from './models/Nugget'
const nugget = new Nugget()
nugget.name = "Hi I Am A Nugget"
await nugget.save()
const nuggets = await Nugget.find({})
console.log('nuggets', nuggets)
Try to change model/Category.js to:
const BaseEntity = require("typeorm").BaseEntity;
class Category extends BaseEntity {
constructor(id, name) {
super();
this.id = id;
this.name = name;
}
}
module.exports = {
Category: Category
};

JSON to Javascript Class

I have a http request that gets this Json object from a nosql database:
let jsonBody = {
birthday : 1997,
firstname: 'foo',
lastname:'bar'
}
Then I want to load this information into the Student model:
class Student{
constructor(){
}
getFullname(){
return this.lastname+' '+this.firstname
}
getApproxAge(){
return 2018- this.birthday
}
}
Normally, I would add this method to this class:
fromJson(json){
this.studentId = json.studentId;
this.birthday = json.birthday;
this.firstname = json.firstname;
this.lastname = json.lastname;
}
I would use it as follow:
let student = new Student()
student.fromJson(jsonBody)
console.log(student.getFullname())
console.log(student.getApproxAge())
This works fine but my problem is I have: 100 proprieties in reality. Will I have to write all proprities one by one in the fromJson method?
And also, if a propriety name has change, let's say: lastname became LastName, I will have to fix it?
Is there a simpler way to just assign these values to the object student dynamically but keep all of its methods??
Something like this:
fromJson(json){
this = Object.assign(this, json) //THIS IS NOT WORKING
}
Just assign to an instance:
static from(json){
return Object.assign(new Student(), json);
}
So you can do:
const student = Student.from({ name: "whatever" });
Or make it an instance method and leave away the assignemnt:
applyData(json) {
Object.assign(this, json);
}
So you can:
const student = new Student;
student.applyData({ name: "whatever" });
It could also be part of the constructor:
constructor(options = {}) {
Object.assign(this, options);
}
Then you could do:
const student = new Student({ name: "whatever" });
And also, if a property name has changed, let's say: lastname became LastName, I will have to fix it?
Yes you will have to fix that.
There is no way in javascript to deserialize json into classes. So I wrote a library ts-serializable that solves this problem.
import { jsonProperty, Serializable } from "ts-serializable";
export class User extends Serializable {
#jsonProperty(String)
public firstName: string = ''; // default value necessarily
#jsonProperty(String, void 0)
public lastName?: string = void 0; // default value necessarily
#jsonProperty(Date)
public birthdate: Date = new Date(); // default value necessarily
public getFullName(): string {
return [
this.firstName,
this.lastName
].join(' ');
}
public getAge(): number {
return new Date().getFullYear() - this.birthdate.getFullYear();
}
}
const user: User = new User().fromJSON(json);
user.getFullName(); // work fine and return string
user.getAge(); // work fine and return number
// or
const user: User = User.fromJSON(json);
user.getFullName(); // work fine and return string
user.getAge(); // work fine and return number
The library also checks types during deserialization.

Reading from JSON file, variable name is different, does not match

I am trying to read from a JSON file, but it is formatted this way:
[
{
"INV#" : "123"
},
{
"INV#" : "456"
}
]
That variable name does not meet JavaScript or TypeScript naming. So I have the following object:
export interface Invoice {
invoiceNumber: number;
}
class myclass {
private inv: Invoice[];
}
How can I read from that json file into this object. Making changes on the database variable is not an option. Changing the name of my interface variable is not possible in JavaScript. Somehow they have to match, but there must be a way to make the object property into mine.
// let's assume that you've read the json into some variable
let response = [
{
"INV#" : "123"
},
{
"INV#" : "456"
}
];
export interface Invoice {
invoiceNumber: number;
}
class myclass {
private inv: Invoice[];
constructor(_response: any[]) {
// do not forget to check _response for null/undefined, if it is an array or not, etc.
this.inv = _response.map(obj => <Invoice>{
invoiceNumber: parseInt(obj['INV#'])
});
}
}
// usage:
let some_var = new myclass(response);
// now some_var contains array of invoices internally.

Dynamically get class members names and values using Typescript or javascript

I'm pretty new with these languages and I'm sure it's not so complicated but could not find how to walk through class instance variables dynamically.
I'm trying to display instance's variables in a table using Angular. I'd like to write a single function that will work with any class.
Let's say I have a workbook class:
export class workbookEntity {
public name: string;
public creationDate: string;
constructor() {
this.name = 'my work book name';
this.creationDate = '2018/01/26';
}
}
And let's say I want to get the names and values of the variables of an instance of this class in another class' function:
export class showClassComponent {
// some code here
whenSubmitedInHtmlForm(className: string): void {
// do something to walk through instance
// with className parameter = 'workbookEntity'
}
// more code there
}
How would you walk through the instance to get each variable's name and value to get something like this?
[
{
name: 'name',
value: 'my work book name'
},
{
name: 'creationDate',
value: '2018/01/26'
}
]
There's no concept of reflection, so much in Typescript, so you can't neccessarily do a type lookup. But you might be able to do something along the lines of...
export class showClassComponent {
var classes = [ { name: 'workBookEntity', value: new WorkBookEntity() }]
whenSubmitedInHtmlForm(className: string): void {
let c = classes.filter(class => class.name == className)[0];
if(c) {
let ret = [];
for (var key in c) {
if (c.hasOwnProperty(key)) {
ret.push({ name: key, value: c[key] });
}
}
return ret;
}
}
// more code there
}
If you want to be able to retain accurate type information, you can create a pick utility function and then just import it into your class module wherever you need to use it.
let workBook = new WorkbookEntity();
export function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
let newObj = {} as Pick<T, K>;
for (const key of keys) {
newObj[key] = obj[key];
}
return newObj;
}
console.log(pick(workBook, ['name', 'creationDate']));
// log: { name: 'my work book name', creationDate: '2018/01/26' }
Then you can import the first function into another utility function if you to be able to handle multiple objects.
export function pickObjects<T extends object, K extends keyof T>
(objects: T[], keys: K[]): Pick<T, K>[] {
return objects.reduce((result, obj) => [...result, pick(obj, keys)], []);
}
let workbooks = pickObjects([workBook, workBook2], ['name']);
workbooks[0].name // this exists
workbooks[0].age // Typescript error.
The editor will show that age doesn't exist since we didn't pick it

Categories

Resources