ngx-chart error "TypeError: Object(...) is not a function" - angular5

I am trying to implements some statistics in my develepping platform and I try to use ngx-charts to display them. However I get an error and I can't figure out why.
I am using storedProcedures for MySQL statistics which I call from Java Restful Backend and return them in Angular 5 front-end. The returned table has the following two fields: Date and number of incidents per day. So the table returned by the backend has those two columns.
My code for the component rendering the chart is the following:
import {Component, OnInit} from '#angular/core';
import {StatisticsService} from '../../statistics.service';
class Data {
private _name: string;
private _value: number;
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
get value(): number {
return this._value;
}
set value(value: number) {
this._value = value;
}
}
#Component({
selector: 'app-daily-incidents-statistics',
templateUrl: './daily-incidents-statistics.component.html',
styleUrls: ['./daily-incidents-statistics.component.css']
})
export class DailyIncidentsStatisticsComponent implements OnInit {
view: any[] = [700, 400];
data: any[] = [];
// options
showXAxis = true;
showYAxis = true;
gradient = false;
showLegend = false;
showXAxisLabel = true;
xAxisLabel = 'Ημέρα';
showYAxisLabel = true;
yAxisLabel = 'Αρ. Περιστατικών';
constructor(private statisticsService: StatisticsService) {
// Object.assign(this, { single })
// Object.assign(this, { data } );
}
colorScheme = {
domain: ['#5AA454', '#A10A28', '#C7B42C', '#AAAAAA']
};
onSelect(event) {
console.log(event);
}
async ngOnInit() {
console.log('NG ON INIT EXECUTION');
await this.getIncidentsByDay();
}
getIncidentsByDay() {
this.statisticsService.getIncidentsByDay()
.subscribe(
(results) => {
let temp = new Data();
for (let i in results) {
console.log(results[i][0] + '>>=====>> ' + results[i][1]);
temp.name = results[i][0];
temp.value = results[i][1];
this.data.push(temp);
}
const test = this.data;
// for (let i = 0; i < this.data.length; i++) {
// console.log('wtf: ' + this.data[i][0] + '::::' + this.data[i][1]);
// }
// console.log(results);
// console.log(JSON.stringify(results));
// Object.assign(this, {test});
}
);
}
}
However when I run the above code I get in JavaScript console the error:
ERROR TypeError: Object(...) is not a function
at BarVerticalComponent../src/common/base-chart.component.ts.BaseChartComponent.bindWindowResizeEvent (index.js:7818)
at BarVerticalComponent../src/common/base-chart.component.ts.BaseChartComponent.ngAfterViewInit (index.js:7730)
at callProviderLifecycles (core.js:12689)
at callElementProvidersLifecycles (core.js:12656)
at callLifecycleHooksChildrenFirst (core.js:12639)
at checkAndUpdateView (core.js:13794)
at callViewAction (core.js:14136)
at execComponentViewsAction (core.js:14068)
at checkAndUpdateView (core.js:13791)
at callViewAction (core.js:14136)
My Html Template File:
<div>
lalalal <br/>
ante pali... <br/>
kala ti na pw... <br/>
Gamiete pali... <br/>
<ngx-charts-bar-vertical
[view]="view"
[scheme]="colorScheme"
[results]="data"
[gradient]="gradient"
[xAxis]="showXAxis"
[yAxis]="showYAxis"
[legend]="showLegend"
[showXAxisLabel]="showXAxisLabel"
[showYAxisLabel]="showYAxisLabel"
[xAxisLabel]="xAxisLabel"
[yAxisLabel]="yAxisLabel"
(select)="onSelect($event)">
</ngx-charts-bar-vertical>
</div>
While the service for retreiving the values is:
import {Injectable} from '#angular/core';
import {HttpClient} from '#angular/common/http';
import {catchError} from 'rxjs/operators';
import {ErrorHandler} from '../shared/lib/error-handler';
import {Observable} from 'rxjs/Observable';
#Injectable()
export class StatisticsService {
constructor(private http: HttpClient) {
}
public getIncidentsByDay(): Observable<any> {
console.log("FEtching Incidents All By Day");
const url = 'statistics/incidents/day';
return this.http.get(url)
.pipe(catchError(ErrorHandler.handleError));
}
}
What am I doing wrong?

I am using Angular version 5.3 and ngx-charts 8.0 which is compatible with Angular 6 and not Angular 5. I installed ngx-charts version 7.4 and everything works fine.

I fixed the problem for me by downgrading to version 7.3.0
yarn add #swimlane/ngx-charts#7.3.0

I think I see the same with ngx-charts-bar-horizontal, whereas before this was not the case. The documentation page seems to be broken at the moment as well, so I assume the software has recently been updated in a broken way.

