maybe someone can help me: I have created my first Angular package. The package itself has to provide different services to make HTTP requests to a server and return the results.
However, when importing the service, the web page stops rendering and I get an error message:
core.mjs:6484 ERROR Error: ASSERTION ERROR: token must be defined [Expected=> null != undefined <=Actual]
at throwError (core.mjs:326)
at assertDefined (core.mjs:322)
at bloomHashBitOrFactory (core.mjs:3591)
at getOrCreateInjectable (core.mjs:3379)
at Module.ɵɵdirectiveInject (core.mjs:14392)
at NodeInjectorFactory.AppComponent_Factory [as factory] (app.component.ts:10)
at getNodeInjectable (core.mjs:3556)
at instantiateRootComponent (core.mjs:10159)
at createRootComponent (core.mjs:12259)
at ComponentFactory.create (core.mjs:21580)
My Service:
// imports ...
/**
* DoctorService
*/
#Injectable({
providedIn: "root"
})
export class DoctorService {
constructor(private readonly httpClient: HttpClient) { }
/**
* Returns a doctor by a given uuid.
*
* #param uuid
* #return Promise<Doctor>
*/
public async getDoctorByUUID(uuid: string): Promise<Doctor> {
const uuidRegExp = new RegExp(/[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}/);
if (!uuidRegExp.test(uuid)) {
console.error("UUID does not have a valid format. It needs to be in a 8-4-4-4-12 digit pattern.")
return new Promise<Doctor>(() => {
return [];
});
}
const httpParams: HttpParams = new HttpParams();
httpParams.set("module", "mydoc");
httpParams.set("sektion", "show_doctor");
httpParams.set("uuid", uuid);
httpParams.set("return", "json");
const request = this.httpClient.get<Doctor>(API_BASE_URL, { params: httpParams });
return firstValueFrom(request);
}
}
Component which uses the Service:
import {Component} from '#angular/core';
import {DoctorService} from "my-doc-util/src/lib/services/doctor-service/doctor.service";
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'angular-testing';
constructor(private readonly doctorService: DoctorService) {
}
}
I have experienced the same exact error (angular 11)
I don't know if it's the same reason but in my case, it turned out that the component had an uninitialized input.
Related
I'm new to Angular and hoping someone can guide me through the process of making a soap call. I can call the endpoint with a Request in SoapUI and it returns the correct Response. Now I'd like to know how to do the same thing in Angular.
The closest one I could find is Answer #3. But it doesn't provide enough context for a beginner.
Here's what I've got so far:
app.component.ts
import { Component } from '#angular/core';
import { SoapService } from './soap.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
title = 'Test of SOAP calls'
name = 'SOAP Prototype';
response: any;
constructor(private soapService: SoapService)
{
soapService.getResponse().subscribe(
res => {
console.log("returned data: ",res);
}
);
}
}
soap.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { Subject } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
#Injectable()
export class SoapService
{
constructor(private httpClient: HttpClient) { }
getResponse()
{
const myheaders = new HttpHeaders();
myheaders.set('Content-Type','text/xml');
const myparams = new HttpParams();
myparams.set('username', 'me');
myparams.set('acctId','1585');
myparams.set('domain','USR');
myparams.set('active','true');
const response = this.httpClient.post<any>('url-to-soap-service', {headers: myheaders, params: myparams, responseType: 'text'});
console.log(response);
return response;
}
}
Nothing is logged to the console in app.component.ts, nor in soap.service.ts.
I'm see this error in the browser console:
"<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">soap:Bodysoap:Faultsoap:ClientError
reading XMLStreamReader: Unexpected character '{' (code 123) in
prolog; expected '<'\n at [row,col {unknown-source}]:
[1,1]</soap:Fault></soap:Body></soap:Envelope>"
I don't see how there can be an unexpected char when the HttpClient is generating the soap envelope.
What am I doing wrong?
This question already has answers here:
How do I return the response from an Observable/http/async call in angular?
(10 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I am trying to populate MatTableDataSource using Http local call to JSON. But it's not working. I think the assignment operation in 'subscribe()' in 'data-table.component.ts' file is not working. I tried to debug and tried to find the solution, but nothing worked and most of the time I end up breaking up m code. Please help me.
Thanks
Below are the codes with respective file names:
data-table.component.ts
import { Component } from '#angular/core';
import { MatTableDataSource } from '#angular/material';
import { FormDataService } from 'src/app/services/form-data.service';
#Component({
selector: 'app-data-table',
templateUrl: './data-table.component.html',
styleUrls: ['./data-table.component.css']
})
export class DataTableComponent {
displayedColumns: string[] = ['request_number', 'request_name', 'last_updated_date', 'completion', 'status'];
ELEMENT_REQUEST = [];
constructor(private _formDataService: FormDataService) {
console.log("Before getting data: ", this.ELEMENT_REQUEST)
this._formDataService.getformData()
.subscribe((data:any) => {
this.ELEMENT_REQUEST = data; // This line not working!
console.log("Inside: ",data);
}, err => {
console.log(err);
})
console.log("After getting data: ", this.ELEMENT_REQUEST)
}
dataSource = new MatTableDataSource(this.ELEMENT_REQUEST);
logData(row) {
console.log(row);
}
applyFilter(filterValue: String) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}
form-data-model.ts
export interface Form_Data {
request_name: string;
request_number: number;
last_updated_date: string;
completion: number;
status: string;
}
form-data.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Form_Data } from './form-data-model';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class FormDataService {
_url = "/assets/data/form_data.json"
constructor(private http: HttpClient) { }
getformData(): Observable<Form_Data[]> {
return this.http.get<Form_Data[]>(this._url);
}
}
I got this snippet from the chrome console.
Before getting Data is all good, Inside is also working, but After getting data, there is nothing in the array
Image
I have an component where i am adding a new object called customer by calling the api like this:
public onAdd(): void {
this.myCustomer = this.customerForm.value;
this.myService.addCustomer(this.myCustome).subscribe(
() => { // If POST is success
this.callSuccessMethod();
},
(error) => { // If POST is failed
this.callFailureMethod();
},
);
}
Service file:
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import {ICustomer } from 'src/app/models/app.models';
#Injectable({
providedIn: 'root',
})
export class MyService {
private baseUrl : string = '....URL....';
constructor(private http: HttpClient) {}
public addCustomer(customer: ICustomer): Observable<object> {
const apiUrl: string = `${this.baseUrl}/customers`;
return this.http.post(apiUrl, customer);
}
}
As shown in component code, i have already subscribed the api call like this:
this.myService.addCustomer(this.myCustome).subscribe(
() => { // If POST is success
.....
},
(error) => { // If POST is failed
...
},
);
But,I want to subscribe the results in another component, I have tried like this:
public getAddedCustomer() {
this.myService.addCustomer().subscribe(
(data:ICustomer) => {
this.addedCustomer.id = data.id; <======
}
);
}
I am getting this lint error: Expected 1 arguments, but got 0 since i am not passing any parameter.
What is the right approach to subscribe the api call in other components? after POST operation.
Because i want to get added object id for other functionality.
Well it totally depends on the design of your application and the relation between components. You can use Subjects for multicasting the data to multiple subscribers.
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import { ICustomer } from 'src/app/models/app.models';
#Injectable({
providedIn: 'root',
})
export class MyService {
private baseUrl : string = '....URL....';
private latestAddedCustomer = new Subject();
public latestAddedCustomer$ = this.latestAddedCustomer.asObservable()
constructor(private http: HttpClient) {}
public addCustomer(customer: ICustomer): Observable<object> {
const apiUrl: string = `${this.baseUrl}/customers`;
return this.http.post(apiUrl, customer).pipe(map((data) => this.latestAddedCustomer.next(data)));
}
}
and subscribing to the subject as follows
this.latestAddedCustomer$.subscribe()
should get you the latest added customer details. Even though i would not do this the way its written. I would basically write a seperate service to share the data between the components or would write a cache service if its used across the application. But the idea here is to use the concept of Subjects. You can read more about it Here
How do you map and use a JSON reponse that is a single object, rather than an array?
Recently, I started adding a new feature to a project I'm working on that should be taking a JSON response from an API and filling out a simple template with data from it. Shouldn't be difficult, right? Well, no... and yet, yes...
Mock version of the JSON response:
{
"id": 1,
"name": "Acaeris",
}
profile.service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { Profile } from './profile';
/**
* This class provides the Profile service with methods to read profile data
*/
#Injectable()
export class ProfileService {
/**
* Creates a new ProfileService with the injected Http.
* #param {Http} http - The injected Http.
* #constructor
*/
constructor(private http: Http) {}
/**
* Returns an Observable for the HTTP GET request for the JSON resource.
* #return {Profile} The Observable for the HTTP request.
*/
get(): Observable<Profile> {
return this.http.get('assets/profile.json')
.map(res => <Profile>res.json())
.catch(this.handleError);
}
/**
* Handle HTTP error
*/
private handleError (error: any) {
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg);
return Observable.throw(errMsg);
}
}
profile.component.ts
import { Component, OnInit } from '#angular/core';
import { ProfileService } from '../services/profile/profile.service';
import { Profile } from '../services/profile/profile';
/**
* This class represents the lazy loaded ProfileComponent
*/
#Component({
moduleId: module.id,
selector: 'sd-profile',
templateUrl: 'profile.component.html',
styleUrls: ['profile.component.css'],
})
export class ProfileComponent implements OnInit {
errorMessage: string;
profile: Profile;
/**
* Creates an instance of the ProfileComponent with the injected
* ProfileService
*
* #param {ProfileService} profileService - The injected ProfileService
*/
constructor(public profileService: ProfileService) {}
/**
* Get the profile data
*/
ngOnInit() {
this.getProfile();
}
/**
* Handles the profileService observable
*/
getProfile() {
this.profileService.get()
.subscribe(
data => this.profile = data,
error => this.errorMessage = <any>error
);
}
}
profile.ts
export interface Profile {
id: number;
name: string;
}
And I'm just trying to output it using {{profile.name}} but this ends up with the console showing a whole load of error messages and no output. If I try to check the contents of profile after it has loaded, it tells me it is undefined.
However, here's the confusing part. If I replace all the Profile references to Profile[], wrap the JSON in an array, add *ngFor="let p of profile" abd use {{p.name}} everything works fine. Unfortunately, in the actual finished application I would not have control of the JSON format. So what am I doing wrong when trying to handle it as a single object in comparison to handling as an array of objects?
Looks like at expression {{profile.name}} profile variable is undefined at page rendering moment. You can try either add some getter like this:
get profileName(): string { return this.profile ? this.profile.name ? ''; }
and use at template {{profileName}} or you can use ngIf at template like this:
<div *ngIf="profile">{{profile.name}}</div>
or shorter (as drewmoore suggested at comment below):
<div>{{profile?.name}}</div>
When you are working with array it is the same situation - at first rendering time array is undefined. ngFor handles this for you and renders nothing. When async operation of getting 'profile items' is complete - UI is rerendered again with correct values.
The mapfunction returns Observables which are a collection of elements. It basically work the same way as the map function for arrays.
Now to solve you can replace the Profile references by Profile[] and use {{profile[0].name}}.
I have used Promise and observables logic to fetch data from server using "get".
It was working till yesterday. SUddenly it starts throwing the above error.
Please help me finding the error.
I am getting "Generic type 'Promise' requires 1 type argument(s)" error.
#Injectable()
export class myBlogService{
// Property to hold root server URL i.e host
private serverUrl:string = "app/data.json"
constructor(private http:Http) {}
// check function in service to check control is coming to service
check(){
alert("getting clicked from service");
}
// get function to get data from server
// basically blog datas
get(): Promise {
return this.http.get(this.serverUrl)
.map(response => response.json())
}
}
/**
*
* My Components
*
*/
#Component({
selector: 'my-app',
providers: [myBlogService],
styleUrls: ['app/css/app.css'],
template: `
<h1 (click)= check()>My First Angular 2 App</h1>
<button (click)=get()>Get My Name</button>
<h1>{{getResponse.name}}</h1>
`
})
export class myBlogApp {
// Property to hold blog data
public getResponse = {"name": "", "age": ""};
constructor(protected myblogservice:myBlogService){}
// check function to check control is going to service
check() {
this.myblogservice.check();
}
// get function calls service get function which return data from server
get(){
this.myblogservice.get().subscribe(data => {
this.getResponse = data;
});
}
}
/**
*
* NgModule Declaration
*
*/
#NgModule({
imports: [ BrowserModule, HttpModule ],
declarations: [ myBlogApp ],
providers: [ ],
bootstrap: [ myBlogApp ]
})
export class app{}
/**
*
* App engine entry point
*
*/
const platform = platformBrowserDynamic();
platform.bootstrapModule(app);
When "promise: " is given, still it gives issue like
"error TS2339: Property 'subscribe' does not exist on type 'Promise'".
I tried different solution but no luck yet.
You need to add the specific type.
If it contains no data and is being used purely for the resolve/reject functionality, use:
Promise<void>
Ultimately this is a type signature like any other, so you can use:
Promise<any>
https://basarat.gitbooks.io/typescript/content/docs/promise.html
Instead of using Promise try to use Observable, replace:
get(): Promise {
return this.http.get(this.serverUrl)
.map(response => response.json())
}
with
get(): Observable<any> {
return this.http.get(this.serverUrl)
.map(response => response.json())
}