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

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

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;
}
}

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");
}

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

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

Call a Component method in Directive Angular 2

I have a directive which is supposed to call a method from component, but it fails doing this, what should be wrong ?
Here I will put the Directive, and a fragment of Component for understanding the problem..
Directive
import { Directive, EventEmitter, HostListener, Input, OnInit, Output } from '#angular/core';
import { GridComponent } from '../components/grid/grid.component';
import { Cell } from '../cell';
import { KEY_CODE } from '../keyCode.enum';
#Directive({
selector: '[appControl]',
})
export class GridDirective {
constructor(public gridComponent: GridComponent) {}
#HostListener('window:keydown', ['$event'])
handleKeyDown(event: KeyboardEvent) {
console.log(event.key);
const ITEMS = JSON.parse(localStorage.getItem('Grid'));
let key;
switch (event.key) {
case 'ArrowLeft': key = KEY_CODE.LEFT_ARROW;
break;
case 'ArrowUp': key = KEY_CODE.UP_ARROW;
break;
case 'ArrowRight': key = KEY_CODE.RIGHT_ARROW;
break;
case 'ArrowDown': key = KEY_CODE.DOWN_ARROW;
break;
}
this.gridComponent.move(ITEMS, key);
}
}
And here's the component method which it is supposed to call
move(array: Cell[][], key: KEY_CODE) {
localStorage.setItem('lastMove', JSON.stringify(key));
const DATA = this.gridService.move(array, this.score, key);
array = DATA.dataSheet;
this.score = DATA.rating;
this.best = this.gridService.scoreSender(this.score, this.best);
localStorage.setItem('Grid', JSON.stringify(array));
}
it's a wrong way to use a component as a service,
you should pass the "this" value from html and then assign it to gridComponent variable and for passing parameter to directive you can use input decorator
gridComponent :GridComponent;
#Input('appControl') set setGridComponent(gridComponent) {
this.gridComponent = gridComponent;
}
/// in html use property binding to pass the value to it
[appControl]="this"

Access an element's Binding

I have a custom attribute that processes authentication data and does some fun stuff based on the instructions.
<div auth="disabled: abc; show: xyz; highlight: 123">
There's a lot of complicated, delicate stuff happening in here and it makes sense to keep it separate from semantic bindings like disabled.bind. However, some elements will have application-logic level bindings as well.
<div auth="disabled.bind: canEdit" disabled.bind="!editing">
Under the covers, my auth attribute looks at the logged in user, determines if the user has the correct permissions, and takes the correct action based on the result.
disabledChanged(value) {
const isDisabled = this.checkPermissions(value);
if (isDisabled) {
this.element.disabled = true;
}
}
This result needs to override other bindings, which may or may not exist. Ideally, I'd like to look for an existing Binding and override it ala binding behaviors.
constructor(element) {
const bindings = this.getBindings(element); // What is the getBindings() function?
const method = bindings['disabled']
if (method) {
bindings['disabled'] = () => this.checkPermission(this.value) && method();
}
}
The question is what is this getBindings(element) function? How can I access arbitrary bindings on an element?
Edit: Gist here: https://gist.run/?id=4f2879410506c7da3b9354af3bcf2fa1
The disabled attribute is just an element attribute, so you can simply use the built in APIs to do this. Check out a runnable example here: https://gist.run/?id=b7fef34ea5871dcf1a23bae4afaa9dde
Using setAttribute and removeAttribute (since the disabled attribute does not really have a value, its mere existence causes the element to be disabled), is all that needs to happen:
import {inject} from 'aurelia-framework';
#inject(Element)
export class AuthCustomAttribute {
constructor(element) {
this.el = element;
}
attached() {
let val = false;
setInterval(() => {
if(this.val) {
this.el.setAttribute('disabled', 'disabled');
} else {
this.el.removeAttribute('disabled');
}
this.val = !this.val;
}, 1000);
}
}
NEW RESPONSE BELOW
You need to work directly with the binding engine. A runnable gist is located here: https://gist.run/?id=b7fef34ea5871dcf1a23bae4afaa9dde
Basically, you need to get the original binding expression, cache it, and then replace it (if auth === false) with a binding expression of true. Then you need to unbind and rebind the binding expression:
import {inject} from 'aurelia-framework';
import {Parser} from 'aurelia-binding';
#inject(Element, Parser)
export class AuthCustomAttribute {
constructor(element, parser) {
this.el = element;
this.parser = parser;
}
created(owningView) {
this.disabledBinding = owningView.bindings.find( b => b.target === this.el && b.targetProperty === 'disabled');
if( this.disabledBinding ) {
this.disabledBinding.originalSourceExpression = this.disabledBinding.sourceExpression;
// this expression will always evaluate to true
this.expression = this.parser.parse('true');
}
}
bind() {
// for some reason if I don't do this, then valueChanged is getting called before created
this.valueChanged();
}
unbind() {
if(this.disabledBinding) {
this.disabledBinding.sourceExpression = this.disabledBinding.originalSourceExpression;
this.disabledBinding.originalSourceExpression = null;
this.rebind();
this.disabledBinding = null;
}
}
valueChanged() {
if(this.disabledBinding ) {
if( this.value === true ) {
this.disabledBinding.sourceExpression = this.disabledBinding.originalSourceExpression;
} else {
this.disabledBinding.sourceExpression = this.expression;
}
this.rebind();
} else {
if( this.value === true ) {
this.el.removeAttribute('disabled');
} else {
this.el.setAttribute('disabled', 'disabled');
}
}
}
rebind() {
const source = this.disabledBinding.source;
this.disabledBinding.unbind();
this.disabledBinding.bind(source);
}
}
It is important that the attribute clean up after itself, as I do in the unbind callback. I'll be honest that I'm not sure that the call to rebind is actually necessary in the unbind, but it's there for completeness.