how to store API response in an array in angular - node.js

i have a service that returns an API response of type json, in this json object i have a list of number values.i can output those values on my webpage, but i would like to store the values in an array first to do some calculations on. i have tried many ways without success. please guide me
API response screenshot in postman
http call service
getTriggerCount():Observable<Trigger>{
return this.http.get(this.triggersUrl).pipe(
flatMap(count => transformAndValidate(Trigger, count)))
component
#Component({
selector: 'app-triggers',
templateUrl: './triggers.component.html',
styleUrls: ['./triggers.component.css']
})
export class TriggersComponent implements OnInit {
#Input() trigger: Trigger;
constructor(private triggerService: DbApiService) { }
ngOnInit() {
this.getTriggerCount();
}
getTriggerCount(){
this.triggerService.getTriggerCount() .subscribe(trigger => this.trigger = trigger);
}
}
Trigger Class
import { IsNumber, IsNotEmpty, IsString } from 'class-validator';
export class Trigger {
#IsNotEmpty()
#IsNumber()
result: number[];
constructor() { }
}

The issue is with your service, it should be like the following
getTriggerCount():Observable<any>{
return this.http.get(this.triggersUrl).map(res => res.json());
}
Using the new HttpClient it should like like this:
getTriggerCount():Observable<any>{
return this.http.get<any>(this.triggersUrl);
}
To make use of this in the component. You also do not need the #Input() for trigger. Your Trigger class is also over complicated for what you are doing. See below
public trigger: any;
getTriggerCount(){
this.triggerService.getTriggerCount()
.subscribe(trigger => this.trigger = trigger);
}
This will then have the response on the trigger object. If you want to make use of the object, to say, add all the numbers together, you would do the following:
addArray() {
let sum = this.trigger.reduce((a, b) => +a + +b, 0);
}
The +a and +b is to convert the item to a number. This won't work if the item can't convert to a number.

Related

Jest branch code coverage - problem with nullable values

