I'm trying to pass the data of an Observable retrieved by API request to a component variable in order to display it but I just can't make it work. Please help, here is my code. Regards,
TypeScript Service : Request to API to get Observable
export class ServeurService {
serverCharacter = 'https://cegep.fdtt.space/v1/characters';
serverSecret = 'https://cegep.fdtt.space/v1/secret';
personnages: any[] = [];
persoName = '';
constructor(private http_client: HttpClient) { }
getPersonnage(): Observable<ICharactere[]> {
return this.http_client.get<ICharactere[]>(this.serverCharacter).pipe(retry(4));
}
getAllInfosById(id: string): Observable<ICharactere> {
const myUrl = 'https://cegep.fdtt.space/v1/character/' + id;
return this.http_client.get<ICharactere>(myUrl)?.pipe();
}
setPersonnageName(name: string) {
this.persoName = name;
}
getPersonnageName():string {
return this.persoName;
}
getPersonnages() {
this.http_client.get<any>('https://cegep.fdtt.space/v1/characters').subscribe({
next: (val) => {
val.data.forEach((element: { data: any; }) => {
this.personnages.push(element);
});
}
});
return this.personnages;
}
getPersonnageById(id: string) {
const persoSelectionne = this.getPersonnages().find((x: { id: string; }) => x.id === id);
return persoSelectionne;
}
getPersonnageIdByName(name: string) {
const persoSelectionne = this.getPersonnages().find((n: {name: string; }) => n.name === name);
console.log("perso name service", persoSelectionne)
return persoSelectionne.id;
}
TypeScript Component : Passing the Observable to a variable
export class StatsComponent implements OnInit {
myCharactere!: any;
statLookup = [
{ key: 'str', prefix: $localize`str`, suffix: $localize`enght`, couleur: 'bg-danger' },
{ key: 'dex', prefix: $localize`dex`, suffix: $localize`terity`, couleur: 'bg-primary' },
{ key: 'con', prefix: $localize`con`, suffix: $localize`stitution`, couleur: 'bg-warning' },
{ key: 'int', prefix: $localize`int`, suffix: $localize`elligence`, couleur: 'bg-success' },
{ key: 'sag', prefix: $localize`wis`, suffix: $localize`dom`, couleur: 'bg-info' },
{ key: 'cha', prefix: $localize`cha`, suffix: $localize`risma`, couleur: 'bg-dark' }
];
constructor(public myService: ServeurService) { }
ngOnInit(): void {
this.myService.getAllInfosById(this.myService.getPersonnageIdByName(this.myService.getPersonnageName())).subscribe(result => {
this.myCharactere = result
});
console.log("stats component perso", this.myCharactere)
}
getModifier(stat: number): string {
const mod = Math.floor((stat-10)/2)
return (mod<0)?'-':'+'+ mod.toString();
}
}
HTML : Displaying the variable
<div class="row text-center text-light bg-secondary mt-2 bg-transparent">
<div class="row mt-5">
<div class="col-2" *ngFor="let stat of statLookup">
<div class="{{stat.couleur}} mx-xxl-4 mx-2 mx-md-1 rounded-4">
<div class="fw-bold">{{stat.prefix}}<span class="d-none d-lg-inline">{{stat.suffix}}</span>
</div>
<div class="h2">
{{myCharactere && myCharactere.statistics && myCharactere.statistics[stat.key] ? getModifier(myCharactere.statistics[stat.key]) : ''}}
</div>
<div class="">
{{myCharactere?.data.statistics[stat.key]}}
</div>
</div>
</div>
</div>
If it helps, here is the model too :
export interface ICharactere {
error: string;
data: {
id: string;
name: string;
statistics: { [ key : string ]: number }
race: string;
player: string;
classe : string;
sousclasses: string;
level: number;
background: string;
synopsis: string;
image: string;
health: number;
currentHealth: number;
traits: {
trait: string;
description: string;
}[];
// Should be computed
armorClass: number;
initiative: number;
speed: number;
};
}
You have some fundamental concepts mixed up here. First, you're calling getPersonnages() synchronously and it is making an HTTP call which is an asynchronous operation. I understand what you're trying to do, but if you are going to use observables for your search result, then I suggest you make all of your function calls consistent that way. Here's an example:
getPersonnages(): Observable<any> {
return this.http.get<any>('https://cegep.fdtt.space/v1/characters');
}
getPersonnageIdByName(name: string) {
return new Observable(observer => {
this.getPersonnages().subscribe(
(results => {
observer.next(results.data.find(x => x.name === name))
observer.complete();
})
)
})
}
Now you can search for the ID value you want like this:
this.getPersonnageIdByName("Michel Michaud").subscribe(
(searchResult => {
// here I can get the id
const id = searchResult.id;
})
);
Related
I want to export filtered/sorted data(or whatever other actions applied to the table, ie: hide specific column) instead of exporting all the data. Is there a way to do it? I am fairly new to angular, if you could use simple language to explain that'll be great!
Below are my codes
excel.service.ts:
import { Injectable } from '#angular/core';
import * as FileSaver from 'file-saver';
import * as XLSX from 'xlsx';
const EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
const EXCEL_EXTENSION = '.xlsx';
#Injectable({
providedIn: 'root'
})
export class ExcelService {
constructor() { }
public exportAsExcelFile(json: any[], excelFileName: string): void {
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(json);
delete (worksheet[1])
const workbook: XLSX.WorkBook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] };
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
this.saveAsExcelFile(excelBuffer, excelFileName);
}
private saveAsExcelFile(buffer: any, fileName: string): void {
const data: Blob = new Blob([buffer], {type: EXCEL_TYPE});
FileSaver.saveAs(data, fileName + '_' + new Date().toLocaleDateString() + EXCEL_EXTENSION);
}
}
table.component.ts:
showTCExportMenu=false
showTEExportMenu=false
exportAsXLSX(data, name, reimport=false):void {
let table = data
reimport? null: table.forEach(
table => { table.justification? table.justification = table.justification.replace(/<\/?(?!a)\w*\b[^>]*>/ig, ''): null,
table.evidence? table.evidence = table.evidence.replace(/<\/?(?!a)\w*\b[^>]*>/ig, ''): null,
delete table.id, delete table.log
})
// execu ? this.getTestExecu(this.uuid): this.getTestCat(this.uuid)
this.excelService.exportAsExcelFile(table, name);
this.showTCExportMenu=false
this.showTEExportMenu=false
}
table.component.html:
<div>
<clr-datagrid [(clrDgSelected)]="selected">
<clr-dg-column
*ngFor="let column of columns"
[clrDgField]="getStringKey(column.key)">
<ng-container *clrDgHideableColumn="{hidden: false}">
{{column.title}}
</ng-container>
<clr-dg-filter
*ngIf="column?.filter"
[clrDgFilter]="getFilter(column)">
<ng-container filterHost></ng-container>
</clr-dg-filter>
</clr-dg-column>
<clr-dg-row
*clrDgItems="let item of records"
[clrDgItem]="item">
<clr-dg-cell
*ngFor="let column of columns"
[innerHTML]="renderValue(column, item)">
</clr-dg-cell>
<clr-dg-row-detail
[innerHTML]="expandRowRender && expandRowRender(item)"
*clrIfExpanded>
</clr-dg-row-detail>
</clr-dg-row>
<clr-dg-footer>
<button class="btn" (click)="exportAsXLSX(tableData, 'example', true)">Export to excel</button>
<clr-dg-pagination #pagination >
<clr-dg-page-size [clrPageSizeOptions]="[5,10,20,30, 50, 100]">Users per page</clr-dg-page-size>
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
of {{pagination.totalItems}} records
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>
here is where I get my data from api, catone.component.ts:
import { Component, OnInit } from '#angular/core';
import {TableColumns, TableData} from "../tableone/tableone.types";
import { faker } from '#faker-js/faker';
import {Observable, Subject} from "rxjs";
import {HttpClient} from "#angular/common/http";
import {ClrDatagridFilterInterface} from "#clr/angular";
import {AgefilterComponent} from "../agefilter/agefilter.component";
import {DatefilterComponent} from "../datefilter/datefilter.component";
interface InventoryData {
test_name: any;
description: any;
status: string;
test_level: string;
test_category: string;
test_type: string;
test_approach: string;
test_applicability: string;
requirement_accountability: string;
test_plan_accountability: string;
trigger_type: string;
applicable_metadata_statuses: string;
assessment_level_targeted: string;
comp_control_flag: string;
testing_platform: string;
effective_date: Date;
test_retired_date: Date;
metric_inclusion: string;
policy_requirement: string
}
export class AgeFilter implements ClrDatagridFilterInterface<InventoryData> {
changes = new Subject<any>();
public minAge!: number;
public maxAge!: number;
accepts(person: InventoryData): boolean {
return true
}
isActive(): boolean {
return false
}
}
export class BirthdayFilter implements ClrDatagridFilterInterface<InventoryData> {
changes = new Subject<any>;
value = '';
accepts(item: InventoryData): boolean {
return true
}
isActive(): boolean {
return false
}
}
#Component({
selector: 'catone',
templateUrl: './catone.component.html',
styleUrls: ['./catone.component.scss']
})
export class CatoneComponent implements OnInit {
columns: TableColumns<InventoryData> = [
{
title: 'Test_name',
key: 'test_name'
},
{
title: 'Description',
key: 'description'
},
{
title: 'Status',
key: 'status'
},
{
title: 'Test_level',
key: 'test_level'
},
{
title: 'Test_category',
key: 'test_category'
},
{
title: 'Test_type',
key: 'test_type',
},
{
title: 'Test_approach',
key: 'test_approach',
},
{
title: 'Test_applicability',
key: 'test_applicability',
},
{
title: 'Requirement_accountability',
key: 'requirement_accountability',
},
{
title: 'Test_plan_accountability',
key: 'test_plan_accountability',
},
{
title: 'Trigger_type',
key: 'trigger_type',
},
{
title: 'Applicable_metadata_statuses',
key: 'applicable_metadata_statuses',
},
{
title: 'Assessment_level_targeted',
key: 'assessment_level_targeted',
},
{
title: 'Comp_control_flag',
key: 'comp_control_flag',
},
{
title: 'Testing_platform',
key: 'testing_platform',
},
{
title: 'Effective_date',
key: 'effective_date',
},
{
title: 'Test_retired_date',
key: 'test_retired_date',
},
{
title: 'Metric_inclusion',
key: 'metric_inclusion',
},
{
title: 'Policy_requirement',
key: 'policy_requirement',
},
];
tableData: TableData<InventoryData> | Observable<TableData<InventoryData>> = [];
page = 1;
pageSize = 10;
total = 1000;
constructor(private httpClient: HttpClient) { }
renderExpand(p: InventoryData) {
return `
<pre>${'test name: ' + p.test_name}</pre>
`
}
handlePageChange(page: number) {
this.page = page;
this.requestApi();
}
requestApi() {
this.httpClient.get<InventoryData[]>(`myapi`)
.subscribe(data => {
this.tableData = data
})
}
ngOnInit(): void {
this.requestApi();
}
}
without any exernal library you can use this function note that rows (in the class CSVargs) is the data to download so if you pass sorted rows or/and specific length's row should work
export interface CSVargs<T> { // you can make change T by any
rows: T[];
keys: string[];
titles: string[];
filename?: string;
columnDelimiter?: string;
lineDelimiter?: string;
}
export function downloadCSV(args: CSVargs) {
args.filename = args.filename || 'export.csv';
args.columnDelimiter = args.columnDelimiter || ';';
args.lineDelimiter = args.lineDelimiter || '\n';
let csv = convertArrayOfObjectsToCSV(args);
if (csv == null) { return; }
if (!csv.match(/^data:text\/csv/i)) {
const bom = '\uFEFF';
csv = 'data:text/csv;charset=utf-8,' + bom + csv;
}
const data = encodeURI(csv);
const link = document.createElement('a');
link.setAttribute('href', data);
link.setAttribute('download', args.filename);
link.click();
}
function convertArrayOfObjectsToCSV(args: CSVargs) {
if (!args.rows || !args.rows.length) {
return;
}
if (!args.keys || !args.keys.length) {
args.keys = Object.keys(args.rows[0]);
}
if (!args.titles || !args.titles.length) {
args.titles = args.keys;
}
let result = '';
result += '"' + args.titles.join('"' + args.columnDelimiter + '"') + '"';
result += args.lineDelimiter;
args.rows.forEach(item => {
let ctr = 0;
args.keys.forEach(key => {
if (ctr > 0) {
result += args.columnDelimiter;
}
const value = (item && !item[key]) ? item[key] : ''; // is better to check item not undefined not null not empty (create a function to check is not blanc)
result += '"' + value + '"';
ctr++;
});
result += args.lineDelimiter;
});
return result;
}
I am trying to display the data of an object on Angular like so
{{myCharactere && myCharactere.statistics && myCharactere.statistics[stat.key] || ''}}.
The object is issue from an API GET request but I'm not able to send it's value to my local variable myCharactere. Thank you for helping me out! Edit: Added code for clarification
Here is what I tried
TypeScript component
export class StatsComponent implements OnInit {
myCharactere: any;
statLookup = [
// Pourquoi est-ce un mauvais choix???
{ key: 'str', prefix: $localize`str`, suffix: $localize`enght`, couleur: 'bg-danger' },
{ key: 'dex', prefix: $localize`dex`, suffix: $localize`terity`, couleur: 'bg-primary' },
{ key: 'con', prefix: $localize`con`, suffix: $localize`stitution`, couleur: 'bg-warning' },
{ key: 'int', prefix: $localize`int`, suffix: $localize`elligence`, couleur: 'bg-success' },
{ key: 'sag', prefix: $localize`wis`, suffix: $localize`dom`, couleur: 'bg-info' },
{ key: 'cha', prefix: $localize`cha`, suffix: $localize`risma`, couleur: 'bg-dark' }
];
constructor(public myService: ServeurService) { }
ngOnInit(): void {
this.myService.getAllInfosById(this.myService.getPersonnageIdByName("Xefoul Snaromers")).subscribe(result => {
this.myCharactere = result
console.log(this.myCharactere);
});
getModifier(stat: number): string {
const mod = Math.floor((stat-10)/2)
return (mod<0)?'-':'+'+ mod.toString();
}
}
TypeScript Service
export class ServeurService {
personnages: any[] = [];
persoName = '';
constructor(private http_client: HttpClient) { }
getPersonnage(): Observable<ICharactere[]> {
return this.http_client.get<ICharactere[]>(this.serverCharacter).pipe(retry(4));
}
getAllInfosById(id: string) {
const myUrl = 'https://cegep.fdtt.space/v1/character/' + id;
return this.http_client.get<ICharactere>(myUrl).pipe();
}
setPersonnageName(name: string) {
this.persoName = name;
}
getPersonnageName():string {
return this.persoName;
}
getPersonnages() {
this.http_client.get<any>('https://cegep.fdtt.space/v1/characters').subscribe({
next: (val) => {
val.data.forEach((element: { data: any; }) => {
this.personnages.push(element);
});
}
});
return this.personnages;
}
getPersonnageById(id: string) {
const persoSelectionne = this.getPersonnages().find((x: { id: string; }) => x.id === id);
return persoSelectionne;
}
getPersonnageIdByName(name: string) {
const persoSelectionne = this.getPersonnages().find((n: {name: string; }) => n.name === name);
console.log("perso name service", persoSelectionne)
return persoSelectionne.id;
}
}
HTML to display
<div class="row text-center text-light bg-secondary mt-2 bg-transparent">
<div class="row mt-5">
<div class="col-2" *ngFor="let stat of statLookup">
<div class="{{stat.couleur}} mx-xxl-4 mx-2 mx-md-1 rounded-4">
<div class="fw-bold">{{stat.prefix}}<span class="d-none d-lg-inline">{{stat.suffix}}</span>
</div>
<div class="h2">
{{myCharactere && myCharactere.statistics && myCharactere.statistics[stat.key] ? getModifier(myCharactere.statistics[stat.key]) : ''}}
</div>
<div class="">
{{myCharactere && myCharactere.statistics && myCharactere.statistics[stat.key] || ''}}
</div>
</div>
</div>
</div>
Model if it helps
export interface ICharactere {
error: string;
id: string;
name: string;
statistics: { [ key : string ]: number }
race: string;
player: string;
classe : string;
sousclasses: string;
level: number;
background: string;
synopsis: string;
image: string;
health: number;
currentHealth: number;
traits: {
trait: string;
description: string;
}[];
armorClass: number;
initiative: number;
speed: number;
}
Summarized from comments:
In your component you can use
serviceName.getAllInfosById("demochar").subscribe(console.log)
to manually make the request to the API and log the result. Please be aware that this.http_client.get<ICharactere>(myUrl) returns a cold observable. This means that nothing will be done until you actually call .subscribe to it.
Best practice:
Usually when you want to display data from an observable in your HTML template you define an observable and subscribe to it using async pipe.
The way to do this is to first define the observable in your component, like: info$ = this.serviceName.getAllInfosById("demochar").
Now in your HTML template you can use {{ (info$ | async).name }} to first subscribe to the observable (async pipe does this for you) and display the name property of the emitted value.
If you are actually using an observable like this.http_client.get<ICharactere>(myUrl), another way is to await the return value and store it in a this.myCharactere:
async getInfos(): void {
this.myCharactere = await firstValueFrom(this.myService.getAllInfosById(this.myService.getIdPersonnageByName("Xefoul Snaromers")));
}
I have a reusable child table component that loads dynamically based on data from the parent component.
For the first time everything loads well, however when I need to click on one of the sort columns in the table I need to send that sort property again to the parent component to return the result from api and refresh the data in the child component with a new set of data from api.
In the code it looks like this, I missed something in that refresh:
table.component.ts
export class TableComponent implements OnChanges {
#Input() items;
#Input() headers;
#Input('sortColumn') sortColumn;
#Output() sortColumnChange = new EventEmitter<string>();
ngOnChanges(changes: SimpleChanges) {
this.items;
console.log('OnChanges', changes);
}
onSortClick(event, selectedColumn) {
const target = event.currentTarget,
classList = target.classList;
let column = '';
if (classList.contains('sort-icon-asc')) {
classList.remove('sort-icon-asc');
classList.add('sort-icon-desc');
column = `${selectedColumn} DESC`;
this.sortColumn = column;
this.sortColumnChange.emit(column);
} else {
classList.add('sort-icon-asc');
classList.remove('sort-icon-desc');
column = `${selectedColumn} ASC`;
this.sortColumn = column;
this.sortColumnChange.emit(column);
}
}
}
table.component.html
<table>
<thead>
<td (click)="onSortClick($event, header.value)" *ngFor="let header of headers" class="sort-icon-asc">{{ header.name }}</td>
</thead>
<tbody>
<tr *ngFor="let item of items">
<td *ngFor="let value of item | objectValues">
{{ value }}
</td>
</tr>
</tbody>
</table>
users.component.ts
export class UsersComponent implements OnInit {
observablesDispose$: Subject<void> = new Subject();
sortColumn = 'userId ASC';
items: [];
usersTableHeaders = [
{
value: 'userId',
name: this.translateService.instant('ADMIN.USERS_TABLE.USER_ID')
},
{
value: 'name',
name: this.translateService.instant('ADMIN.USERS_TABLE.NAME')
},
{
value: 'role',
name: this.translateService.instant('ADMIN.USERS_TABLE.ROLE')
},
{
value: 'email',
name: this.translateService.instant('ADMIN.USERS_TABLE.EMAIL')
},
{
value: 'status',
name: this.translateService.instant('ADMIN.USERS_TABLE.STATUS')
}
];
constructor(
private readonly usersService: UsersService,
private readonly translateService: TranslateService
) {}
ngOnInit(): void {
this.getUsers();
}
getUsers(): void {
this.usersService
.getUsers(this.sortColumn)
.pipe(takeUntil(this.observablesDispose$))
.subscribe((users) => {
this.items = users.resultList.map((tableColumn) => ({
userId: tableColumn.userId,
name: tableColumn.displayName,
role: tableColumn.role,
email: tableColumn.email,
status: tableColumn.status
}));
});
}
ngOnDestroy(): void {
this.observablesDispose$.next();
this.observablesDispose$.complete();
}
}
users.component.html
<div class="row">
<div class="table-section">
<app-table
[headers]="usersTableHeaders"
[items]="items"
[(sortColumn)]="sortColumn">
</app-table>
</div>
</div>
EDIT
users.component.ts
export class UsersComponent implements OnInit {
observablesDispose$: Subject<void> = new Subject();
sortColumn = 'userId ASC';
items: [];
usersTableHeaders = [
{
value: 'userId',
name: this.translateService.instant('ADMIN.USERS_TABLE.USER_ID')
},
{
value: 'name',
name: this.translateService.instant('ADMIN.USERS_TABLE.NAME')
},
{
value: 'role',
name: this.translateService.instant('ADMIN.USERS_TABLE.ROLE')
},
{
value: 'email',
name: this.translateService.instant('ADMIN.USERS_TABLE.EMAIL')
},
{
value: 'status',
name: this.translateService.instant('ADMIN.USERS_TABLE.STATUS')
}
];
constructor(
private readonly usersService: UsersService,
private readonly translateService: TranslateService
) {}
ngOnInit(): void {
this.getUsers();
}
getUsers(): void {
this.usersService
.getUsers(this.sortColumn)
.pipe(takeUntil(this.observablesDispose$))
.subscribe((users) => {
this.items = users.resultList.map((tableColumn) => ({
userId: tableColumn.userId,
name: tableColumn.displayName,
role: tableColumn.role,
email: tableColumn.email,
status: tableColumn.status
}));
});
}
updateSort(newColumn: string): void {
this.sortColumn = newColumn;
this.getUsers();
}
ngOnDestroy(): void {
this.observablesDispose$.next();
this.observablesDispose$.complete();
}
}
users.component.html
<div class="row">
<div class="table-section">
<app-table
[headers]="usersTableHeaders"
[items]="items"
[(sortColumn)]="sortColumn"
(sortColumnChange)="updateSort($event)"
>
</app-table>
</div>
</div>
In your way of handle sortColumn change you cannot control change of it to update users list. In your component you should do like:
users.component.html
<div class="row">
<div class="table-section">
<app-table
[headers]="usersTableHeaders"
[items]="items"
[sortColumn]="sortColumn"
(sortColumnChange)="updateSort($event)">
</app-table>
</div>
</div>
users.component.ts
...
updateSort(newColumn: string): void {
this.sortColumn = newColumn;
getUsers();
}
So I got a User Enitity (Benutzer) and want to get only those users, who are supervisors (Vorgesetzter). Therefore I implemented a Service called " getAllVorgesetzten".
The User Entity looks like:
#Entity()
export class Benutzer {
#PrimaryGeneratedColumn({ type: "int" })
BenutzerID: number;
#Column({ type: "varchar", length: 50})
Benutzername: string;
#Column({ type: "varchar", length: 50})
Passwort: string;
#Column()
istAdmin: boolean;
#Column()
istVorgesetzter: boolean;
#Column({ type: "varchar", length: 50})
Vorgesetzter: string;
#Column({ type: "varchar", length: 50})
Vorname: string;
#Column({ type: "varchar", length: 50})
Nachname: string;
#Column()
Geburtsdatum: Date;
#Column({ type: "varchar", length: 50})
Email: string;
#Column()
Eintrittsdatum: Date;
#ManyToOne(() => Arbeitstage, arbeitstage => arbeitstage.allebenutzer)
arbeitstage: Arbeitstage;
#ManyToOne(() => Bundesland, bundesland => bundesland.alleBenutzer)
bundesland: Bundesland;
#OneToMany(() => Urlaubsantrag, urlaubsantrag => urlaubsantrag.benutzer)
anträge: Urlaubsantrag[];
}
The User Service is implemented as follows:
#Injectable()
export class BenutzerService {
constructor(
#InjectRepository(Benutzer)
private benutzerRepository: Repository<Benutzer>,
) {}
getAllBenutzer(): Promise<Benutzer[]> {
return this.benutzerRepository.find({ relations: ['bundesland', 'arbeitstage', 'anträge']});
}
findBenutzerByID(id: number): Promise<Benutzer> {
return this.benutzerRepository.findOne(id, { relations: ['bundesland','arbeitstage','anträge']});
}
getAllVorgesetzten(istVorgesetzter: boolean): Promise<Benutzer[]>{
return this.benutzerRepository.find({ where: {istVorgesetzter: istVorgesetzter} });
}
async createBenutzer(benutzer: CreateBenutzer) {
const nutzer = this.benutzerRepository.create(benutzer);
await this.benutzerRepository.save(benutzer);
return nutzer;
}
async updateBenutzer(benutzer: UpdateBenutzer): Promise<UpdateResult> {
return await this.benutzerRepository.update(benutzer.BenutzerID, benutzer);
}
async deleteBenutzer(id: number): Promise<DeleteResult> {
return await this.benutzerRepository.findOne(id).then((value) => {
return this.benutzerRepository.delete(value);
});
}
}
And the Controller looks like:
#Controller('benutzer')
export class BenutzerController {
constructor(private readonly benutzerService: BenutzerService) {}
#Post()
async createBenutzer(#Body() createBenutzer: CreateBenutzer): Promise<Benutzer> {
return this.benutzerService.createBenutzer(createBenutzer);
}
#Get()
async getBenutzer(): Promise<Benutzer[]> {
return this.benutzerService.getAllBenutzer();
}
#Get(':id')
async getBenutzerByID(#Param('id', new ParseIntPipe()) id): Promise<Benutzer> {
return this.benutzerService.findBenutzerByID(id);
}
#Get('/vorgesetzter')
async getAllVorgesetzten(#Query('istVorgesetzter', new ParseBoolPipe()) istVorgesetzter: boolean): Promise<Benutzer[]>{
console.log(istVorgesetzter);
return this.benutzerService.getAllVorgesetzten(istVorgesetzter);
}
#Patch()
async update(#Body() updateBenutzer: UpdateBenutzer) {
return this.benutzerService.updateBenutzer(updateBenutzer);
}
#Delete(':id')
async remove(#Param('id', new ParseIntPipe()) id) {
return this.benutzerService.deleteBenutzer(id);
}
}
So I have the request method like http://localhost:3000/benutzer/vorgesetzter?istVorgesetzter=true and want to get all users (benutzer) where istVorgesetzter = true. But I get the following error:
error in swagger
{
"statusCode": 400,
"message": "Validation failed (numeric string is expected)",
"error": "Bad Request"
}
Order matters here, #Get('/vorgesetzter') should be implemented before #Get(':id'). With that request you are calling this.benutzerService.findBenutzerByID(id); with the following string: vorgesetzter?istVorgesetzter=true receiving the error you describe.
This is how express is implemented and NestJS follows the same behaviour: expressjs/express#2235, nestjs/nest#995
I am working on Angular application and need map nested object with collection. I have map first half of data but I am struggling to map collection, reference options[] under heading mapping Code
I have add question base class followed by DropdownQuestion class to which I am intended to map json data. structure of json data is in data model class
data model class
export class QuestionsDataModel
{
consultationId: string;
displayId: string;
displayOrder: string;
questionId: string;
questionType: string;
title: string;
questionElement: {
questionElementId: string;
questionElementTypeId: string;
questionId: string;
questionElementType: {
id:string;
typeDefination: string;
validation: string;
};
preDefineAnswer:{
questionElementId:string;
preDefineAnswerId:string;
text:string;
preDefineSubAnswer:{
preDefineAnswerId: string;
preDefineSubAnswerId: string;
subText:string;
};
};
} ;
}
Mapping code (need help here)
for(var key in questionsList)
{
let _dropBox = new DropdownQuestion({
consultationId: questionsList[key].consultationId,
questionId: questionsList[key].questionId,
questionElementId: questionsList[key].questionElementId,
questionType: questionsList[key].questionType,
title:questionsList[key].title,
key: questionsList[key].questionId,
label: questionsList[key].title,
options: [ // need help here, how to map this collection from json data
{key: 'solid', value: 'Solid'},
{key: 'great', value: 'Great'},
{key: 'good', value: 'Good'},
{key: 'unproven', value: 'Unproven'}
],
order: 1
});
Dropdown class
import { QuestionBase } from './question-base';
export class DropdownQuestion extends QuestionBase<string> {
controlType = 'dropdown';
options: {key: string, value: string}[] = [];
constructor(options: {} = {}) {
super(options);
this.options = options['options'] || [];
}
}
Question Base class
export class QuestionBase<T>{
consultationId: string;
questionId: string;
questionElementId:string;
questionType:string;
title:string;
value: T;
key: string;
label: string;
required: boolean;
order: number;
controlType: string;
constructor(options: {
consultationId?:string,
questionId?:string,
questionElementId?:string,
questionType?:string,
title?:string,
value?: T,
key?: string,
label?: string,
required?: boolean,
order?: number,
controlType?: string
} = {}) {
this.consultationId = options.consultationId,
this.questionId = options.questionId,
this.questionElementId = options.questionElementId,
this.questionType = options.questionType,
this.title = options.title,
this.value = options.value;
this.key = options.key || '';
this.label = options.label || '';
this.required = !!options.required;
this.order = options.order === undefined ? 1 : options.order;
this.controlType = options.controlType || '';
}
}
[![enter image description here][1]][1]
error after using map
You can use the Array.prototype.map function:
for(var key in questionsList)
{
let _dropBox = new DropdownQuestion({
[...],
options: questionsList[key].preDefineAnswer.map(a => {key: a.preDefineAnswerId, value: a.text},
[...]
});