Get absolute app URL in Angular 2 - javascript

Is there a way to get the absolute URL of my Angular 2 app, including the <base href="">?
I need to send redirect URLs to my rest API for Twitter authentication. Twitter will get these and redirect the user to them upon successful authentication.
So I need something like this but with a dynamic absoluteBaseUrl dynamical (depends on environment):
// How do I avoid hardcoding this?
let absoluteBaseUrl = "https://example.com/app";
let redirectUrl = absoluteBaseUrl + "/authsuccess";
// authUrl will look something like: http://example.com/api/auth?redirect=http%3A%2F%2Fexample.com%2Fapp%2Fauthsuccess
let authUrl = ComposeTwitterAuthUrl(redirectUrl);
// Redirect the user to the Twitter auth screen
window.location.href= authUrl;

You can try something like this, Create file appConfig.service.ts in root component.
import { Injectable } from "#angular/core";
interface EndPoint {
baseUrl: string;
requiresAuthentication: boolean;
}
interface ResourceLocator {
[key: string]: EndPoint;
}
interface XResourceLocator {
x: ResourceLocator;
}
interface YResourceLocator {
y: ResourceLocator;
}
#Injectable()
export class APIConfigurations implements XResourceLocator, YResourceLocator {
private _config;
constructor() {
this._config = require("./apiConfig.json");
}
public get x(): ResourceLocator {
return this.clone(this._config.x);
}
public get y(): ResourceLocator {
return this.clone(this._config.y);
}
private clone<T>(value: T): T {
return JSON.parse(JSON.stringify(value));
}
}
and then define your all urls in apiConfig.json:
{
"x": {
"apiary": {
"baseUrl": "https://private-xyz.apiary-mock.com/test/",
"requiresAuthentication": false
},
"local": {
"baseUrl": "http://localhost:8080/test/",
"requiresAuthentication": false
}
},
"y": {
"apiary": {
"baseUrl": "https://private-xyz.apiary-mock.com/test1/",
"requiresAuthentication": false
},
"local": {
"baseUrl": "http://localhost:8080/test1/",
"requiresAuthentication": false
}
}
}
So you can define any baseUrl based on the environment here.
And use this in your any service.ts file:
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import {APIConfigurations} from "../app/apiconfig.service";
import 'rxjs/Rx';
#Injectable()
export class DashboardService {
private _requestOptions: RequestOptions;
private _baseUrl: string;
constructor(private http: Http, apiConfigs: APIConfigurations) {
const headers = new Headers({ 'Accept': 'application/json' });
const config = apiConfigs.x["local"];
this._baseUrl = config.baseUrl;
this._requestOptions = new RequestOptions({ headers: headers, withCredentials: config.requiresAuthentication });
}
/**
* [getUsers list of users]
*/
getUsers() {
return this.http.get(this.resolveUrl(`users`), this._requestOptions)
.map(res => res.json())
.catch(this.handleError);
}
private handleError(error: Response) {
return Observable.throw(error.json().error || 'Server error');
}
public resolveUrl(path: string): string {
var normalized = this._baseUrl.endsWith("/")
? this._baseUrl
: this._baseUrl + "/";
return normalized + path;
}
}
Hope this will help you.

Related

How to display data from client service in ngx-wheel Angular

