Transforme synchronous Map method to async traitment - javascript

I have a huge amont of data to transform into new format.
Actually I'm using map method but as it's syncronous and it's affecting performances.
dataFormatted = cmtAllRawdataDB[0].rows.map(elm => new Message(elm, configResult));
For information Message class have globally this format:
export class Data {
public value: string;
public date: Date;
constructor(dbData) {
this.value = '123';
}
}
export class Measure {
public name: string;
public unit: string;
public data: Data[];
constructor(config, dbData) {
this.name = config.name;
this.unit = config.value;
...
this.data = [new Data(dbData)];
}
}
export class Sensor {
public id: string;
public label: string;
public measures: Measure[] = [];
constructor(dbData, config) {
this.id = '123';
this.label = 'SensorType';
config.unitConfig.map(elm => this.measures.push(new Measure(elm, dbData)));
}
}
export class Message {
public id: string;
...
public sensors: Sensor[];
constructor(dbData: any, config: any) {
this.id = dbData.value._id;
....
this.sensors = [new Sensor(dbData, config)];
console.log(this.id, this.arrivalTimestamp);
}
}
Is there a way to run asynchronously this code ?

Just put this operation inside function and put it inside settimeout method, for just 10 millisecond
var example = () => {
setTimeout(() => {
return (dataFormatted = cmtAllRawdataDB[0].rows.map(
elm => new Message(elm, configResult)
));
}, 10);
};

Use async and await keywords like this way
async getDataFormatted(){ return(cmtAllRawdataDB[0].rows.map(elm => new Message(elm, configResult)));
}
let dataFormatted= await getDataFormatted();

Related

ERROR TypeError: Cannot read property 'instant' of undefined, ngx-translate angular typescript