If you really need to use the 8.0 version, you can upgrade to angular 6 to solve the problem. Here is how you can do the upgrade from v5 to v6 https://stackoverflow.com/a/49474334
You can also think that the documention page is broken by now but ou can find it here https://swimlane.gitbook.io/ngx-charts/v/docs-test/installing

Related

ionic device plugin returning null

No matter what I do or try I can't get info about the device. I'm using last version of ionic 4.
Since all I find online is basically
Don't execute on browser
get the values one by one
Of course that's not what's going on. I'm not doing that, I have cordova available, etc.
I'm testing on device, both android and ios. I deal with this in a service. I'm calling the functions with buttons so everything is more than loeaded, everything is ready. This is the code I'm trying to make work:
import { Injectable } from '#angular/core';
import { Device } from '#ionic-native/device/ngx';
import { Platform } from '#ionic/angular';
#Injectable({
providedIn: 'root'
})
export class InitialService {
eldevice: any = '';
constructor(
private device: Device,
private platform: Platform
) {}
async setup() {
if (this.platform.is('cordova')) { // es movil
this.eldevice = await this.storage.get('device');
if (this.eldevice == null) { // nuevo device
this.eldevice.platform = this.device.platform;
this.eldevice.version = this.device.version;
this.eldevice.uuid = this.device.uuid;
this.eldevice.manufacturer = this.device.manufacturer;
console.log('datos sin await', this.eldevice);
this.eldevice = await this.storage.set('device', this.device);
} else { // device conocido
console.log('datos guardados', this.eldevice);
}
} else { // es virtual
console.log('virtual');
}
}
clearData() {
this.storage.clear();
this.eldevice = null;
}
}
Updated:
Any cordova plugins require you to await for platform to be in "ready" state.
So before calling / using plugins you need to call platform.ready() method and call specific plugin functions in the callback, or after "await".
Also looking at your setup() method you seem like attempting to access properties of an object that gets 'null' assigned to it after storage check. See comments in the code below:
import { Injectable } from '#angular/core';
import { Device } from '#ionic-native/device/ngx';
import { Platform } from '#ionic/angular';
#Injectable({
providedIn: 'root'
})
export class InitialService {
eldevice: any = '';
constructor(
private device: Device,
private platform: Platform
) {}
async setup() {
// await for platform ready:
await this.platform.ready();
if (this.platform.is('cordova')) { // es movil
this.eldevice = await this.storage.get('device');
if (this.eldevice == null) { // nuevo device
// here below 'eldevice' is null (as confirmed by the check above) and you are attempting to assign something to non existing properties (platform, version etc).
// to fix you need actual object to be assigned to eldevice:
this.eldevice = {
platform: this.device.platform,
version: this.device.version,
uuid: this.device.uuid,
manufacturer: this.device.manufacturer
}
//this.eldevice.platform = this.device.platform;
//this.eldevice.version = this.device.version;
//this.eldevice.uuid = this.device.uuid;
//this.eldevice.manufacturer = this.device.manufacturer;
console.log('datos sin await', this.eldevice);
this.eldevice = await this.storage.set('device', this.device);
} else { // device conocido
console.log('datos guardados', this.eldevice);
}
} else { // es virtual
console.log('virtual');
}
}
clearData() {
this.storage.clear();
this.eldevice = null;
}
}

Unable to get nativeElement of ion-textarea in Ionic 4 to set height