I want to display the ngx-wheel using api but I'm having trouble displaying the data.
Here my Service :
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class RestServices {
restEndpoint:string = 'https://gorest.co.in/public/v2/users'
constructor(
private httpClient: HttpClient
) { }
async getServiceId() {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
return this.httpClient.get<any[]>(this.restEndpoint, httpOptions)
}
Here my Component :
private subscription: Subscription | undefined;
items: any = []
ngOnInit(): void {
this.subscription = this._restService.getServices()
.subscribe((res:any)=>{
let item = res
this.items = item.map((v:any) => ({
text: v.name,
id: v.id,
textFillStyle: "white",
textFontSize: "16"
}));
})
}
ngOnDestroy(): void {
this.subscription?.unsubscribe()
}
Here for html
<ngx-wheel #wheel [width]='350' [height]='350' [spinDuration]='8' [disableSpinOnClick]='true' [items]='items'
[innerRadius]='10' [spinAmount]='10' [textOrientation]='textOrientation' [textAlignment]='textAlignment'
pointerStrokeColor='black' pointerFillColor='white' [idToLandOn]='idToLandOn' (onSpinStart)='before()'
(onSpinComplete)='after()'>
I hope to find the answer here. Thank you
First, you don't need await, async and ,toPromise()... remove them and simply return
return this.httpClient.get<any[]>(this.restEndpoint, httpOptions);
inside your component you should use your constructor only for simple data initialization: if you have to consume a rest api it is a better approach to move that piece of code inside the ngOnInit method:
items: any[] = []
constructor(private restService: RestService){}//dependency injection
ngOnInit(): void {
this.restService.getServiceId().subscribe(response => {
console.log('response success: ', response);
this.items = response; //this may change a little based on your api
console.log('items: ', this.items);
}, errorLog => {
console.log('response error: ', errorLog)
});
}
The above solution is valid, you can enrich it by adding a *ngIf="isLoaded" on your html element and set to true the isLoaded INSIDE subscribe method. but if you prefer you can do the following in the component.ts
items$: Observable<any> = EMPTY;
constructor(private restService: RestService){}//dependency injection
ngOnInit(): void {
this.items$ = this.restService.getServiceId();
}
then, in your html it would change to the following:
<ngx-wheel #wheel *ngIf="items$ | async as items" [width]='350' [height]='350' [spinDuration]='8' [disableSpinOnClick]='true' [items]='items'
[innerRadius]='10' [spinAmount]='10' [textOrientation]='textOrientation' [textAlignment]='textAlignment'
pointerStrokeColor='black' pointerFillColor='white' [idToLandOn]='idToLandOn' (onSpinStart)='before()'
(onSpinComplete)='after()'>

Angular PayPal Processing, Childcomponent and Lifecycle

I am currently working on the PayPal integration in my own shop (Angular Frontend, dotnet core WebApi backend) and apparently I have a problem with the life cycle between the main component (CheckoutProcessComponent) and the child component (PaymentPayPalComponent) and with the use of the necessary PayPal javascript.
Basically the complete PayPal workflow works as long as I use static variables. And this is exactly where my problem starts.
CheckoutProcessComponent.ts
import { Component, OnInit } from '#angular/core';
import { CartService } from 'src/app/_services/shop/cart.service';
import { ISubscriptionCollection } from 'src/app/_models/misc/ISubscriptionCollection';
import { serialUnsubscriber } from 'src/app/shared/utility.module';
import { CheckoutService } from 'src/app/_services/checkout/checkout.service';
import { ICheckoutOrderData } from 'src/app/_models/shop/ICheckoutOrderData';
import { IOrderProcessSummary } from 'src/app/_models/shop/IOrderProcessSummary';
#Component({
selector: 'app-checkout-process',
templateUrl: './checkout-process.component.html',
styleUrls: ['./checkout-process.component.css']
})
export class CheckoutProcessComponent implements OnInit {
subscriptions: ISubscriptionCollection = {};
checkoutOrderData = {} as ICheckoutOrderData;
orderSummaryFromServer: IOrderProcessSummary;
orderCreated: boolean = false;
constructor(public checkoutService: CheckoutService, public cartService: CartService) { }
ngOnInit() {
this.checkoutOrderData.Order = this.checkoutService.orderData;
this.checkoutOrderData.Cart = this.cartService.shoppingCart;
// Create Order
this.subscriptions['createOrder'] = this.checkoutService.createOrder(this.checkoutOrderData)
.subscribe((res: IOrderProcessSummary) => {
this.checkoutService.checkoutSummary = res;
this.orderSummaryFromServer = res;
console.log('Order created: ' + res);
}, error => {
console.log('Error');
});
}
ngOnDestroy(): void {
serialUnsubscriber(...Object.values(this.subscriptions));
}
nextStep(step: number) {
this.checkoutService.updateCheckoutStep(step);
}
...
}
CheckoutProcessComponent.html
<app-payment-paypal [orderSummary]="orderSummaryFromServer" *ngIf="checkoutService.orderData.paymentMethod === 'PM_PAYPAL'"></app-payment-paypal>
<app-payment-stripe *ngIf="checkoutService.orderData.paymentMethod === 'PM_STRIPE'"></app-payment-stripe>
<app-payment-moneytransfer *ngIf="checkoutService.orderData.paymentMethod === 'PM_TRANSFER'"></app-payment-moneytransfer>
PaymentPayPalComponent.ts
import { Component, OnInit, AfterViewChecked, Input } from '#angular/core';
import { environment } from 'src/environments/environment';
import { IOrderProcessSummary } from 'src/app/_models/shop/IOrderProcessSummary';
import { CheckoutService } from 'src/app/_services/checkout/checkout.service';
declare let paypal: any;
#Component({
selector: 'app-payment-paypal',
templateUrl: './payment-paypal.component.html',
styleUrls: ['./payment-paypal.component.css']
})
export class PaymentPaypalComponent implements OnInit, AfterViewChecked {
#Input() orderSummary: IOrderProcessSummary;
paypalClientId = environment.paymentPayPal.clientId;
addScript: boolean = false;
scriptTagElement: HTMLScriptElement;
constructor(private checkoutService: CheckoutService) { }
ngOnInit() {
}
ngOnDestroy(): void {
if (this.scriptTagElement) {
document.body.removeChild(this.scriptTagElement);
}
}
ngAfterViewChecked(): void {
if (!this.addScript) {
this.addPayPalScript().then(() => {
paypal.Buttons({
createOrder: function() {
return fetch('https://localhost:5021/api/payments/paypal-create-order', {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
orderId: 1234
})
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.id; // Use the same key name for order ID on the client and server
});
},
onApprove: function(data, actions) {
console.log('onApprove - transaction was approved, but not authorized', data, actions);
actions.order.get().then(details => {
console.log('onApprove - you can get full order details inside onApprove: ', details);
});
return fetch('https://localhost:5021/api/payments/paypal-capture-order', {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
token: data.orderID,
payerID: data.payerID,
})
});
},
onClientAuthorization: (data) => {
console.log('onClientAuthorization - you should probably inform your server about completed transaction at this point', data);
// this.showSuccess = true;
},
onCancel: (data, actions) => {
console.log('OnCancel', data, actions);
// this.showCancel = true;
},
onError: err => {
console.log('OnError', err);
// this.showError = true;
}
}).render('#paypal-button-container');
})
}
}
addPayPalScript() {
return new Promise((resolve, reject) => {
this.scriptTagElement = document.createElement('script');
this.scriptTagElement.src = 'https://www.paypal.com/sdk/js?currency=EUR&client-id=' + this.paypalClientId;
this.scriptTagElement.onload = resolve;
document.body.appendChild(this.scriptTagElement);
this.addScript = true;
})
}
}
PaymentPayPalComponent.html
<div class="text-center" id="paypal-button-container"></div>
The processing flow is as follows:
CheckoutProcessComponent > creates the order on the server with the cart data and stores the order in the database (general function, non PayPal related)
The result from 1. is of IOrderProcessSummary which holds the order Id and the total of the order
Depending on the selected payment method, the corresponding payment-Child Component will be displayed. In this case the PaymentPayPalComponent.
Then I use the PayPal-feature "CreatePayPalOrderOnServer" which uses the PayPal Api in my backend to create an order on the PayPal server. But for that I need the specific orderId because I need to fill the PayPal-Order data with the specific order data from my system (in the example I have a fixed 1234 order Id).
For step 4. I tried it with Input()-parameter and with injecting the CheckoutService to the PaymentPayPalComponent but I am not able to work with any kind of dynamic variables within the PayPal-Button-Function (JavaScript). In the example I need to change the "orderId: 1234" with a value from the Input() orderSummary or the same value from the CheckoutService, but both of them stay undefined.
The PayPal-Javascript is loaded correctly and the PayPal-Buttons show up and work as intended technically.
How do I bring my dynamic data into the PaymentPayPalComponent and into the PayPal.Buttons-Function?
Thanks for your tips!

