Angular 2: Create objects from a class - class

Hello I'm wondering if it's possible to create a class where you implement an interface and from there you send the data get from .get service to create a new object. Something like this
import { Component, OnInit } from '#angular/core';
import { User} from '../interfaces/user';
import {UserService} from '../services/user.service';
import { UserClass } from '../classes/user-class'
#Component({
selector: 'up-pros',
templateUrl: './pros.component.html',
providers: [UserService]
})
export class ProsComponent implements OnInit {
public users :User[];
public term: string;
constructor(private _httpService: UserService) { }
ngOnInit() {
console.log(UserClass)
this.term= 'INSTRUCTOR';
this._httpService.searchUsers(this.term)
.subscribe(
data => {this.users = new UserClass(data), console.log(data)},
error => alert(error + ' Error Get')
);
}
}
where my UserClass code is something like next one
import { User } from '../interfaces/user';
import { Address } from "../interfaces/address";
export class UserClass implements User {
public id: number
public name: string
public password: string
public lastNameA: string
public lastNameB: string
public photo: string
public telephone: string
public email: string
public userType: string
public active: string
public score: number
public createdAt: string
public updatedAt: string
public Address: Address
constructor ( id: number,
password: string,
name: string,
lastNameA: string,
lastNameB: string,
photo: string,
telephone: string,
email: string,
userType: string,
active: string,
score: number,
createdAt: string,
updatedAt: string,
Address: Address) {
this.name = name
this.password = password
this.lastNameA = lastNameA
this.lastNameB = lastNameB
this.photo = photo
this.telephone = telephone
this.email = email
this.userType = userType
this.active = active
this.score = score
this.createdAt = createdAt
this.updatedAt = updatedAt
this.Address = Address
}
}
and by the last, the interface:
import { Address } from "./address"
export interface User {
name: string;
password: string;
lastNameA: string;
lastNameB: string;
photo: string;
telephone: string;
email: string;
userType: string;
active: string;
score: number;
createdAt: string;
updatedAt: string;
Address: Address;
}
Is this possible? because if I try to do this Im getting the next error at pros-component.ts:
Supplied parameters do not match any signature of call target.
[default] Checking finished with 1 errors
My service:
import {Injectable} from '#angular/core';
import {Http, Headers} from '#angular/http';
import 'rxjs/add/operator/map';
import { User } from '../interfaces/user';
#Injectable()
export class UserService {
url= 'http://localhostapi/users';
constructor(private _http: Http){}
getUsers(){
return this._http.get(this.url)
.map(res => res.json());
}
searchUsers(term : string ){
return this._http.get('http://localhostapi/listas?user='+term)
.map(res => res.json());
}
searchUser(term : string ){
return this._http.get('http://localhostapi/users/'+term)
.map(res => res.json());
}
postUsers(user: User){
var headers = new Headers ();
headers.append('Content-Type','application/json');
return this._http.post(this.url, user, {headers: headers})
.map(res => res.json());
}
updateUsers(user: User, term: string){
var headers = new Headers ();
headers.append('Content-Type','application/json');
return this._http.put(this.url+"/"+term, user, {headers: headers})
.map(res => res.json());
}
}

If the structure of data matches the list of UserClass, you can simply do
this._httpService.searchUsers(this.term)
.subscribe(
data => {
this.users = data as User[];
console.log(data)
},
error => alert(error + ' Error Get')
);

Related

How to use Axios in Nest.js to POST params request?

