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