At first glance problem looks really easy, but unfortunately I have a problem with covering test scenario when nullable getter is null. Considering the sample below:
#Component({
selector: 'sample-form-test',
templateUrl: './sample-form-test.component.html'
})
export class SampleFormTestComponent implements ngOnInit {
form?: FormGroup;
get name(): FormControl | null {
return this.form?.get('name') as FormControl;
}
constructor(private formBuilder: FormBuilderService) {}
ngOnInit() {
this.form = this.formBuilder.build();
}
It is always underlined in a code coverage report that the question mark inside the getter above is not covered by the tests. Even if I try to cover it by checking directly whether is that getter null right after a component creation:
describe('create SampleFormTestComponent', () => {
let spectator = Spectator<SampleFormTestComponent>; // from #ngneat/Spectator
const createComponent = createComponentFactory({ // from #ngneat
component: SampleFormTestComponent,
providers: MockProvider(FormBuilderService, {
build: () => {
new FormGroup({name: new FormControl})
}
}
});
it('should create', () => {
spectator = createComponent();
expect(spectator).toBeTruthy();
expect(spectator.component.name).toBeNull();
});
}
It doesn't help at all and branch coverage is always lowered by that nullable getters. The worst scenario is when I have them multiple inside the class - in that scenario it is not possible to meet code coverage requirements. Do you know how can I easily solve that problem?
UPDATE
The easiest way is to initialize form in a constructor – it will allow to access the form properties (even if those are empty) without necessity to check if those values are null ot not.
#Component({
selector: 'sample-form-test',
templateUrl: './sample-form-test.component.html'
})
export class SampleFormTestComponent implements ngOnInit {
form: FormGroup;
get name(): FormControl {
return this.form.get('name') as FormControl;
}
constructor(private formBuilder: FormBuilderService) {
this.form = this.formBuilder.build();
}
Here is the updated Stackblitz solution

NestJS: present response content from URL on healthcheck

I'm trying to develop a healthcheck endpoint with NestJS (in which I have no experience). One of the dependencies I want to check is Twilio's SMS service. So far, the best URL I've found to gather this information is https://status.twilio.com/api/v2/status.json. The problem here is that I don't want to merely ping this address, but to gather it's JSON response and present some of the information it provides, namely these:
Is it possible, using (or not) the Terminus module? In the official docs I didn't find anything regarding this, only simpler examples using pingCheck / responseCheck: https://docs.nestjs.com/recipes/terminus
Yes, it is possible.
I have never used this, but HttpHealthIndicator has responseCheck method to check depends on the API response message. You can specify a callback function to analyze responses from the API. The callback function should return boolean represents the status of the API.
I couldn't find this in the documents, but you can see it here.
Although meanwhile the logic for this healthcheck has changed (and so this question became obsolete), this was the temporary solution I've found, before it happened (basically a regular endpoint using axios, as pointed out in one of the comments above):
Controller
import { Controller, Get } from '#nestjs/common';
import { TwilioStatusService } from './twilio-status.service';
#Controller('status')
export class TwilioStatusController {
constructor(private readonly twilioStatusService: TwilioStatusService) {}
#Get('twilio')
getTwilioStatus() {
const res = this.twilioStatusService.getTwilioStatus();
return res;
}
}
Service
import { HttpService } from '#nestjs/axios';
import { Injectable } from '#nestjs/common';
import { map } from 'rxjs/operators';
#Injectable()
export class TwilioStatusService {
constructor(private httpService: HttpService) {}
getTwilioStatus() {
return this.httpService
.get('https://status.twilio.com/api/v2/status.json')
.pipe(map((response) => response.data.status));
}
}
Of course this wasn't an optimal solution, since I had to do this endpoint + a separated one for checking MongoDB's availability (a regular NestJS healthcheck, using Terminus), the goal being an healthcheck that glued both endpoints together.
It is possible to merge in any property to the resulting object. You can see that in the TypeScript Interface
/**
* The result object of a health indicator
* #publicApi
*/
export declare type HealthIndicatorResult = {
/**
* The key of the health indicator which should be uniqe
*/
[key: string]: {
/**
* The status if the given health indicator was successful or not
*/
status: HealthIndicatorStatus;
/**
* Optional settings of the health indicator result
*/
[optionalKeys: string]: any;
};
};
And here is an example:
diagnostics/health/healthcheck.controller
import { Controller, Get } from '#nestjs/common'
import { ApiTags } from '#nestjs/swagger'
import { HttpService } from '#nestjs/axios'
import { HealthCheckService, HealthCheck, HealthIndicatorStatus, HealthCheckError } from '#nestjs/terminus'
#ApiTags('diagnostics')
#Controller('diagnostics/health')
export class HealthController {
constructor(
private health: HealthCheckService,
private httpService: HttpService,
) { }
#Get()
#HealthCheck()
check() {
return this.health.check([
() => this.httpService.get('http://localhost:9002/api/v1/diagnostics/health').toPromise().then(({ statusText, config: { url }, data }) => {
const status: HealthIndicatorStatus = statusText === 'OK' ? 'up' : 'down'
return { 'other-service': { status, url, data } }
}).catch(({ code, config: { url } }) => {
throw new HealthCheckError('Other service check failed', { 'other-service': { status: 'down', code, url } })
}),
])
}
}
diagnostics/diagnostics.module.ts
import { Module } from '#nestjs/common'
import { TerminusModule } from '#nestjs/terminus'
import { HttpModule } from '#nestjs/axios'
import { HealthController } from './health/health.controller'
#Module({
imports: [
HttpModule,
TerminusModule,
],
controllers: [HealthController],
})
export class DiagnosticsModule { }

Angular8 http and services missunderstand

I'm here because I do not understand how Http works in angular. I would create a "news" thread on my website. To do that I have created a service in my angular app that calls a .net core web API.
Also, I would add a paginate to my thread (I want to display news by 5 on the page).
I can get my values, that is not my issue here. But, to create my paginate, I need to have values for number of pages calculation.
I tried to add code to create my paginate (number of pages, number of elements...) but I always get 0 to these values and my array of news is filled after the onInit(). This is what I don't understand.
This is my component:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { NewsService } from '../news.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
title = 'News';
news = [];
displayed = [];
numberOfPages = 0;
constructor(private newsService: NewsService) { }
ngOnInit() {
// I don't really understand these lines (mainly the subscribe part)
this.newsService.getAllNews().subscribe((data) => {
this.news = Array.from(Object.keys(data), k => data[k]);
// this console.log appears after the onInit(), why ?
console.log(this.news);
});
this.numberOfPages = this.news.length / 5; // Get 0 here, why ?
}
}
My service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class NewsService {
private finalData = [];
private apiUrl = 'https://localhost:5001/api/v1/posts';
constructor(private http: HttpClient) { }
getAllNews() {
return this.http.get(this.apiUrl);
}
}
In the browser console, I get this:
console screen
Maybe I forgot something in my code or I don't know what.
Someone can help me to achieve my goal? I want to understand how to proceed to make a working paginate for my news.
You should add
this.numberOfPages = this.news.length / 5;
inside the subscribe
this.newsService.getAllNews().subscribe((data) => {
this.news = Array.from(Object.keys(data), k => data[k]);
// this console.log appears after the onInit(), why ?
console.log(this.news);
});
like so:
this.newsService.getAllNews().subscribe((data) => {
this.news = Array.from(Object.keys(data), k => data[k]);
// this console.log appears after the onInit(), why ?
console.log(this.news);
this.numberOfPages = this.news.length / 5;
});
My guess is that when you try to initialise the this.numberOfPagesthe this.news.length is not yet set(data are not yet retrieved from the API). Hope this helps

