I have a test page for QA where our QA can replicate the behavior of the server by passing json to a mock service.
Everything works as intended when I use a valid json, but when I use an invalid json I receive an error, which is regular. The problem I have is that the page doesn't update anymore after this json error, even with a valid json.
Here is an extract of the test page component:
export class QaTestComponent implements OnInit {
modules: Module[];
pageState: PageState;
mockModulesValue: string;
mockPageStateValue: string;
constructor(private moduleService: MockModuleService, private pageStateService: MockPageStateService) { }
getModules() {
this.moduleService.getModules().then(modules => this.modules = modules);
}
updateModules() {
let jsonModules = JSON.parse(this.mockModulesValue);
this.moduleService.setModules(jsonModules);
this.getModules();
}
Here is the html file with the function call:
<div class="qa-test-interface-setup-datas-type col-md-6">
<h3 class="qa-test-interface-setup-datas-type-title">Modules</h3>
<textarea name="" id="" cols="30" rows="10" class="qa-test-interface-setup-datas-type-textarea" [(ngModel)]="mockModulesValue"></textarea>
<button class="qa-test-interface-setup-datas-type-button" (click)="updateModules()">Update</button>
</div>
And here is the mock service:
export class MockModuleService implements ModuleService {
raw: Module[] = aJsonArray;
response: Module[] = this.raw;
setModules(mockModules: Module[]) {
this.response = mockModules == null ? this.raw : mockModules;
}
getModules(): Promise<Module[]> {
return Promise.resolve(this.response);
}
}
I tried logging to see if a valid mockModuleValues was blocked in a component or a service after an error but I can see it goes through until getModules().
So after some research I came to the point where I did my json parsing inside a try/catch to avoid the error killing my subscriber.
updateModules() {
if(this.mockModulesValue) {
try {
let jsonModules = JSON.parse(this.mockModulesValue);
this.moduleService.setModules(jsonModules);
this.getModules();
} catch(e) {
alert(e);
}
}
}
Related
Im trying to get this onfido cordova plugin to work but even though I get no errors it doesnt seem to do anything.
https://github.com/rewireltd1/cordova-plugin-onfido
This is a simple Ionic tutorial app which ive added a button to, which calls a method in my ts file to initialize the plugin.
import { Component } from '#angular/core';
#Component({
selector: 'page-hello-ionic',
templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
applicantId: string = APPLICANT_ID
token: string = TOKEN
options: any;
constructor(
) {
this.options = {
token: this.token, // IMPORTANT: see notes
applicant_id: this.applicantId,
flow_steps: [ 'welcome', 'document', 'face', 'final'],
}
}
handleOnfido() {
try {
console.log(1)
window['cordova'].plugins.onfido.init((res) => {
console.log(res)
this.onComplete(res)
}, this.options)
console.log(2)
} catch (error) {
console.log('ERROR', error)
}
}
onComplete(completeResponse) {
console.log('in on complete', completeResponse)
}
}
The app successfully builds on my android and when I click the button I get the logs 1 and 2 so no errors but then nothing. From looking at the Github does it look like im doing anything wrong? Any assistance would be massively helpful.
Thanks
I am trying to implement sentry error handling into my application, now I have it set up and working as expected.. but now I want to be able to pass user information on the Sentry object for better error logging.
So I have the following setup
export class SentryErrorHandler implements ErrorHandler {
userInfo: UserInfo;
constructor(
private _store: Store<AppState>
) {
this.getUserInfo();
}
getUserInfo() {
this._store.select('userInfo')
.subscribe(result => {
this.userInfo = result;
});
}
handleError(err: any): void {
Sentry.configureScope((scope) => {
scope.setUser({
email: this.userInfo?.emailAddress,
id: this.userInfo?.id?,
});
});
const eventId = Sentry.captureException(err.originalError || err);
Sentry.showReportDialog({ eventId });
}
}
and I am providing the error handler like so in my root module
// ...
{ provide: ErrorHandler, useClass: SentryErrorHandler }
// ...
but what happens is, when I start my application I get the following error
Obviously im doing something wrong here, any help would be appreciated!
This error is happening because without the #Injectable decorator Angular cannot wire up dependencies for the class (even using it in providers).
So all you have to do is add the #Injectable() decorator in your error class.
See a demo here:
https://stackblitz.com/edit/angular-ctutia
This question already has answers here:
Angular2: Cannot read property 'name' of undefined
(7 answers)
Closed 3 years ago.
I am using an environment variable to be able to read something from a JSON and display in my HTML. My issue is that my HTML is trying to read the environment variable before it has been defined in the .ts and therefore I get an error.
I am currently defining the variable in ngOnit() but this gives me an error. I am using httpclient to be able to read the JSON (from a server) and obviously what is happening is that the variable is being read in the HTML before httpclient has got the data.
HTML
<p>Player One is: {{ id.playerone }} </p>
.ts
import { HttpClient } from '#angular/common/http';
export class ApComponent implements OnInit {
id: any = [];
constructor(private httpService: HttpClient) { }
ngOnInit() {
this.httpService.get('http://server/info.json').subscribe(
result => {
this.id = result;
},
error => {
console.log('Error Occured', error);
}
);
}
}
JSON
{
"playerone":"ajf806",
"playertwo":"hof934"
}
I get the expected output of Player One is: ajf806 but I also get an error in the console which is:
ERROR TypeError: Cannot read property '0' of undefined.
It does work and I get the output but I don't want to have the error in the console. Is there a way to delay the HTML reading the environment variable until the JSON has been read?
Change your variable like this:
id: any;
also change your template like this:
<p>Player One is: {{ id?.playerone }} </p>
Another version of the above code [a bit better]:
import { HttpClient } from '#angular/common/http';
export class ApComponent implements OnInit {
id$: Observable<any>;
constructor(private httpService: HttpClient) { }
ngOnInit() {
this.id$ = this.httpService.get('http://server/info.json')
.pipe(
catchError((error) => {
//handle your error
console.log(error);
})
)
);
}
}
Now change your template to make use of async pipe like this:
<ng-conatiner *ngIf="(id$ | async) as id">
<p>Player One is: {{ id.playerone }} </p>
</ng-container>
NOTICE - you are not subscribing to the observable in your component. async pipe is taking care of subscription management [i.e. subscribing/unsubscribing.].
I'm currently working on a register page and therefore, I need to post my data to the server. The client-side validation and server-validation works. I know I can handle the client-side errors like *ngIf="(emailAddress.errors?.required || emailAddress.errors?.email) && emailAddress.touched". But how to handle the server-side errors?
In my service, if an error occurs, I simply give it into the component by return throwError(error);
But how can I know to display the specific error in my component if for example there is already someone with this email address? And how do distinguish between email/password validation errors server side?
Depends on the complexity and modules you have.
If you use any kind of state management library such as ngrx or ngxs, I suggest you do as follow:
Define State with a property 'error' which keeps track of the latest server-error.
Api call executed via actions and error is caught and stored to state also via actions. (Do whatever error mapping before saving the error to your State)
Use selectors for component to receive error stream from State.
If you don't have any state management library, you can create a BehaviorSubject within singleton service, and use it to publish server-error as soon as you got into any catchError context.
This way you can write your own http interceptor and have your response inside your component. Also in your component you know your http response is success or error.
You can implement other Http calls(GET, PUT, etc) and also handle your general errors in handleError() function.
app.module.ts
export class AppModule {
constructor() {}
imports: [
HttpClientModule,
],
providers: [
{
provide: Http,
useFactory: httpFactory,
deps: [HttpHandler]
},
],
}
export function httpFactory(httpHandler: HttpHandler) {
return new Http(httpHandler);
}
http.service.ts
export class Http extends HttpClient {
constructor(handler: HttpHandler) {
super(handler);
}
postCall(url: string, body, options?): Observable<any> {
return super.post(url, body, options)
.pipe(
tap(response => { console.log(response) }),
catchError(this.handleError(error)));
}
private handleError<T>(result?: T) {
return (error: any): Observable<T> => {
console.log(error);
return of(result as T);
};
}
}
your.component.ts
export class YourComponent {
constructor(private http: Http) {}
this.http.postCall('URL', {}).subscribe(response => {
if (response instanceof HttpErrorResponse) {
// Your Response is error
} else {
// Your Response is your desired result
}
}
I'm trying to do a ToDoList in service with localstorage.
add.component.ts
export class AddComponent implements OnInit {
item: Item[];
constructor(
private router: Router,
private itemService: ItemService) {
}
addTodo() {
this.itemService.save();
this.router.navigate(['./list']);
}
ngOnInit() {}
}
item.service.ts
#Injectable()
export class ItemService {
private itemsUrl = 'items';
private headers = new Headers({'Content-Type': 'application/json'});
private todos: any;
private currentItem: any;
constructor(
private http: Http,
private item: Item) {
this.currentItem = (localStorage.getItem('currentItem')!==null) ? JSON.parse(localStorage.getItem('currentItem')) : [ ];
this.todos = this.currentItem;
}
save(): Promise<Item> {
return this.http
.post(this.itemsUrl, {headers: this.headers})
.toPromise()
.then((res: Response) => {
this.todos.push({
id: this.item.id,
title: this.item.title,
message: this.item.message,
done: false
});
this.todos.title = '';
this.todos.message = '';
localStorage.setItem('currentItem', JSON.stringify(this.todos))
return this.todos;
})
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.log('An error occured', error);
return Promise.reject(error.message || error);
}
}
item.ts
export class Item {
id: number;
title: string;
message: string;
}
add.component.ts
<div class="container">
<form (submit)="addTodo()">
<div class="form-group">
<label>Id:</label>
<input [(ngModel)]="id" class="textfield form-control" name="id">
</div>
<div class="form-group">
<label>Titulo:</label>
<input [(ngModel)]="title" class="textfield form-control" name="title">
</div>
<div class="form-group">
<label>Mensagem:</label>
<input [(ngModel)]="message" class="textfield form-control" name="message">
</div>
<button type="submit" class="btn btn-success">Save</button>
</form>
</div>
If I add localstorage in add.component.ts it works! But if a try to do it as a service I have an error : EXCEPTION: Uncaught (in promise): Error: DI Error Error: DI Error
I don't know what to do. I search how to do it but I don't found an answer that would help me.
Does anyone know how to fix it?
Localstorage is not an angular service. It's just a native JS object controlling the browser's localstorage. Therefor you can not inject it. If you want to have service functionality, you can wrap the native localstorage in an angular LocalStorageService
You don't want to inject Item into ItemService. You really want to have a get function that accepts an Item as an argument and retrieves it from localStorage.
As PierreDuc said, local storage is feature of the user browser. According to this it should work with all major browsers.
Because it browser feature and not part of angular it doesn't need to be injected.
More of how to use localStorage you can read here.
If you still want to use it as an angular service I recommend you to use this library.