I am beginner in NestJS and I would like to ask question on how to use Axios in NestJs. But the problem is I keep getting error TypeError: Converting circular structure to JSON
I have created an API POST http://localhost:3000/api/create in NestJS and my raw request
Raw input
{
"id":1,
"date":"2022-06-28",
"roster":[
{
"startDate":"2022-06-27",
"weekDay":1,
"session":1,
"sTime":"08:00:00",
"eTime":"10:00:00"
}
]
}
Postman request images
My goal is in create.service.ts file, I want pass the value that I receive in postman and add all values into new API link https://create.com/api/index.php?id=&date=&roster=[].
Expected output : https://create.com/api/index.php?id=1&date=2022-06-27&roster=[{"startDate":"2022-06-27","weekDay":1,"session":1,"sTime":"08:00:00","eTime":"10:00:00"}]
But I receive an error TypeError: Converting circular structure to JSON when I submit my post request
create.service.ts
import { HttpException, Injectable } from '#nestjs/common';
import axios from 'axios';
import { CreateValidator } from './create.validator';
#Injectable()
export class CreateService {
constructor() { }
async create(query: CreateValidator) {
return axios.post(`https://create.com/api/index.php?`, null, { params: query })
.then()
.catch(err => {
throw new HttpException(err.response?.data ?? err.response?.statusText ?? 'Unexpected error.', err.response?.status ?? 400);
});
}
}
create.controller.ts
import { Post, Body } from '#nestjs/common';
import { ApiConsumes, ApiTags } from '#nestjs/swagger';
import { BaseController } from '../base/base.controller';
import { CreateService } from './create.service';
import { CreateValidator } from './create.validator';
#ApiTags('New : Create ')
export class CreateController extends BaseController {
constructor(
private readonly createService: CreateService,
) {
super();
}
#Post('api/create')
#ApiConsumes('application/x-www-form-urlencoded')
async create(#Body() body: CreateValidator) {
const result = await this.createService.create(body);
return {result,};
}
}
create.validator.ts
import { ApiProperty } from '#nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsNotEmpty, isString } from 'class-validator';
export class CreateValidator {
#ApiProperty({type: Number,required: true,})
id: number;
#ApiProperty({type: String,required: true,})
date: Date;
#ApiProperty({type: [Object],})
#Transform((input) => isString(input.value) ? JSON.parse(input.value) : input.value)
#IsNotEmpty({ message: 'IsNotEmpty' })
roster: Array<{
startDate: Date;
weekDay: number;
s_time: string;
e_time: string;
}>;
}
My current coding as below
It turns out that I need to change #ApiProperty({ type : [Object]}) into #ApiProperty({ type : Object }) in my validator file.
create.validator.ts
import { ApiProperty } from '#nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsNotEmpty, isString } from 'class-validator';
export class CreateValidator {
#ApiProperty({type: Number,required: true,})
id: number;
#ApiProperty({type: String,required: true,})
date: Date;
#ApiProperty({type: Object,})
#Transform((input) => isString(input.value) ? JSON.parse(input.value) : input.value)
#IsNotEmpty({ message: 'IsNotEmpty' })
roster: Array<{
startDate: Date;
weekDay: number;
s_time: string;
e_time: string;
}>;
}
Now it's working fine.
Thanks.

(node:18560) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'typeFn' of undefined

I am getting this error when I am trying to resolve a field(blocks) with the #ResolveField() decorator.
page.resolver.ts
import {
Resolver,
Query,
Mutation,
Args,
ResolveField,
Parent,
} from '#nestjs/graphql';
import { PageService } from './page.service';
import { PageType } from './type/page.type';
import { CreatePageInput } from './input/create-page.input';
import { BlockService } from '../block/block.service';
import { Page } from './page.interface';
#Resolver('Page')
export class PageResolver {
constructor(
private readonly pageService: PageService,
private readonly blockService: BlockService,
) {}
#Query(() => [PageType])
pages() {
return this.pageService.getAllPages();
}
#Query(() => [PageType])
async page(#Args('id') id: string) {
return this.pageService.getPage(id);
}
#Mutation(() => PageType)
createPage(#Args('createPageInput') createPageInput: CreatePageInput) {
return this.pageService.createPage(createPageInput);
}
#ResolveField()
blocks(#Parent() page: Page) {
return this.blockService.getManyBlocks(page.blockIds);
}
}
page.interface.ts
import { Document } from 'mongoose';
export interface Page extends Document {
readonly id: string;
readonly name: string;
readonly createdAt: Date;
readonly updatedAt: Date;
readonly createdBy: string;
readonly updatedBy: string;
readonly blockIds: string[];
}
It's solved after using the function () => PageType in the #Resolver() decorator.
#Resolver(() => PageType)

How do we get android token on ionic 4?

