how to call a function class javascript - 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)});
}

Related

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 */)
}

Items in localStorage are removed after page reload in NgShoppingCart using Angular

I have an Angular (8.0.0) project.
I've added this library to implement a shopping cart in Angular:
NgShoppingCart
After I've added it in app.module like explained here I added these lines of code in one component:
constructor(private cartService: CartService<TourCartItem>) {
}
ngOnInit() {
}
add() {
const item = new TourCartItem({id: 1, name: 'My item'});
item.setId(9);
item.setName('Test item');
item.setPrice(10);
item.setQuantity(10);
this.cartService.addItem(item);
}
}
Everything works when I add an item, I see this in localStorage:
but after I reload the page the items are reset:
This is my app.module:
#NgModule({
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
SharedModule.forRoot(),
ShoppingCartModule.forRoot({
itemType: TourCartItem,
serviceType: 'localStorage',
serviceOptions: {storageKey: 'ToursCart', clearOnError: true},
}),
CoreModule,
ServiceWorkerModule.register('/ngsw-worker.js', {enabled: environment.production}),
],
providers: [],
bootstrap: [CoreComponent]
})
export class AppModule {
constructor() {
if (!environment.production) {
console.log('app');
}
}
}
This is my custom class TourCartItem:
export class TourCartItem extends CartItem {
uuid: any;
description: string;
name: string;
price: number;
image: string;
quantity: number;
data: any;
constructor(itemData?: any) {
super();
if (itemData) {
this.uuid = itemData.uuid;
this.description = itemData.description;
this.name = itemData.name;
this.price = itemData.price;
this.image = itemData.image;
this.quantity = itemData.quantity;
this.data = itemData.data;
}
}
static fromJSON(itemData: any) {
return new TourCartItem(itemData.uuid);
}
getId(): any {
return this.uuid;
}
setId(id: any): void {
this.uuid = id;
}
getDescription(): any {
return this.description;
}
setDescription(description: any): any {
this.description = description;
}
getName(): string {
return this.name;
}
setName(name: string): void {
this.name = name;
}
getPrice(): number {
return this.price;
}
setPrice(price: number): void {
this.price = price;
}
getQuantity(): number {
return this.quantity;
}
setQuantity(quantity: number): void {
this.quantity = quantity;
}
getImage(): string {
return this.image;
}
setImage(image: string): void {
this.image = image;
}
getData(): any {
return this.data;
}
setData(data: any): void {
this.data = data;
}
}
Can someone help, maybe trying to install this library?
Thanks in advance.
Fixed, the issue was that my custom ItemCart dont have correct fromJSON implementation.

Transforme synchronous Map method to async traitment

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();

Map JSON to existing deep object structure

Say I have the following Typescript model:
class Person{
public Address: Address;
public FirstName: string;
public LastName: string;
constructor(){
this.Address = new Address();
}
}
And I get an exact representation of this object from a server via JSON.
How would I go about generically setting the properties of both the Person and the Address but leave the existing objects intact.
So similar to this, but generically:
public SetData(json:any){
this.Address.City = json.Address.City;
this.Address.Province = json.Address.Province;
this.FirstName = json.FirstName;
}
The gotcha being that the original objects must remain and have there setters called as they are Mobx observables. This rules out Object.assign and any 'extend' methods I have found.
Thanks.
In somewhat simplified case you can do it manually without too much effort:
class Address
{
public City: string;
public Province: string;
}
class Person{
public Address: Address;
public FirstName: string;
public LastName: string;
constructor() {
this.Address = new Address();
}
private SetDataInternal(target: any, json: any)
{
if (typeof json === "undefined" || json === null)
{
return;
}
for (let propName of Object.keys(json))
{
const val = target[propName];
if (typeof val === "object")
{
this.SetDataInternal(val, json[propName]);
}
else
{
target[propName] = json[propName];
}
}
}
public SetData(json: any)
{
this.SetDataInternal(this, json);
}
}
const json = {
Address: {
City: "AAA",
Province: "BBB"
},
FirstName: "CCC"
}
const p = new Person();
p.SetData(json);
console.log(p);
It surely miss some checks and corner cases validations, but apart from that it does what you ask for.
My final implementation based of Amids:
import * as _ from "underscore";
export class ObjectMapper
{
public static MapObject(source: any, destination: any) {
_.mapObject(source, (val, key) => {
if(_.isObject(val))
{
this.MapObject(val, destination[key]);
}
else if(_.isArray(val))
{
const array = destination[key];
for(var i in val)
{
const newObject = {};
_.extend(newObject, val[i]);
array.push(newObject);
}
}
else
{
destination[key] = val;
}
});
}
}

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