I have a Observable:
getItemInfo(): Observable<Company_item[]> {
return this.db.list<Company_item>(this.API_URL_ITEM).snapshotChanges().pipe(map(response => response.map((item) => this.assignKey(item))));
}
... and current work as:
displayedColumns: string[] = ['billing_date', 'billing_month', 'billing_us', 'billing_vat', 'billing_worker', 'billing_zus', 'company_id', 'key' ];
companyItems$: Observable<Company_item[]> = this.companiesService.getItemInfo();
dataSource = this.companyItems$;
and it's display value on MatTable fine.
I want to switch value of:
getCompaniesInfo(): Observable<Company[]> {
return this.db.list<Company>(this.API_URL_COMPANIES).snapshotChanges().pipe(map(response => response.map((item) => this.assignKey(item))));
}
like:
on company_id value switch to company_name.
My model:
export interface Company {
company_country: string;
company_email: string;
company_name: string;
company_post_code: string;
company_street: string;
company_tax_us_no: string;
company_tax_zus_no: string;
key: string;
}
export interface Company_item {
billing_date: string;
billing_month: string;
billing_us: number;
billing_vat: number;
billing_worker: number;
billing_zus: number;
company_id: number;
key: string;
}
I wrote to this :
getIdInfo(id: string): Observable<Company> {
return this.getCompaniesInfo().pipe(map(res => res.find(re => re['key'] == id) ))
}
and now i have:
getIdInfo$(id: string) {
return this.companiesService.getIdInfo(id).subscribe(res => {
res.company_name}
)
}
and for test to display company_name :
<ng-container matColumnDef="company_id">
<th mat-header-cell *matHeaderCellDef>ID FIRMY</th>
<td mat-cell *matCellDef="let item">{{ item.company_id + getIdInfo$("1") }}
</td>
</ng-container>
But I have to display: 1[object Object]
I should still get the company_id from MatTable to getIdInfo$ function but I don't know how to go about it. How should I do it to make it work well?
I was thinking about forkJoin and displaying the already finished stream in MatTable dataSource but I don't know how to go about it.
As you can see, I'm just starting my programming adventure.
I am very much asking for your support.
I try this:
res: string;
id(id: string): string {
let companyName: string;
this.companiesService.getIdInfo(id).subscribe(res => {
this.res = res.company_name;
companyName = this.res;
console.log(companyName) }, // DISPLAY OK
error => console.log(error)
)
console.log(companyName); //DISPLAY UNDEFINED
return companyName;
}
ngOnInit() {
console.log(this.id("1")) //DISPLAY UNDEFINED
}
But still UNDEFINED
Related
Hello i am supossed to change the model to the one below but now my code doesnt work and i cant figure out how to format the data with the model provided . Any help appreciated.
here is the api: https://archive-api.open-meteo.com/v1/era5?latitude=51.51&longitude=-0.13&start_date=2005-08-25&end_date=2005-08-25&hourly=temperature_2m,relativehumidity_2m,dewpoint_2m,apparent_temperature,surface_pressure,precipitation,rain,cloudcover,windspeed_10m,winddirection_10m,soil_temperature_0_to_7cm&timezone=Europe%2FLondon
in the component ngOnInit subscription i am making variable for each array of data from the api (modifying some arrays there like time,precipitation and wind direction) and then pushing new WeatherDataItem object with those variables to empty array weatherData: WeatherDataItem[] = [] from which i am filling table columns in html
weatherData: WeatherDataItem[] = [];
…
…
this.weatherService.getWeather()
...
...
.subscribe({
next: (historicalWeatherData) => {
const temperatures = historicalWeatherData.hourly.temperature_2m;
const times = historicalWeatherData.hourly.time.map((time) =>
this.datePipe.transform(time, 'shortTime')
);
const humidities = historicalWeatherData.hourly.relativehumidity_2m;
const windSpeeds = historicalWeatherData.hourly.windspeed_10m;
const airPressures = historicalWeatherData.hourly.surface_pressure;
const windDirections =
historicalWeatherData.hourly.winddirection_10m.map((item) =>
this.checkWindDirection(item)
);
const precipitations = historicalWeatherData.hourly.precipitation.map(
(item) => {
if (item > 0) {
return new Rain(item, true);
}
return new Rain(item, false);
}
);
const cloudcover = historicalWeatherData.hourly.cloudcover;
const soilTemperatures =
historicalWeatherData.hourly.soil_temperature_0_to_7cm;
temperatures.forEach((value, i) => {
this.weatherData.push(
new WeatherDataItem(
value,
times[i],
humidities[i],
windSpeeds[i],
airPressures[i],
windDirections[i],
precipitations[i],
cloudcover[i],
soilTemperatures[i]
)
);
});
...
...
...
here is the model i am using right now for weatherData
export class WeatherDataItem {
constructor(
public temperature: string,
public time: string,
public humidity: string,
public wind: string,
public pressure: string,
public direction: string,
public precipitation: Rain,
public cloudcover: string,
public soilTemperature: string
) {}
}
and i am supposed to use this model because the above one apparently has too many arguments in constructor but dont know how to implement that because now in the component i am getting error: expecting 1 argument but got 9
export class WeatherDataItem {
temperature: number;
time: string;
humidity: number;
wind: number;
pressure: number;
direction: string;
precipitation: Rain;
cloudcover: number;
soilTemperature: number;
constructor(inputData: Object) // type WeatherDataItem ? or what should be the type here
{
(this.temperature = inputData.temperature),
(this.time = inputData.time),
(this.humidity = inputData.humidity),
(this.wind = inputData.wind),
(this.pressure = inputData.pressure),
(this.direction = inputData.direction),
(this.precipitation = inputData.precipitation),
(this.cloudcover = inputData.cloudcover),
(this.soilTemperature = inputData.soilTemperature);
}
}
i tried this in component but no luck
const inputData = [
temperatures,
times,
humidities,
windSpeeds,
airPressures,
windDirections,
precipitations,
cloudcover,
soilTemperatures,
];
this.weatherData.push(new WeatherDataItem(inputData));
html
<p-table
[value]="weatherData"
...
...
...
<ng-template pTemplate="body" let-weather>
<tr>
<td field="time">{{weather.time}}</td>
<td field="temperature">{{weather.temperature}}°C</td>
<td field="humidity">{{weather.humidity}}%</td>
<td field="wind">{{weather.wind}} km/h</td>
<td field="pressure">{{weather.pressure}} hPa</td>
<td field="direction">{{weather.direction}}</td>
<td field="precipitation.didRain">{{weather.precipitation.amount}} mm</td>
<td field="cloudcover">{{weather.cloudcover}}%</td>
<td field="soilTemperature">{{weather.soilTemperature}}°C</td>
</tr>
</ng-template>
it works when I've added it, maybe you've got a typo somewhere. I had to add the mapping to string when creating the new WeatherDataItem in your OnInit function
https://stackblitz.com/edit/angular-ivy-qchu4z
I'm trying to see if there's a more elegant way other than using map to accomplish the following:
I have a class with an array of another object. So my Meeting object has many users:
import { User } from './user';
export class Meeting {
_id?: string;
name: string;
roomSid?: string;
users: User[];
contentList: any;
startDate: Date;
endDate: Date;
createDate: Date;
}
export class User {
_id: string;
firstName: string;
lastName: string;
dealerName: string;
location: string;
role: 'attendee' | 'host' | 'participant';
videoServiceId: string;
profilePic?: string;
__v?: string;
get isHost(): boolean {
return this.role === 'host';
}
get isAttendee(): boolean {
return this.role === 'attendee';
}
get isParticipant(): boolean {
return this.role === 'participant';
}
get isClient(): boolean {
return this.isAttendee || this.isParticipant;
}
}
When I do:
this.httpClient
.get<Meeting>(`${this.apiUrl}${meetingId}`)
.pipe(
catchError(this.handleError));
without using map to convert the received result from the get, the User object array is getting set incorrectly. My getters are undefined unless I do a Object.assign(new User, user). HttpGet returns the Meeting as a Meeting class just fine, just not the objects inside.
Is there something I'm missing or is this working as intended and I have no choice but to use map(). Although I feel that if I have another Object inside my User class, then things could get a bit messier.
For reference here is a response from the server:
{
"users": [
{
"_id": "971c4160-c60c-11ea-8505-dff43e61059c",
"firstName": "alex",
"lastName": "oroszi",
"dealerName": "here",
"location": "here",
"role": "attendee",
"videoServiceId": "PA634a9331a9cad648bb6e6dbcea8e49a0"
}
],
"contentList": [],
"_id": "5f0a005b627fb647f519118b",
"name": "Room1",
"startDate": "2020-07-11T16:00:00.000Z",
"endDate": "2020-07-11T17:00:00.000Z",
"createDate": "2020-07-11T18:09:31.016Z",
"__v": 0
}
When specifying .get<Meeting>(`${this.apiUrl}${meetingId}`) you're letting TypeScript know that the get method will return a Meeting object which is not the case. If you check the result of your method with data instanceof Meeting it will return false. You will need to create a meeting object and populate it with the data received from the request.
The easiest way to do this without any libraries will probably be as follows.
export class Meeting {
_id?: string;
name: string;
roomSid?: string;
users: User[];
contentList: any;
constructor(data) {
this._id = data._id;
this.name = data.name;
this.roomSid = data.roomSid;
this.users = data.users.map(user => new User(user));
this.contentList = data.contentList;
// ...
}
}
export class User {
_id: string;
firstName: string;
lastName: string;
dealerName: string;
location: string;
role: 'attendee' | 'host' | 'participant';
videoServiceId: string;
profilePic?: string;
__v?: string;
constructor(data) {
this._id = data._id:
this.firstName = data.firstName:
// ...
}
get isHost(): boolean {
return this.role === 'host';
}
get isAttendee(): boolean {
return this.role === 'attendee';
}
get isParticipant(): boolean {
return this.role === 'participant';
}
get isClient(): boolean {
return this.isAttendee || this.isParticipant;
}
}
function getMeeting(meetingId): Observable<Meeting> {
this.httpClient.get<Meeting>(`${this.apiUrl}${meetingId}`)
.pipe(
catchError(this.handleError),
map(meeting => new Meeting(meeting)),
);
}
The downside of this approach is the DRYness as the property name is repeated three times. An alternative is solutions such as TypedJson which allow you to serialize and deserialze objects with help of decorators. Quick example of a model in TypedJSON:
#jsonObject
class Meeting {
#jsonMember
_id: string;
#jsonArrayMember(User)
users: Array<User>;
}
I'm new with ORM system and I'm trying to insert a data "Mark" binded with an object "pseudo".
This my entities,
Pseudo:
#Entity()
export class PseudoEntity{
#PrimaryGeneratedColumn()
id: number;
#Column({unique: true})
pseudo: string;
#Column({ default: 1 })
application_version: number;
#Column({ default: -1 })
score_on_last_calculation: number;
#Column({default: 1})
nb_request: number;
#Column({default: -1})
nb_mark_on_last_calculation: number;
#OneToMany(type => Mark, marks => marks)
marks: Mark[];
}
And Mark:
#Entity()
export class MarkEntity {
#PrimaryGeneratedColumn()
int: number;
#Column({ type: 'datetime'})
submission_date: Date;
#Column()
mark: number;
#ManyToOne(
type => Pseudo,
pseudo => pseudo,
)
pseudo: Pseudo;
}
This is my service to insert the data:
#Injectable()
export class MarkService {
constructor(private pseudoService: PseudoService) {}
async postMark(pseudo: string, mark: number) {
await this.pseudoService.findPseudo(pseudo).then(
p =>
getConnection()
.createQueryBuilder()
.insert()
.into(Mark)
.values([
{
mark: mark,
pseudo: p,
},
]),
);
}
}
I succeed to insert a Pseudo but not a mark :/
Could you help me please ?
Thanks in advance
First you should make a few slight changes to your entities:
#OneToMany(type => Mark, marks => marks.pseudo)
marks: Mark[];
#ManyToOne(
type => Pseudo,
pseudo => pseudo.marks,
)
pseudo: Pseudo;
Having made the changes above, use the injected pseudoRepository for querying and updating the desired Pseudo: (more about Registering and Injecting entities)
#Injectable()
export class MarkService {
constructor(#InjectRepository(Pseudo) private readonly pseudoRepository: Repository<Pseudo>) { }
async postMark(mark: number, pseudo: Pseudo): Promise<void> {
let _mark = new Mark();
mark.mark = mark;
mark.pseudo = await pseudoRepository.findOne({ pseudo });
await this.pseudoRepository.save(_mark)
}
}
I didn't try it but I suppose this should work:
import { Injectable } from '#nestjs/common';
import { PseudoEntity as Pseudo } from '../entity/pseudo.entity';
import { MarkEntity as Mark } from '../entity/mark.entity';
import { getConnection } from 'typeorm';
#Injectable()
export class PseudoService {
async postMark(markInput: number, pseudoInput: string) {
let mark = new Mark();
mark.mark = markInput;
mark.submission_date = Date.now();
mark.pseudo = await await repository.findOne({ pseudo: pseudoInput});
await getConnection().manager
.save(mark)
.then(mark => {
console.log("Mark has been saved. Mark id is ", mark.id);
});
}
//....
}
You should probably add a check in case no pseudo is found within the database for this pseudoInput.
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)});
}
Suppose I have the following interfaces:
interface Person {
name: string;
}
interface Attendee {
person: Person;
id: number;
}
I have already figured out how to use the compiler API to extract string representations of every property's type, e.g.:
{
Attendee: {
person: "Person",
id: "number"
}
}
Here's how I do it: https://github.com/jlkiri/tsx-ray/blob/master/src/index.ts.
It's a combination of typeToString and getTypeOfSymbolAtLocation of the Type Checker.
However I would like to resolve types likes Person to their definition so that I get:
{
Attendee: {
person: {
name: "string";
},
id: "number"
}
}
Is there API I can use to easily do this, or do I have to implement the logic myself?
Check ts-morph. I recently discovered it and it looks promising.
Here is a minimal code that can do what you want:
import {ClassDeclaration, Project} from 'ts-morph';
const project = new Project({);
project.addSourceFilesAtPaths("src/**/*.ts");
const allSourceFiles = project.getSourceFiles();
allSourceFiles.forEach(sourceFile => {
const classes = sourceFile.getClasses();
classes.forEach(cls => {
console.log(`class ${cls.getName()} {`);
const properties = cls.getProperties();
properties.forEach(prop => {
const type = prop.getType();
if(type.isClassOrInterface()) {
const typeSymbol = type.getSymbol();
console.log(` ${prop.getName()} :
${typeSymbol?.getName()} {`);
const clsDeclaration = typeSymbol?.getDeclarations()[0] as ClassDeclaration;
const members = clsDeclaration.getMembers();
members.forEach(m => {
console.log(` ${m.getText()}`);
});
console.log(` }`);
} else {
console.log(` ${prop.getName()} : ${type.getText()}`);
}
});
console.log(`}`);
});
})
For the following two files:
// ./src/property.ts
class Category {
description: string;
id: number;
}
export default Category;
// ./src/product.ts
import Category from './category';
class Product {
name: string;
price: number;
category: Category;
}
export default Product;
you will get the following printout:
class Category {
description : string
id : number
}
class Product {
name : string
price : number
category : Category {
description: string;
id: number;
}
}