I'm looking for help for the implementation of Revolut #revolut/checkout npm package with Angular 7
declared the main script at angular.json:
"scripts": [
"node_modules/#revolut/checkout/cjs/index.js"
]
Put the indicated script at the index.html head:
<script>!function(e,o,t){e[t]=function(n,r){var c={sandbox:"https://sandbox-merchant.revolut.com/embed.js",prod:"https://merchant.revolut.com/embed.js",dev:"https://merchant.revolut.codes/embed.js"},d=o.createElement("script");d.id="revolut-checkout",d.src=c[r]||c.prod,d.async=!0,o.head.appendChild(d);var s={then:function(r,c){d.onload=function(){r(e[t](n))},d.onerror=function(){o.head.removeChild(d),c&&c(new Error(t+" is failed to load"))}}};return"function"==typeof Promise?Promise.resolve(s):s}}(window,document,"RevolutCheckout");</script>
my checkout component:
import { Component, Input, OnInit } from '#angular/core';
import { Subject } from 'rxjs';
declare let RevolutCheckout: any;
#Component({
selector: 'app-revolutwidget',
templateUrl: './revolutwidget.component.html',
styleUrls: ['./revolutwidget.component.scss']
})
export class RevolutwidgetComponent implements OnInit {
#Input() payOrder : any;
#Input() billingData : any;
revolutCheckout = RevolutCheckout;
checkoutResult$ = new Subject<string>();
constructor() { }
async ngOnInit() {
try {
console.log(this.billingData)
this.checkoutResult$.subscribe(res => {
console.log(res);
if(res === 'success'){
this.onSuccess();
} else if(res === 'error'){
this.onError();
} else if (res === 'cancel'){
this.onCancel();
}
})
this.revolut()
}catch(err){
console.log(err);
}
}
async revolut(){
const billingData = this.billingData
const checkoutResult = this.checkoutResult$;
this.revolutCheckout(this.payOrder.payOrderId,this.payOrder.mode).then(function (instance) {
instance.payWithPopup({
onSuccess() {
checkoutResult.next('success')
},
onError(){
checkoutResult.next('error')
},
onCancel(){
checkoutResult.next('cancel')
},
locale: "es",
...billingData
})
})
}
onSuccess(){
console.log('successs');
}
onError(){
console.log('error');
}
onCancel(){
console.log('cancel');
}
}
The widget is working but I'm getting this (non critical?) error after compilation at the browser's console before the app ends loading:
index.js:2 Uncaught ReferenceError: exports is not defined
at index.js:2:1
where index.js is node_modules/#revolut/checkout/cjs/index.js
I didn't found any example about implementing Revolut with Angular anywhere, so any help would be appreciated.
Thank you
Related
can any one please tell me why I can not loop through this array?
In ngOnInit, everything works fine. I got an array that I successfully display in the template.
But in ngAfterViewInit, console.log show the array but when looping through with "for of" or "forEach", nothing works.
import { JobsService } from '../jobs.service';
import {Job} from '../models/Job';
#Component({
selector: 'app-job',
templateUrl: 'job.component.html'
})
export class JobComponent implements OnInit, AfterViewInit {
title = 'Job';
jobs: Job[] = [];
InProcess = '';
CurrentPartner = '';
ShowProcess = false;
sended = '';
constructor(private jobsService: JobsService) {
}
ngOnInit() {
this.jobs = this.jobsService.getJobs();
}
ngAfterViewInit() {
console.log(this.jobs); // Show the array
// Nothing happened when looping through the array
this.jobs.forEach((oneJob) => {
console.log(oneJob);
});
}
}
Screenshot of the console in Google Chrome
The content of the service:
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import {Job} from './models/Job';
interface IJob {
message: string;
jobs: any[];
}
#Injectable({
providedIn: 'root'
})
export class JobsService {
constructor(private httpClient: HttpClient) { }
private REST_API_SERVER = 'http://localhost:8080/myband/api/getjobs.php';
private REST_API_SERVER_SEND = 'http://localhost:8080/myband/api/sendjob.php';
jobList: Job[] = [];
errorMessage: any;
message: string;
static handleError(err: HttpErrorResponse) {
let errorMessage = '';
if (err.error instanceof ErrorEvent) {
errorMessage = `An error occurred: ${err.error.message}`;
} else {
errorMessage = `Server returned code: ${err.status}, error message is: ${err.message}`;
}
console.error(errorMessage);
return throwError(errorMessage);
}
public getJobs() {
this.requestJobs().subscribe(
iJob => {
this.message = iJob.message;
for (const job of iJob.jobs) {
const oneJob: Job = new Job(job);
this.jobList.push(oneJob);
}
},
error => this.errorMessage = error as any
);
return this.jobList;
}
public requestJobs(): Observable<IJob> {
return this.httpClient.get<IJob>(this.REST_API_SERVER).pipe(
catchError(JobsService.handleError)
);
}
}
The first thing I want to say to you is about isolation of responsibilities.
Your service must have just one job: provider one way to access your data; It means your logic inside getJobs() method could be done in your component.
export class JobsService {
constructor(
private httpClient: HttpClient,
) {}
private REST_API_SERVER = 'http://localhost:8080/myband/api/getjobs.php';
public requestJobs(): Observable<IJob> {
return this.httpClient.get<IJob>(this.REST_API_SERVER);
}
}
Now, you can handler your data in your component.
import { JobsService } from '../jobs.service';
#Component({
selector: 'app-job',
templateUrl: 'job.component.html'
})
export class JobComponent implements OnInit, AfterViewInit {
title = 'Job';
jobs$;
InProcess = '';
CurrentPartner = '';
ShowProcess = false;
sended = '';
constructor(private jobsService: JobsService) {
}
ngOnInit() {
this.jobs$ = this.jobsService.requestJobs();
}
ngAfterViewInit() {
this.jobs$
.pipe(
map(() => {}), // change your data here
catchError(() => {}) // handler your error here;
)
.subscribe(
() => {} // have access to your final data here.
);
}
}
Things to know:
You can remove the subscribe() execution and use the async pipe in your template;
The use of the operator map in pipe() is optional, you can handler your final data directly from your first callback subscribe().
You can convert your Observable to Promise using toPromise() method in one observable. Don't forgot async / await in your ngAfterViewInit.
Let me know if there is something I can help.
Try:
Object.keys(this.jobs).forEach(job => {
console.log(this.jobs[job]);
});
Try to assign an iterator function with below part replacement by this code:
// Nothing happened when looping through the array
this.jobs.forEach(oneJob, function(value, key) {
console.log(key + ': ' + value);
});
Usage of forEach in AngularJS:
For documentation try to check AngularJS forEach Docs
Syntax:
someIterable.forEach(object, iterator, [context])
Please check below example
class Job {
id: any;
status: any;
constructor(obj: any) {
this.id = obj.id;
this.status = obj.status;
}
}
let arr = [
{
id: 1,
status: "job"
}, {
id: 2,
status: "job2"
}
];
let newArr: any = [];
arr.forEach(a => {
let obj: Job = new Job(a);
newArr.push(obj);
})
console.log(newArr);
newArr.forEach((a: any) => {
console.log(a);
})
Hii all I am trying to post data to json server using post method , but unfortunately I have erros, my app have buttons follow, likes etc , I want when user clicks follow numbers increase and saved to the json file , so now when user clicks button I get the following error :
Note: am using fakes json server : Fake Json server
Error: Insert failed, duplicate id
at Function.insert (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash-id\src\index.js:49:18)
at C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:4374:28
at arrayReduce (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:683:21)
at baseWrapperValue (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:4373:14)
at LodashWrapper.wrapperValue (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:9052:14)
at create (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\lib\server\router\plural.js:221:52)
at Layer.handle [as handle_request] (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\route.js:137:13)
at next (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\route.js:131:14)
at Route.dispatch (C:\Users\jelly\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\route.js:112:3)
POST /statuses 500 13.873 ms - -
Here is service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import {Status } from '../model/statuses.model';
import { Comment } from '../model/comments.model';
#Injectable({
providedIn: 'root'
})
export class UserService {
status: Status[];
constructor(private http: HttpClient) { }
statusUrl = 'http://localhost:3000/statuses';
commentsUrl = 'http://localhost:3000/comments';
getStatuses() {
return this.http.get<Status[]>(this.statusUrl);
}
addStatus(status: Status) {
return this.http.post(this.statusUrl, status);
}
addComments(comment: Comment) {
return this.http.post(this.commentsUrl, comment);
}
}
here is ts file :
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { UserService } from '../service/user.service';
import { Status } from '../model/statuses.model';
import { Comment } from '../model/comments.model';
import {FormBuilder, FormGroup, Validators} from '#angular/forms';
#Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
styleUrls: ['./user-profile.component.scss']
})
export class UserProfileComponent implements OnInit {
status: Status[];
comment: Comment[];
constructor(private formBuilder: FormBuilder, private http: HttpClient, private userService: UserService) { }
addForm: FormGroup;
ngOnInit() {
this.addForm = this.formBuilder.group({
id: [],
name: ['', Validators.required],
city: ['', Validators.required],
description: ['', Validators.required],
});
this.userService.getStatuses()
.subscribe( data => {
this.status = data;
console.log(data);
console.log(this.status);
});
}
addComments() {
this.userService.addComments(this.addForm.value)
.subscribe(data => {
this.comment.push(this.addForm.value);
});
}
followButtonClick(statusId) {
const statusToUpdate = this.status.filter(status => status.id === statusId)[0];
statusToUpdate.followers++;
statusToUpdate.following++;
this.persistStatus(statusToUpdate);
}
likesButtonClick(statusId) {
const statusToUpdate = this.status.filter(status => status.id === statusId)[0];
statusToUpdate.like++;
this.persistStatus(statusToUpdate);
}
persistStatus(status) {
this.userService.addStatus(status)
.subscribe(data => {
this.status = status;
});
}
}
Here is json file :
{
"statuses": [
{
"id": 1,
"statusId": 20,
"likes": 121,
"following": 723,
"followers": 4433
}
]
}
Here is model
export class Status {
id: number;
statusId: number;
like: number;
following: number;
followers: number;
}
what am I doing wrong in my code ????
From documentation of the fake json-server you are using,:
Id values are not mutable. Any id value in the body of your PUT or
PATCH request will be ignored. Only a value set in a POST request will
be respected, but only if not already taken.
You are trying to update an existing status, so you need a put call not post. Something like this:
updateStatus(status: Status) {
return this.http.put(this.statusUrl + '/' + status.id, status);
}
And use it in the persistStatus function.
persistStatus(status) {
his.userService.updateStatus(status)
.subscribe(data => {
this.status = [status];
});
}
I develop an Ionic 3.9 chat with Firebase and I have the following error:
TypeError: this.db.list(...).subscribe is not a function
Here is my code:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { AngularFireDatabase } from 'angularfire2/database';
#IonicPage()
#Component({
selector: 'page-consersation',
templateUrl: 'conversation.html',
})
export class ConversationPage {
username: string = '';
message: string = '';
_chatSubscription;
s;
messages;
constructor(public db: AngularFireDatabase,
public navCtrl: NavController, public navParams: NavParams) {
this.username = this.navParams.get('username');
this._chatSubscription = this.db.list('/conversation').subscribe( data => {
this.messages = data;
});
}
sendMessage() {
this.db.list<any>('/conversation').push({
username: 'romain',
message: this.message
}).then( () => {
// message is sent
});
this.message = '';
}
}
Can you help me please?
In this.db.list('/conversation').subscribe( you are missing something between the .list(...) and the .subscribe(...
What you're missing is either .valueChanges() or .snapshotChanges()... You can read about the differences at the AngularFire2 documentation here.
I typically use .valueChanges() most often, so for a quick example with .valueChanges() your code would be:
this._chatSubscription = this.db.list('/conversation').valueChanges().subscribe( data => {
this.messages = data;
);
EDIT - corrected code below. Not supposed to set a variable equal to the whole .subscribe... Define your pointer/listener, and then subscribe to it separately.
this._chatSubscription = this.db.list('/conversation').valueChanges()
this._chatSubscription.subscribe( data => {
this.messages = data;
);
2nd EDIT - after new error message that OP posted as answer.
That new error looks like it's due to version conflicts - check out this question with multiple possible solutions.
When you're getting the following error polyfills.js:3 Uncaught TypeError: Object(...) is not a function..., try the following code below:
this._chatSubscription = this.db.object('/conversation').valueChanges().subscribe(data => {
this.messages = data;
});
First I've searched for "No provider for Http", as the error was showing, but I've realised that I've imported http within videoplayer.component, but I diddn't used it. But I've learned much about mocking services and especially the post on an observable abstract mock up is very helpfull. After removing the http from the videoplayer.component, I've got the next error: VideoService is not defined. I've forgotten the import in the testing module! After resolving this in the test component, I've received "No provider for HTTP" again.
So first my testing code (videoplayer.component.spec.ts) with the mock up from the post above
import { ComponentFixture, TestBed } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { async } from '#angular/core/testing';
import { AbstractMockObservableService }
from '../shared/test/abstract.mock.observable.service';
import { VideoPlayer } from './videoplayer.component';
import { VideoService } from './video.service';
describe('VideoPlayer (inline template)', () => {
class MockService extends AbstractMockObservableService {
getLoading(cb) {
return true;// stubbing?
}
pushLoadState() {
return false;// stubbing?
}
getOptions(requestDisplayId) : Observable<VideoDetail> {
return false;// return Observable???
}
reservePlayer(displayID,domID) { // TODO register ids?
return false;
}
}
let mockService;
let comp: VideoPlayer;
let fixture: ComponentFixture<VideoPlayer>;
let de: DebugElement;
let el: HTMLElement;
// async beforeEach
beforeEach(async(() => {
mockService = new MockService();
TestBed.configureTestingModule({
declarations: [ VideoPlayer ], // declare the test component
providers: [ {provide: VideoService, useValue: mockService } ],
})
.compileComponents(); // compile template and css
}));
// synchronous befareEach...
beforeEach(() => {
fixture = TestBed.createComponent(VideoPlayer);
comp = fixture.componentInstance; // VideoPlayer test instance
// query for the title <h1> by CSS element selector
de = fixture.debugElement.query(By.css('.videocontainer'));
el = de.nativeElement;
console.log(de);
console.log(el);
});
it('SOME CONTENT', () => {
});
});
Now the videoplayer.component.ts, please excuse the direct dom manipulations for the Youtube iFrame-API, I'm still searching for an Angular2 compatible way.
import {Component,Input,Output,Inject,ElementRef} from '#angular/core';
import {NgIf} from '#angular/common';
import {VideoService} from './video.service';
#Component({
selector: 'my-video-player',
providers: [VideoService],
template: require('./videoplayer.html'),
})
export class VideoPlayer implements OnChanges {
#Input() displayid : String;
#Input() displayflag : Number;
// -1 button to load player,0 no display,1 load but dont start,
// 2 autostart after load
#Output() onStateChange = new EventEmitter<any>();
private options : Object;
private loadingFlag : boolean;
private errorFlag : boolean;
private myPlayer : Object;
ngOnChanges(changes: SimpleChanges) {
var refreshed = false;
if (changes.includes('displayid'))
{
let did = changes['displayid'];
if (did.previousValue !== did.currentValue) {
refreshPlayer();
refreshed = true;
}
}
if (!refreshed && changes.includes('displayid'))
{
let did = changes['displayflag'];
if (did.previousValue !== did.currentValue) {
refreshPlayer();
refreshed = true;
}
}
/*for (let propName in changes) {
let chng = changes[propName];
let cur = JSON.stringify(chng.currentValue);
let prev = JSON.stringify(chng.previousValue);
}*/
}
constructor(#Inject(ElementRef) elr: ElementRef,
#Inject(VideoService) videoService: VideoService) {
this.loadingFlag = true;
}
ngOnInit() {
refreshPlayer();
}
loadPlayer() {
this.displayflag = 2;
this.refreshPlayer();
}
refreshPlayer() {
// loadingFlag with Callback
this.loadingFlag = videoService.getLoading(this.refreshPlayer);
if (this.loadingFlag) return;
if (this.myPlayer !== null) {
this.myPlayer.destroy();
this.myPlayer = null;
}
this.errorFlag = false;
if (this.displayid !== null && this.displayflag > 0) {
console.log('refreshPlayer: ' + this.displayid);
videoService.getOptions(this.displayid)
.subscribe(
this.getOptionsOnNext,
this.getOptionsOnError,
this.getOptionsOnCompleted
);
}
}
private getOptionsOnNext(data) {
this.displayid = data.displayid; //?
var myId = 'vp'+this.displayid;
// check if element exists
if (document.getElementById(myId)===null)
{
var newNode = document.createElement("div");
newNode.id = myId;
elr.nativeElement.insertBefore(newNode);
}
this.options = data.options;
this.options.events = {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange,
'onError': onPlayerError,
};
this.myPlayer = new YT.Player(myId, options);
videoService.reservePlayer(this.displayid,myId);
}
private getOptionsOnError(err) {
// console.log(err);
this.errorFlag = true;
}
private getOptionsOnCompleted() {
console.log('getOptionsOnCompleted: ' + this.displayid);
}
private onPlayerReady(event) {
if (this.displayflag == 2)
event.target.playVideo();
}
private onPlayerStateChange(event) {
onStateChange.emit(event.data);
}
private onPlayerError(event) {
console.log(event);
errorFlag = true;
}
}
And here is the stack trace, telling me nothing.
Error: No provider for Http!
Error: DI Error
at NoProviderError.ZoneAwareError (webpack:///~/zone.js/dist/zone.js:811:0 <- src/polyfills.ts:3833:33)
at NoProviderError.BaseError [as constructor] (webpack:///~/#angular/core/src/facade/errors.js:22:0 <- src/test.ts:22301:16)
at NoProviderError.AbstractProviderError [as constructor] (webpack:///~/#angular/core/src/di/reflective_errors.js:54:0 <- src/test.ts:45305:16)
at new NoProviderError (webpack:///~/#angular/core/src/di/reflective_errors.js:116:0 <- src/test.ts:45367:16)
at ReflectiveInjector_._throwOrNull (webpack:///~/#angular/core/src/di/reflective_injector.js:485:0 <- src/test.ts:63446:19)
at ReflectiveInjector_._getByKeyDefault (webpack:///~/#angular/core/src/di/reflective_injector.js:524:0 <- src/test.ts:63485:25)
at ReflectiveInjector_._getByKey (webpack:///~/#angular/core/src/di/reflective_injector.js:456:0 <- src/test.ts:63417:25)
at ReflectiveInjector_.get (webpack:///~/#angular/core/src/di/reflective_injector.js:325:0 <- src/test.ts:63286:21)
at TestBed.get (webpack:///~/#angular/core/bundles/core-testing.umd.js:827:0 <- src/test.ts:8978:67)
at CompiledTemplate.proxyViewClass.AppView.injectorGet (webpack:///~/#angular/core/src/linker/view.js:152:0 <- src/test.ts:64221:45)
at CompiledTemplate.proxyViewClass.DebugAppView.injectorGet (webpack:///~/#angular/core/src/linker/view.js:580:0 <- src/test.ts:64649:49)
at CompiledTemplate.proxyViewClass.View_VideoPlayer_Host0.createInternal (/DynamicTestModule/VideoPlayer/host.ngfactory.js:19:55)
at CompiledTemplate.proxyViewClass.AppView.createHostView (webpack:///~/#angular/core/src/linker/view.js:108:0 <- src/test.ts:64177:21)
at CompiledTemplate.proxyViewClass.DebugAppView.createHostView (webpack:///~/#angular/core/src/linker/view.js:564:0 <- src/test.ts:64633:52)
at ComponentFactory.create (webpack:///~/#angular/core/src/linker/component_factory.js:202:0 <- src/test.ts:33107:25)
There are lot of documentation and examples on how to convert Angular 1 services and factories to Angular2 but I couldnt find anything on how to convert a ng1 provider to something equivalent in ng2.
Example provider
function AlertService () {
this.toast = false;
this.$get = getService;
this.showAsToast = function(isToast) {
this.toast = isToast;
};
getService.$inject = ['$timeout', '$sce'];
function getService ($timeout, $sce) {
var toast = this.toast,
alertId = 0, // unique id for each alert. Starts from 0.
alerts = []
return {
factory: factory,
add: addAlert
};
function factory(alertOptions) {
var alert = {
type: alertOptions.type,
msg: $sce.trustAsHtml(alertOptions.msg),
id: alertOptions.alertId,
toast: alertOptions.toast
};
alerts.push(alert);
return alert;
}
function addAlert(alertOptions) {
alertOptions.alertId = alertId++;
var alert = this.factory(alertOptions);
return alert;
}
}
}
angular
.module('angularApp', [])
.provider('AlertService', AlertService);
What would be the correct equivalent for this in Angular 2?
Ok so finally we figured it out thanks to https://github.com/jhipster/generator-jhipster/issues/3664#issuecomment-251902173
Here is the Service in NG2
import {Injectable, Sanitizer, SecurityContext} from '#angular/core';
#Injectable()
export class AlertService {
private alertId: number;
private alerts: any[];
constructor(private sanitizer: Sanitizer, private toast: boolean) {
this.alertId = 0; // unique id for each alert. Starts from 0.
this.alerts = [];
}
factory(alertOptions): any {
var alert = {
type: alertOptions.type,
msg: this.sanitizer.sanitize(SecurityContext.HTML, alertOptions.msg),
id: alertOptions.alertId,
toast: alertOptions.toast
};
this.alerts.push(alert);
return alert;
}
addAlert(alertOptions, extAlerts): any {
alertOptions.alertId = this.alertId++;
var alert = this.factory(alertOptions);
return alert;
}
isToast(): boolean {
return this.toast;
}
}
and here is the provider for the service
import { Sanitizer } from '#angular/core';
import { AlertService } from './alert.service';
export function alertServiceProvider(toast?: boolean) {
// set below to true to make alerts look like toast
let isToast = toast ? toast : false;
return {
provide: AlertService,
useFactory: (sanitizer: Sanitizer) => new AlertService(sanitizer, isToast),
deps: [Sanitizer]
}
}
Now you need to call the alertServiceProvider method in the provider declaration of your module.
#NgModule({
imports: [
...
],
declarations: [
...
],
providers: [
...
alertServiceProvider()
],
exports: [
...
]
})
export class SharedCommonModule {}
The code is part of the JHipster project and you can browse actual templates here