Angular 4 raw string from ActivatedRoute params

I have been searching everywhere I could not find an answer on this. I'm passing a string on the url example. "localhost:4200/home/ABCD%2BrAD4Og%3D%3D" when I subscribe to the param or use snapshot I get something like "ABCD+rAD4Og=="
How do I get what was exactly passed? Thank you
I have found an answer. If you want to get the raw param that was passed all you have to do is use "encodeURIComponent(uri)"
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-example',
template: `<h1>raw URI example</h1>`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent implements OnInit {
constructor(private router: ActivatedRoute) {}
rawUri: string = null;
ngOnInit() {
this.router.params.subscribe(param => {
// the "id" part inside param[''] could be anything you defined in your route config file.
this.rawUri = encodeURIComponent(param['id']);
console.log('raw url param ', this.rawUri);
}
}
}

Angular 2 SimpleChanges Object throws error at first npm start

In my angular 2 application there is a component containing an array of objects that is passing the chosen (clicked) one to it's direct child component. This does display the data more detailed. I'm using the "SimpleChanges" feature to watch in this child component if the object given changed to make another http request to get the related comments from a database.
If I try to build it with npm I get an error, saying :
app/displayEntry.component.ts(23,41): error TS2339: Property 'entry' does not exist on type 'SimpleChanges'
If I just comment this part out, start npm and finally put it in there again and save it, there is no Problem anymore ( no erro and it works ).
My question is, is there a way to work around this behavior and can this cause any trouble later I don't foresee or should I just ignore it? Thanks for your help
Parent component:
import { Component, OnInit } from '#angular/core';
import { entry } from './Objekte/entry';
import { entryService } from './entry.service'
#Component({
templateUrl: 'app/Html_Templates/displayLastEntrys.template.html'
})
export class displayLastEntrys implements OnInit{
public entrys : entry[];
private entryChoosen: boolean;
private ChoosenEntry : entry;
constructor ( private entryservice : entryService){
this.entryChoosen = false;
}
ngOnInit() : void {
this.getData();
}
getData() {
this.entryservice.getFirstEntrys().then(entrys => this.entrys = entrys);
}
entryClicked(ent: entry){
this.entryChoosen = true;
this.ChoosenEntry = ent;
}
leaveEntry () {
this.entryChoosen = false;
}
voted( upordown : boolean ) {
}
}
Child component:
import { Component, Input, Injectable, OnChanges , SimpleChanges, Output, EventEmitter} from '#angular/core';
import { entry} from './Objekte/entry';
import { entryService } from './entry.service';
import { comment } from './Objekte/comments';
#Component({
selector: 'display-entry',
templateUrl: 'app/Html_Templates/displayEntry.template.html'
})
export class displayComponent implements OnChanges{
#Input() public entry : entry;
public comments : comment[];
private changecounter : number;
constructor(private service : entryService) {
this.changecounter = 0;
}
ngOnChanges(changes : SimpleChanges){
this.service.getComments(changes.entry.currentValue.id)
.then(com => this.comments = com )
.catch();
this.entry.viewed++;
// To implement :: change database
}
votedUp () : void {
this.entry.votes ++;
// To implement :: change database
}
votedDown () : void {
this.entry.votes --;
// To implement :: change database
}
}
The accepted solution is suboptimal for TypeScript, as you're defeating the type system.
SimpleChanges does not have an entry property, so the compiler quite rightly balks. The solution is to treat the changes object as an array:
ngOnChanges(changes : SimpleChanges){
if (changes['entry']) {
this.service.getComments(changes['entry'].currentValue.id)
}
}
Then you can continue to strongly type the ngOnChanges method.
To make the compiler not complain just change your method definition for parameter one from SimpleChanges to any:
ngOnChanges(changes: any) {
//...
Maybe it's changed a lot now but this works these days
import {Component, Input, OnChanges, SimpleChanges} from '#angular/core';
import {ConfigModel} from './config.model'
#Component({
selector: 'selector',
templateUrl: './template.html',
styleUrls: ['./styles.scss']
})
export class BlaComponent implements OnChanges {
#Input() config: ConfigModel;
ngOnChanges(changes: SimpleChanges): void {
if (changes.config && changes.config.currentValue) {
let config = <ConfigModel>changes.config.currentValue;
// do more
}
}
}
I myself got the compile error because i wasn't using .currentValue after calling changes.config
If you are completely dependent on the IDE's auto-completion, make sure to actually use SimpleChanges instead of just SimpleChange. A very thing to be overlooked at.

Resources