Hello i'm using fcm ionic native plugin, its working well with android 7 and below but on android 8 Oreo and above it can't get the device token, what could be the problem?
You can use the code below and hope it works out for you:
export interface AuthResponseData {
kind: string;
idToken: string;
email: string;
refreshToken: string;
localId: string;
expiresIn: string;
registered?: boolean;
}
export class AuthService implements OnDestroy {
private _user = new BehaviorSubject<User>(null);
get token() {
return this._user.asObservable().pipe(
map(user => {
if (user) {
return user.token;
} else {
return false;
}
})
);
}
constructor(private http: HttpClient) { }
signup(email: string, password: string) {
return this.http
.post<AuthResponseData>(
`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${yourAPIKey}`,
{ email, password, returnSecureToken: true })
.pipe(tap(this.setUserData.bind(this)));
}
login(email: string, password: string) {
return this.http
.post<AuthResponseData>(
`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${yourAPIKey}`,
{ email, password, returnSecureToken: true })
.pipe(tap(this.setUserData.bind(this)));
}
private setUserData(userData: AuthResponseData) {
const expirationTime = new Date(new Date().getTime() + +userData.expiresIn * 1000);
const user = new User(userData.localId, userData.email, userData.idToken, expirationTime);
this._user.next(user);
this.storeAuthData(userData.localId, userData.idToken, expirationTime.toISOString(), userData.email);
}
private storeAuthData(userId: string, token: string, tokenExpirationDate: string, email: string) {
const data = JSON.stringify({ userId, token, tokenExpirationDate, email });
Plugins.Storage.set({ key: 'authData', value: data });
}
}
And you can use this link for more information

Cannot read property forEach of undefined

The title of this question is just the error I am currently receiving, but what I really need help with is understanding observables and API calls. For whatever reason, I just haven't been able to get a good grasp of this concept, and I am hoping that someone might have an explanation that will finally click.
I am trying to create a new Angular service that retrieves JSON from an API. I then need to map the response to a model. Due to weird naming conventions, job descriptions and job requirements are used interchangeably here. Here is my service class.
import { CommunicationService } from './communication.service';
import { AiDescription } from '../models/ai-description.model';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class AiDescriptionService {
requirements: Observable<AiDescription[]>;
private aiDescriptionUrl: string = '/api/core/company/jobdescriptions';
private dataStore: {
requirements: AiDescription[]
};
private _requirements: BehaviorSubject<AiDescription[]>;
private emptyRequestParams = {
"company_id": "",
"carotene_id": "",
"carotene_version": "",
"city": "",
"state": "",
"country": ""
};
readonly caroteneVersion: string = "caroteneV3";
constructor(
private communicationService: CommunicationService
) {
this.dataStore = { requirements: [] };
this._requirements = new BehaviorSubject<AiDescription[]>([]);
this.requirements = this._requirements.asObservable();
}
LoadRequirements(params: Object) {
this.communicationService.postData(this.aiDescriptionUrl, params)
.subscribe(res => {
let jobDescriptions = [];
jobDescriptions = res.jobdescriptions;
jobDescriptions.forEach((desc: { id: string; description: string; }) => {
let aiDescription = new AiDescription();
aiDescription.id = desc.id;
aiDescription.description = desc.description;
});
this.dataStore.requirements = res;
this._requirements.next(Object.assign({}, this.dataStore).requirements);
});
}
CreateRequest(
companyID : string,
caroteneID : string,
city: string,
state: string,
country: string
): Object {
let newRequestParams = this.emptyRequestParams;
newRequestParams.company_id = companyID;
newRequestParams.carotene_id = caroteneID;
newRequestParams.carotene_version = this.caroteneVersion;
newRequestParams.city = city;
newRequestParams.state = state;
newRequestParams.country = country;
this.LoadRequirements(newRequestParams);
return this.dataStore;
}
}
The postData() function being called by this.communicationService is here:
postData(url: string, jobInformation: any): Observable<any> {
const start = new Date();
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
const body = JSON.stringify(jobInformation);
const options = { headers };
return this.http.post(url, body, options)
.catch(err => Observable.throw(err))
.do(() => {
this.analyticsLoggingService.TrackTiming('JobPostingService', 'PostSuccess', new Date().getTime() - start.getTime());
}, () => {
this.analyticsLoggingService.TrackError('JobPostingService', 'PostFailure');
});
}
I didn't write the postData function, and I would not be able to modify it. When running a unit test, I am getting this error: "TypeError: Cannot read property 'forEach' of undefined".
But more than simply fixing the error, I am really trying to get a better understanding of using Observables, which is something I haven't been able to get a good understanding of from other sources.
In your example, I recommend replacing any and Object with explicitly defined models.
Here's an example for Angular 8 for Subscription, Promise, and Observable API calls. You can get more info here: https://angular.io/tutorial/toh-pt6.
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
import { Observable } from 'rxjs';
import { User } from './user.model';
#Injectable({ providedIn: 'root' })
export class UserService {
users: User[];
authHeaders = new HttpHeaders()
.set('Content-Type', 'application/json');
constructor(
private readonly http: HttpClient
) { }
getUsers() {
this.http.get(`https://myApi/users`, { headers: this.authHeaders })
.subscribe(
(data: User[]) => {
this.users = data;
}, (error: HttpErrorResponse) => { /* handle error */ });
}
async getUserPromise(userID: number): Promise<User> {
const url = `https://myApi/users/${userID}`;
return this.http.get<User>(url, { headers: this.authHeaders })
.toPromise();
}
getUserObservable(userID: number): Observable<User> {
const url = `https://myApi/users/${userID}`;
return this.http.get<User>(url, { headers: this.authHeaders });
}
}
I like to keep my class models in separate files. This example would have user.model.ts with content like:
export class User {
constructor(
public id: number,
public username: string,
public displayName: string,
public email: string
) { }
}
I've not included authentication headers or error handling for brevity; however, you might want to add those as needed.