Today i'm trying to implement translate service in a ts file like everywhere in my app, first of all have this class :
export class GaugeChartAdapter<T = any> extends ChartAdapter<T> {
constructor(protected translate: TranslateService) {
super(translate);
}
public process() {
...
options.series = options.series.map(elem => {
if (lang === 'fr') {
switch (elem.name) {
case 'Institution':
elem.name = this.translate.instant('COMPANY');
...
}
}
I have to implement also in the class ChartAdapter otherwise I got this error :
Type 'typeof GaugeChartAdapter' is not assignable to type 'new () => ChartAdapter<any>'
so I did this :
export abstract class ChartAdapter<T> {
constructor(protected translate: TranslateService) {
}
abstract process(...): any;
}
My problem is that in the navigator I have :
core.js:4098 ERROR TypeError: Cannot read property 'instant' of undefined
Thanks for help.
EDIT
There is the creation of my Chart factory:
export const graphsOptions: { [name: string]: any } = {
'gauge': GAUGE_OPTIONS,//comming from a class
//others graph..
};
export const graphsAdapters: { [name: string]: new () => ChartAdapter<any> } = {
'gauge': GaugeChartAdapter,
//others graph..
};
export class ChartCreator {
public static createChart(key: string, element: HTMLElement, chartParams, callback?: any) {
graphsOptions[key]['lang'] = chartParams.lang;
graphsOptions[key]['title'] = chartParams.title;
if (chartParams.colors && key === 'pie') {
graphsOptions[key]['plotOptions']['pie']['colors'] = chartParams.colors;
}
const adapter = new graphsAdapters[key];
return chart(element, adapter.process(graphsOptions[key], chartParams.data), callback);
}
public static createGauge(key: string, element: HTMLElement, data: any, total: number, lang: string, callback?: any) {
const adapter = new graphsAdapters[key];
return chart(element, adapter.process(graphsOptions[key], data, total, lang), callback);
}
public static createMap(key: string, data: any) {
data[0][0] = data[0][0].toLowerCase();
const adapter = new graphsAdapters[key];
return new MapChart(adapter.process(graphsOptions[key], data));
}
};
SO I found the answer, thanks to #MaieonBrix,
My ts file was not actually a angular So I pass a parameter through the instantiation in my component:
//TS COMPONENT
constructor(public translate: TranslateService) {
}
private renderGraph(): void {
this.chart = ChartCreator.createGauge('gauge', this.chartTarget.nativeElement, this.chartData,
this.total, this.lang, this.showInitValue, this.translate);
}
//Factory
public static createGauge(key: string, element: HTMLElement, data: any, total: number, lang: string, callback?: any, translateService?) {
const adapter = new graphsAdapters[key];
return chart(element, adapter.process(graphsOptions[key], data, total, lang, translateService), callback);
}
etc...
So translate was undefined because it wasn't in the angular scope, but by declaring it in the component who call the factory was the solution.

How to access a variable in a class in a json

I have an abstract class in fileA :
export abstract class BtAction {
public name: string;
public icon: string;
public cmd: string;
public cmdResponse: string;
public successMsg: string;
public errorMsg: string;
public device: any;
...
}
And a JSON in fileB :
export const BtActionList = {
open: class ActionOpen extends BtAction {
constructor(toast: ToastController,
private ble: BLE) {
super(toast);
this.name = "Open";
this.cmd = "0x3A21";
this.cmdResponse = "3a01";
this.successMsg = "successMsg";
this.icon = "log-in";
this.errorMsg = "error";
}
...
},
stock: class ActionStock extends BtAction {
constructor(toast: ToastController,
private ble: BLE) {
super(toast);
this.name = "Stock";
this.cmd = "0x3A21";
this.cmdResponse = "3a01";
this.successMsg = "successMsg";
this.icon = "log-in";
this.errorMsg = "error";
}
...
}
}
My file C import BtActionList and i want to loop on it to display a tabsbar :
import { BtActionList } from './utils/bt-action-list';
But when i put a console.log i see nowhere my variable :
Inspector of my Object
How can i access to my variables ?
Thanks !
I think what you might want is this:
export const BtActionList: {open: BtAction, stock: BtAction} = {
open: {
name: "Open",
cmd: "0x3A21",
cmdResponse: "3a01",
successMsg: "successMsg",
icon: "log-in",
errorMsg: "error"
},
stock: {
name: "Stock",
cmd: "0x3A21",
cmdResponse: "3a01",
successMsg: "successMsg",
icon: "log-in",
errorMsg: "error"
}
};
The way you had it right now, the classes are not instantiated and as a result aren't create to be able to access any variable on it. If you really want the class you can instantiate it like so:
class ActionOpen extends BtAction {
constructor(toast: ToastController,
private ble: BLE) {
super(toast);
this.name = "Open";
this.cmd = "0x3A21";
this.cmdResponse = "3a01";
this.successMsg = "successMsg";
this.icon = "log-in";
this.errorMsg = "error";
}
}
class ActionStock extends BtAction {
constructor(toast: ToastController,
private ble: BLE) {
super(toast);
this.name = "Stock";
this.cmd = "0x3A21";
this.cmdResponse = "3a01";
this.successMsg = "successMsg";
this.icon = "log-in";
this.errorMsg = "error";
}
}
export const BtActionList = {
open: new ActionOpen(/* pass in your initializers */),
stock: new ActionStock(/* pass in your initializers */)
}

how to call a function class javascript

I wanted to create a class with private parameters and functions to access the data I want. You can see this :
export class Product {
private name: string;
private type: string;
private longDetail: string;
private shortDetail: string;
private stock: number;
private price: number;
private linkImage: string;
private id: number;
constructor(
name: string,
type: string,
longDetail: string,
shortDetail: string,
stock: number,
price: number,
linkImage: string,
id: number
) {
this.name = name;
this.type = type;
this.longDetail = longDetail;
this.shortDetail = shortDetail;
this.stock = stock;
this.price = price;
this.linkImage = linkImage;
this.id = id;
}
getName(): string {
return this.name;
}
getType(): string {
return this.type;
}
getLongDetail(): string {
return this.longDetail;
}
getShortDetail(): string {
return this.shortDetail;
}
getStock(): number {
return this.stock;
}
getPrice(): number {
return this.price;
}
getLinkImage(): string {
return this.linkImage;
}
getId(): number {
return this.id;
}
}
And when I want to call a function in a component I am told :
ProductListComponent.html:15 ERROR TypeError: newProduct.getName is not a function
Do you have a solution ? Thank you very much in advance !
EDIT :
This is the code called after the click in front end
addProductBasket(newProduct: Product) {
const newClientBasket = this.createNewClientBasketWithAdd(
this.clientBasket.getValue(),
newProduct
)
this.clientBasket.next(newClientBasket)
console.log(newClientBasket)
}
private createNewClientBasketWithAdd(
oldClientBasket: BasketProduct[],
newProduct: Product
): BasketProduct[] {
const found = oldClientBasket.find((product) => {
if (product.getId() === newProduct.getId()) {
product.addOneProduct()
}
})
if (found === undefined) {
console.log(newProduct.getName())
oldClientBasket.push(
new BasketProduct(
newProduct.getName(),
newProduct.getType(),
newProduct.getLongDetail(),
newProduct.getShortDetail(),
newProduct.getStock(),
newProduct.getPrice(),
newProduct.getLinkImage(),
newProduct.getId()
)
)
}
return oldClientBasket
}
It's my apiservice to get data
export class ApiService {
private dataApi: BehaviorSubject<Product[]> = new BehaviorSubject<Product[]>([]);
constructor(private http: HttpClient) {
this.getDataFromApi();
}
private getDataFromApi(){
this.http
.get<Product[]>("../../assets/data.json")
.toPromise()
.then((data) => this.dataApi.next(data));
}
public getData():Observable<Product[]>{
return this.dataApi.asObservable();
}
}
You should have an instance of Product class before accessing its methods.
var newProduct = new Product();
newProduct.getName();
After David's help in commenting, I understood that I had to instantiate the data I receive in http client.
I then modified the constructor and my client http get
constructor(obj: any) {
Object.assign(this, obj);
}
and
private getDataFromApi(){
this.http
.get<Product[]>("../../assets/data.json").pipe()
.toPromise()
.then((data) => {
const productList = data.map(product => new Product(product));
this.dataApi.next(productList)});
}

Deserialize a JSON object into its original class

I am trying to serialize/deserialize an object. I am thinking that the best way would be to save the path to the file that called as part of the json, but I am unsure of how to get said path.
Can getting this path to the file (A.ts/B.ts) be done when called within the parent (Base.ts)?
Is there maybe a better approach to doing this? I am trying to take a class created in the main node process, and and pass it to a worker process, the only why to do this that I can see is to serialize/deserialize the class somehow.
// src/Base.ts
export abstract class Base {
public serialize() {
return JSON.stringify({path: '', obj: this})
}
public static deserialize(json: string) {
let { path, obj } = JSON.parse(json) as { path: string, obj: { [key: string]: any } }
let newable = require(path)
let o = new newable
return Object.assign(o, obj)
}
}
// src/filter/A.ts
export class A extends Base {
public cat: string = 'meow'
public sayHi() { return this.cat }
}
// src/filter/B.ts
export class B extends Base {
public dog: string = 'woof'
public sayHi() { return this.dog }
}
// test.ts
let serializedA = new A().serialize()
let serializedB = new B().serialize()
// Create child...
let worker = cp.fork(path.join(__dirname, './worker'), [], { silent: true })
worker.send({ serializedA, serializedB })
// worker.ts
process.on('message', msg => {
let classA = Base.deserialize(msg.serializedA)
let classB = Base.deserialize(msg.serializedB)
})
The simplest way that comes to mind would be to have a set of class names associated with callbacks that would require the appropriate classes.
// src/JsonIO.ts
export class JsonIO {
private _classes: { name: string, callback: () => { new(): any } }[] = []
public serialize(obj: any): string {
return JSON.stringify({ class: obj.constructor.name, value: obj })
}
public deserialize(json: string) {
const obj = JSON.parse(json) as { class: string, value: any }
const clazz = this._classes.find(c => c.name == obj.class)
if(!clazz) return obj.value
return Object.assign(new (clazz.callback()), obj.value)
}
public registerClass(name: string, callback: () => { new(): any }) {
this._classes.push({ name, callback })
}
}
// src/Base.ts
export abstract class Base { /* ... */ }
// src/filter/A.ts
export class A {
public cat: string = 'meow'
}
// src/filter/B.ts
export class B {
public dog: string = 'woof'
}
// test.ts
const io = new JsonIO()
io.registerClass('A', () => A /* require('filter/A.ts') */)
io.registerClass('B', () => B /* require('filter/B.ts') */)
const serializedA = io.serialize(new A)
const serializedB = io.serialize(new B)
const a = io.deserialize(serializedA)
const b = io.deserialize(serializedB)

Storing interfaces in object

Imagine I have the following interfaces
interface IMarket {
ID: number,
Name: string,
MarketDescription: string
}
interface IDepartment {
ID: number,
Name: string,
DepartmentDescription: string
}
Is there a way to store the interfaces in an object like this?
var typeMap = { Markets: IMarket, Departments: IDepartment }
I'd like to do something like this. I'd like to dynamically set the generic type for "getQueryResults" based on a string value I pass into the constructor.
export class Service {
protected baseURL = "";
protected typeName = "";
private typeMap = { Markets: IMarket, Departments: IDepartment }
constructor(typeName) {
this.baseURL = 'http://localhost/API/odata/' + typeName;
this.currentType = typeMap[typeName];
}
getQueryResults(): Promise<this.currentType> {
return new Promise<this.currentType>((resolve, reject) => {
$.getJSON(this.baseURL, function (returnValue) {
resolve(returnValue.value);
});
})
}
}
var marketService = new Service("Markets");
var topMarket = marketService.getQueryResults();
//topMarket is an instance(?) of IMarket
var departmentService = new Service("Departments");
var topDepartment = departmentServicegetQueryResults();
//topDepartment is an instance(?) of IDepartment
That can be simply solved using generics, it's exactly what it's for:
export class Service<T> {
protected baseURL = "";
constructor() {
this.baseURL = 'http://localhost/API/odata/' + typeName;
}
getQueryResults(): Promise<T> {
return new Promise<T>((resolve, reject) => {
$.getJSON(this.baseURL, function (returnValue) {
resolve(returnValue.value);
});
})
}
}
var marketService = new Service<IMarket>();
var topMarket: Promise<IMarket> = marketService.getQueryResults();
var departmentService = new Service<IDepartment>();
var topDepartment: Promise<IDepartment> = departmentService.getQueryResults();
Edit
You can use 2 more classes to "get rid" of the need to have Service<TYPE> more than once (per TYPE):
export abstract class Service<T> {
protected baseURL = "";
constructor() {
this.baseURL = 'http://localhost/API/odata/' + this.getTypeName();
}
getQueryResults(): Promise<T> {
return new Promise<T>((resolve, reject) => {
$.getJSON(this.baseURL, function (returnValue) {
resolve(returnValue.value);
});
})
}
protected abstract getTypeName(): string;
}
export class MarketsService extends Service<IMarket> {
protected getTypeName(): string {
return "Markets";
}
}
export class DepartmentsService extends Service<IDepartment> {
protected getTypeName(): string {
return "Departments";
}
}
var marketService = new MarketsService();
var topMarket: Promise<IMarket> = marketService.getQueryResults();
var departmentService = new DepartmentsService();
var topDepartment: Promise<IDepartment> = departmentService.getQueryResults();
But unlike the need to specify the type every time you use Service, these extra classes will be part of the compiled js, so it's a question of what's more important to you.
Taking a note from the TypeScript docs:
http://www.typescriptlang.org/docs/handbook/namespaces.html#namespaced-validators
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
It appears you would want:
namespace YourNamespace {
export interface IMarket {
ID: number,
Name: string,
MarketDescription: string
}
export interface IDepartment {
ID: number,
Name: string,
DepartmentDescription: string
}
}

Categories