Pass value to extends plugin ng2 smart table

I've checked the document and source code for pagination implementation (advanced-example-server.component.ts).
And found that the ServerDataSource it used had only implemented pagination via HTTP GET (_sort, _limit, _page, etc parameters expose in URL)..... as my current project worked on required to use POST to send front-end parameters to back-end Restful APIs,
using extends to HTTP post call implement, I don't know how to add the extra parameters in pagination request. I Need To pass the request_server to extendsplugin.ts
import { Observable } from 'rxjs/internal/Observable';
import { ServerDataSource } from 'ng2-smart-table';
export class PostServerDataSource extends ServerDataSource {
protected requestElements(): Observable<any> {
let httpParams = this.createRequesParams();
return this.http.post(this.conf.endPoint, request_server, { observe: 'response' });
}
}
anotherComponent.ts
swiftListTable() {
const request_server = { "userType": this.currentUser.role, "authName": this.currentUser.username }
this.source = new PostServerDataSource(this.http,{endPoint: this.service.apiURL + 'swift/pagination', dataKey: 'content', pagerLimitKey:"_limit",
pagerPageKey:"_page",
sortDirKey: "pageable",
sortFieldKey: "pageable",
totalKey:'totalElements'});
}
There are two ways you can handle it,
one way is attaching the params in query string and append to url like,
this.service.apiURL + 'swift/pagination?param1=p&param2=q'
Other way could be handling it in requestElements and swiftListTable functions like below.
swiftListTable() {
const request_server = {
"userType": this.currentUser.role,
"authName": this.currentUser.username
}
this.source = new PostServerDataSource(http,
{ endPoint: url, dataKey: 'content', pagerLimitKey:'_limit'}, request_server);
export class PostServerDataSource extends ServerDataSource {
params: any;
constructor(http: HttpClient, config: any, params?: any) {
super(http, config);
this.params = params;
}
protected requestElements(): Observable<any> {
let httpParams = this.createRequesParams();
if (this.params) {
let keys = Object.keys(this.params);
keys.forEach((key) => {
httpParams = httpParams.set(key, this.params[key]);
});
}
return this.http.post(this.conf.endPoint, httpParams, { observe: 'response' });
}
}

Converting JSON into XML Angular 7

EDIT: This doesn't work with the xml2js npm package since I want to do the opposite, convert json to xml, not the other way around.
I have my API using JSON data format but I also have to save the object that I updated in a text file in an XML format, since this other application that we communicate with only accepts XML format.
I have my service
shipment.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import * as x2js from 'xml2js';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class ShipmentService {
baseUrl = "http://localhost:5000/api/shipments/"
constructor(
private http: HttpClient
) {}
getShipments() {
return this.http.get(this.baseUrl);
}
getShipment(id) {
return this.http.get(this.baseUrl + id);
}
updateShipment(id: number, shipment) {
return this.http.put(this.baseUrl + id, shipment);
}
}
And tracker.component.ts
import { Component, OnInit } from '#angular/core';
import { ShipmentService } from 'src/app/services/shipment.service';
import { NgbModal } from '#ng-bootstrap/ng-bootstrap';
import { ShipmentModalComponent } from '../shipment-modal/shipment-modal.component';
import { Router } from '#angular/router';
import { NgxSpinnerService} from 'ngx-spinner';
var convert = require('xml-js');
#Component({
selector: 'app-tracker',
templateUrl: './tracker.component.html',
styleUrls: ['./tracker.component.css']
})
export class TrackerComponent implements OnInit {
shipments:any = [];
shipment:any = {};
modal_on:boolean = false;
modalcontent:any;
closeResult = '';
reference: string;
constructor(
private shipmentService: ShipmentService,
private modalService: NgbModal,
private spinner: NgxSpinnerService,
private router: Router
) {}
ngOnInit() {
this.getShipments();
}
convertToXML(json) {
var options = {compact: true};
var result = convert.json2xml(json, options);
console.log(result);
}
getShipments() {
this.spinner.show(undefined,{
type: "square-spin",
size: "medium",
bdColor: 'rgba(0,0,0,.5)',
color: "rgb(5, 5, 80)",
fullScreen: false
});
this.shipmentService.getShipments().subscribe(response => {
this.shipments = response;
this.spinner.hide();
this.convertToXML(response);
console.log(response);
}, error => {
console.log(error);
});
}
}
So I tried to use x2js and other xml2json libraries but I had no success converting the JSON object into an XML object or string for that matter.
So I used js2xmlparser npm package and I wrote the following method on my service.ts file and component.ts file as follows:
service.ts
import * as JsonToXML from 'js2xmlparser';
convertXML(obj) {
let options = {
format: {
doubleQuotes: true
},
declaration: {
include: false
}
}
return JsonToXML.parse("UniversalEvent", obj, options);
}
and in my component.ts file i wrote the following method:
openModal(content, shipment) {
// this.modal_on = true;
let new_obj = {};
this.modalcontent = shipment;
this.modalService.open(content, {ariaLabelledBy: 'modal-basic-title'});
new_obj = this.addXmlAttr(new_obj);
this.xmlShipment = this.shipmentService.convertXML(new_obj);
console.log(this.xmlShipment)
console.log(this.modalcontent);
}
addXmlAttr(obj) {
obj = {
"#": {
xmlns: "http://www.cargowise.com/Schema/Universal/2011/11",
version:"1.0"
},
Event: {
DataContext: {
DataTargetCollection: {
DataTarget: {
Type: "ForwardingShipment",
Key: this.modalcontent.vortex_Reference
}
}
},
EventTime: this.modalcontent.actual_Pickup,
EventType: "PCF",
AdditionalFieldsToUpdateCollection: {
AdditionalFieldsToUpdate: {
Type: "ForwardingShipment.DocsAndCartage.JP_PickupCartageCompleted",
Value: this.modalcontent.actual_Pickup
}
}
}
}
return obj;
}
As somebody suggested, I edited the json object to my specifications and then parsed it to XML and the converted object looks like so:
<UniversalEvent xmlns="http://exampleurl.com/Schema/Example/2011/11" version="1.0">
<Event>
<DataContext>
<DataTargetCollection>
<DataTarget>
<Type>ForwardingShipment</Type>
<Key>123456</Key>
</DataTarget>
</DataTargetCollection>
</DataContext>
<EventTime>2019-05-22T00:00:00</EventTime>
<EventType>PCF</EventType>
<AdditionalFieldsToUpdateCollection>
<AdditionalFieldsToUpdate>
<Type>ForwardingShipment.DocsAndCartage.JP_PickupCartageCompleted</Type>
<Value>2019-05-22T00:00:00</Value>
</AdditionalFieldsToUpdate>
</AdditionalFieldsToUpdateCollection>
</Event>
</UniversalEvent>
install npm i js2xmlparser
import * as JsonToXML from "js2xmlparser";
console.log(JsonToXML.parse("person", this.obj));
Here this.obj is your JSON object
Stackblitz Example