I have a custom directive to adjust the ion-textarea height to autosize the height as text is entered rather than setting a fixed row height or having ugly scroll bars as the textarea fills up.
In Ionic-4 I am unable to get the nativeElement of the html textarea of the ion-textarea. Any help would be great
It's running on Angular 6 and Ionic 4 but when I try and get this.element.nativeElement.getElementsByTagName('textarea')[0] it is always undefined so I can't set the height programatically.
import { ElementRef, HostListener, Directive, OnInit } from '#angular/core';
#Directive({
selector: 'ion-textarea[autosize]'
})
export class AutosizeDirective implements OnInit {
#HostListener('input', ['$event.target'])
onInput(textArea:HTMLTextAreaElement):void {
this.adjust();
}
constructor(public element:ElementRef) {
}
ngOnInit():void {
setTimeout(() => this.adjust(), 0);
}
adjust():void {
const textArea = this.element.nativeElement.getElementsByTagName('textarea')[0];
textArea.style.overflow = 'hidden';
textArea.style.height = 'auto';
textArea.style.height = textArea.scrollHeight + 'px';
}
}
As the const textArea always comes back undefined I can't set the height to follow the scroll height to prevent the scroll bars.
Anyone been able to do this in Ionic-4? seen working examples in Ionic-3 as per the above code.
Thank you
Rowie
Below code would help your problem.
import { ElementRef, HostListener, Directive, AfterViewInit } from '#angular/core';
#Directive({
selector: 'ion-textarea[autosize]'
})
export class AutoSizeDirective implements AfterViewInit {
readonly defaultHeight = 64;
#HostListener('input', ['$event.target'])
onInput(textArea: HTMLTextAreaElement) {
this.adjust(textArea);
}
constructor(private element: ElementRef) {}
ngAfterViewInit() {
this.adjust();
}
adjust(textArea?: HTMLTextAreaElement) {
textArea = textArea || this.element.nativeElement.querySelector('textarea');
if (!textArea) {
return;
}
textArea.style.overflow = 'hidden';
textArea.style.height = 'auto';
textArea.style.height = (textArea.value ? textArea.scrollHeight : defaultHeight) + 'px';
}
}
Usage: <ion-textarea autosize></ion-textarea>
I have confirmed it on Ionic 4.0.2/Angular 7.2.6.
Regards.
this package does all the autosizing of my ion-textareas for me https://github.com/chrum/ngx-autosize
just follow the guide and get it working, if it doesn't work importing it into the app.module.ts then try importing it into the page's module, I personally needed that dunno if you will, but package is a life saver

Upgrading from RxJS5 to RxJS6

I'm having an issue upgrading from RxJS5 to version 6. I've got the following code:
private captureEvents(canvasEl: HTMLCanvasElement) {
Observable
.fromEvent(canvasEl, 'mousedown')
.switchMap((e) => {
return Observable
.fromEvent(canvasEl, 'mousemove')
.takeUntil(Observable.fromEvent(canvasEl, 'mouseup'))
.pairwise()
})
.subscribe((res: [MouseEvent, MouseEvent]) => {
const rect = canvasEl.getBoundingClientRect();
const prevPos = {
x: res[0].clientX - rect.left,
y: res[0].clientY - rect.top
};
const currentPos = {
x: res[1].clientX - rect.left,
y: res[1].clientY - rect.top
};
this.drawOnCanvas(prevPos, currentPos);
});
}
But when I upgrade to RxJS6 I get the following error:
Property 'fromEvent' does not exist on type 'typeof Observable'.
I tried to change my imports from this (RxJS5):
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/operator/pairwise';
import 'rxjs/add/operator/switchMap';
To this (RxJS6):
import { Observable, fromEvent } from 'rxjs';
import { switchMap, takeUntil, pairwise } from 'rxjs/operators';
This was my best attempt up upgrading the code:
private captureEvents(canvasEl: HTMLCanvasElement) {
const obsMouseDown = fromEvent(canvasEl, 'mousedown').pipe(
switchMap((e) => {
const obsMouseMove = fromEvent(canvasEl, 'mousemove').pipe(
takeUntil(a => {
const obsMouseUp = fromEvent(canvasEl, 'mouseup').pipe(
pairwise()
);
return obsMouseUp;
}));
return obsMouseMove;
}))
.subscribe((res: [MouseEvent, MouseEvent]) => {
const rect = canvasEl.getBoundingClientRect();
const prevPos = {
x: res[0].clientX - rect.left,
y: res[0].clientY - rect.top
};
const currentPos = {
x: res[1].clientX - rect.left,
y: res[1].clientY - rect.top
};
this.drawOnCanvas(prevPos, currentPos);
});
}
But this isn't working - I get an error for the "takeUntil" code:
Argument of type '(a: any) => Observable<[Event, Event]>' is not
assignable to parameter of type 'Observable'
plnkr example of original code here:
https://embed.plnkr.co/QSvJxi/
For some reason your plnkr didn't work for me but I'll try my best to provide an answer. I think you should do 2 things here for starter. Try initializing your Observables so it's easier to call them and subscribe to them like so:
const mousedown$ = fromEvent(pauseButton, 'mousedown');
const mouseup$ = fromEvent(resumeButton, 'mouseup');
const mousemove$ = fromEvent(resumeButton, 'mousemove');
The second thing you should pipe your operators now with Rxjs 5 & 6, like so, And subscribe to all your events
mousedown$.pipe(
switchMap(res => {
mousemove$.pipe(//Whatever Operators and subscribitions to other events).subscribe(...)
}),
map(// Whatever you want back from your event)
).subscribe(...)
I refer to you the documentation links switchMap && takeUntil . As many syntaxes are changing in Rxjs don't be shy to brows the documentation, there is nothing better.
fromEvent
Now is already of type Observable. You don't need the chain it to an Observebal instead you can call it directly and affect it to a variable or better a const. Like below:
const source = fromEvent(document, 'click');
as for the import, you figured it right
import { fromEvent } from 'rxjs';
I think you are actually very close, I think you have your pipes too "deep" though - remember you can chain as many operators as you need together in a pipe, so your inner mouse-move-until-mouse-up switchmap should look more like this:
private captureEvents(canvasEl: HTMLCanvasElement) {
const obsMouseDown = fromEvent(canvasEl, 'mousedown').pipe(
switchMap((e) => {
return fromEvent(canvasEl, 'mousemove').pipe(
takeUntil(a => fromEvent(canvasEl, 'mouseup')),
pairwise()
));
}))
.subscribe((res: [MouseEvent, MouseEvent]) => {
// snip
});
}

Angular 5 - Event emitter (Property 'update' does not exist on type ....)

I've got a component that I want to update when a person's name changes by emitting an event. My problem is the code doesn't compile because of an error. This is my code
ApplicationFormComponent
#Output() nameChange = new EventEmitter();
closeAccordion(isComplete: string, accordionToClose: string, accordion: NgbAccordion) {
if (accordionToClose === 'personal-details-panel') {
this.applicationStatusFlags.personalDetailsStatus = (isComplete === 'true');
this.nameChange.emit({ personId: this.personId });
}
}
ApplicationFormComponent.html
<name-display
[personId]="personId"
[placeHolderText]="'Hello'"
(nameChange)="update($event)">
</name-display>
NameDisplayComponent
import { Component, Input, OnChanges, SimpleChanges } from '#angular/core';
import { PersonService } from "../../../service/person.service";
#Component({
selector: 'name-display',
templateUrl: './NameDisplay.component.html',
providers: [PersonService]
})
export class NameDisplayComponent implements OnChanges {
constructor(private readonly personService: PersonService) { }
#Input() personId;
#Input() placeHolderText: string = "";
forename: string = "";
ngOnChanges(changes: SimpleChanges): void {
if (changes["personId"]) {
this.personService.getPersonDetails(this.personId).subscribe((res: IPersonDetails) => {
this.forename = res.forenames;
});
}
};
update(personId: number) {
alert("update name");
this.personService.getPersonDetails(personId).subscribe((res: IPersonDetails) => {
this.forename = res.forenames;
});
}
}
My problem is basically when I use angular cli with the command ng server --aot, it doesn't compile because of this error:
ERROR in src\app\component\ApplicationForm\ApplicationForm.component.html(42,9): : Property 'update' does not exist on type 'ApplicationFormComponent'.
I've written a similar component that uses an event emitter which doesn't have this problem, so I'm stuck with how to fix the error.
Any ideas?
It is because you are passing $event to method.
(nameChange)="update($event)"
But it accepts number.
update(personId: number) {
alert("update name");
}
Please change the method as below.
update(event:any) {
const personId = event as number
alert("update name");
}