angular2-mdl table component with server side data

I experiment with Angular 2 - Material Design Lite especially with the table component but I can not figure out how would I pass data from server on ajax request. Here is the example provided for table initialisation.
How would I pass data from restAPI to table component?
Here I have a kind of working example. I placed the initial data on my Component Init method where I call the DataService which populates the table. I'm not sure if is the right workaround but at this point I have data in table.
import { Component, ViewChild, ViewContainerRef, OnInit, Pipe, PipeTransform } from '#angular/core';
import { MdDialog, MdDialogConfig, MdIcon } from "#angular/material";
import { AuthenticationService, DialogsService, DataService } from '../../../services/';
import { RouterModule, Routes, Router } from '#angular/router';
import {
IMdlTableModelItem,
MdlDefaultTableModel
} from 'angular2-mdl';
export interface ITableItem extends IMdlTableModelItem {
username: string;
email: string;
role: string;
unitPrice: number;
}
#Component({
selector: 'employees',
templateUrl: 'app/layouts/secure/employees/employees.html',
providers: [DialogsService, MdIcon]
})
export class EmployeesComponent implements OnInit {
public message: string;
public employees: any[];
public result: any;
public showSearchBar: false;
public tableData:[ITableItem];
public selected;
public tableModel = new MdlDefaultTableModel([
{key:'username', name:'Username', sortable:true},
{key:'email', name:'Email', sortable:true},
{key:'role', name:'Role', sortable:true},
{key:'status', name:'Status', sortable:true},
{key:'unitPrice', name:'Test', numeric:true}
]);
constructor(
private dialogsService: DialogsService,
public viewContainerRef: ViewContainerRef,
private _dataService : DataService,
private router: Router
) {
}
openDialog() {
this.dialogsService
.confirm('User Form', 'Are you sure you want to do this?', this.viewContainerRef)
.subscribe(res => this.result = res);
}
toggleSearch() {
console.log(this)
}
ngOnInit() {
var self = this;
this._dataService
.GetAll('employees')
.subscribe( data => {
data = Object.keys(data).map((key)=>{ return data[key]})
this.employees = data;
this.tableData = data;
this.tableModel.addAll(this.tableData);
}, error => console.log(error),
() => function ( data ) {
this.tableData = this.employees;
this.tableModel.addAll(this.tableData);
this.selected = this.tableData.filter( data => data.selected);
},
);
}
generateArray(obj){
return Object.keys(obj).map((key)=>{ return obj[key]});
}
selectionChanged($event){
this.selected = $event.value;
}
}
#fefe made it a little more difficult than it had to be, at least with the current version. The magic of the as keyword can do the heavy lifting.
For example my class setup looks like:
import...
export interface IUnreadMessage extends IMdlTableModelItem {
messageId: number;
subject: string;
from: string;
}
#Component ...
export class ...
private unreadMessagesTable = new MdlDefaultTableModel([
{key: 'messageId', name: 'Message ID'},
{key: 'subject', name: 'Subject'},
{key: 'from', name: 'From'}
]);
Then in my ajax call I have:
...ajax call here).subscribe(value => {
const messages = value as Array<IUnreadMessage>;
this.unreadMessagesTable.addAll(messages);
},
error => {
...error handler here...
});
Make sure your interface is EXACTLY (including case) the same as your returned ajax data and it should hook right up!