Merge objects in Angular 2 [duplicate]

This question already has answers here:
How to return value from an asynchronous callback function? [duplicate]
(3 answers)
Closed 6 years ago.
Im having trouble merging 3 objects array. My objective is to merge 3 arrays to one and send HTTP POST to the server.
I have tried using concat but Im getting this error:
EXCEPTION: Error in ./PreviewEmailPage class PreviewEmailPage_Host - inline template:0:0 caused by: Cannot read property 'concat' of undefined
These are my codes:
import { Component } from '#angular/core';
import { NavParams, NavController, LoadingController } from 'ionic-angular';
import { Validators, FormGroup, FormControl } from '#angular/forms';
import { Http, Headers} from '#angular/http';
import 'rxjs/add/operator/map';
import { Storage } from '#ionic/storage';
#Component({
selector: 'preview-email-page',
templateUrl: 'preview-email.html',
})
export class PreviewEmailPage {
headers: Headers;
loading: any;
url: string;
preview: any[];
FirstArray: any[];
SecondArray: any[];
ThirdArray: any[];
PostData: any[];
constructor(
public nav: NavController,
public navParams: NavParams,
public loadingCtrl: LoadingController,
public localStorage: Storage,
public http: Http,
) {
this.localStorage.get('FirstArray').then((value) => {
this.FirstArray= value;
})
this.localStorage.get('SecondArray').then((value) => {
this.SecondArray= value;
})
this.localStorage.get('ThirdArray').then((value) => {
this.ThirdArray= value;
})
this.PostData = this.FirstArray.concat(this.SecondArray);
this.PostData = this.PostData.concat(this.ThirdArray);
this.loading = this.loadingCtrl.create();
}
ionViewWillEnter(){
this.headers = new Headers();
this.headers.append("Content-Type", "application/x-www-form-urlencoded");
console.log(this.PostData);
this.getPreview();
}
getPreview(){
this.loading.present();
this.url = 'https://domain.com/REST/getpreview.php';
this.http.post(this.url, this.PostData, {headers: this.headers}).map(res => res.json()).subscribe(res => {
console.log(res);
this.preview = res;
}, err => {
console.log('error');
})
}
}
Since this.localStorage.get is an async operation your this.FirstArray is not defined untill the then is executed.
What you can do is run them all in parallel with Promise.all:
Promise.all([this.localStorage.get('FirstArray'), this.localStorage.get('SecondArray'), this.localStorage.get('ThirdArray')]).then(values => {
this.FirstArray= values[0];
this.SecondArray= values[1];
this.ThirdArray= values[2];
this.PostData = this.FirstArray.concat(this.SecondArray);
this.PostData = this.PostData.concat(this.ThirdArray);
});

Categories