How to use pathlocationstrategy in angular 5 to set base href or APP_BASE_HREF?

Below is the code snippet:
import {
Router
} from "#angular/router";
import {
HttpClient
} from "#angular/common/http";
import {
environment
} from "../../environments/environment";
import {
Location,
LocationStrategy,
PathLocationStrategy
} from '#angular/common';
#Injectable()
export class CommonServicesService {
PathLocation: Location;
referralCode: any = localStorage.getItem('referenceCode');
constructor(
location: Location,
) {
this.PathLocation = location;
}
redirectAfterSuccessfulLogin() {
if (localStorage.getItem("redirectUrl")) {
let url = localStorage.getItem("redirectUrl");
localStorage.removeItem("redirectUrl");
this.PathLocation.prepareExternalUrl("'/'+this.referralCode"); //is this the correct way?
console.log(this.PathLocation);
this.router.navigate([url]);
} else {
this.PathLocation.prepareExternalUrl("'/'+this.referralCode");
console.log(this.PathLocation);
this.router.navigate(["/"]);
}
}
}
you can do some thing like that :
Create a baseUrl function that takes code as a parameter.
Call that function according to the condition after login,this will
gives you the updated URL
like this:
getBaseUrl = function(code){
return `localhost:3000/${code}`
}
now you can use it as :
getBaseURl(1234)
it returns : "localhost:3000/1234"
now you can add further path after this URL.
OR
you can further use same function for both the URL like this :
getBaseUrl = function(code){
if(code == 0000) return localhost:3000
else return `localhost:3000/${code}`
}
now whenever you are calling the function you have to pass 0000 for non-login condition Base Url and 4 digit code to get the after login base URL
getBaseURl(1234) // for login one
getBaseURl(0000) // for non-login one