So, I'm currently trying to send a HTTP request, I'm doing everything exactly like in official guide and it's wont work (as usual when you make deal with Angular2)
Here is my app.module
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouterModule, Routes } from '#angular/router';
import { HttpModule, JsonpModule } from '#angular/http';
import { AppComponent } from './app.component';
import { PageComponent } from './modules/Affiliate/affiliate.component';
import { NotFoundComponent } from './not-found.component';
const routes: Routes =
[
{ path: 'page', component: PageComponent },
{ path: '404', component: NotFoundComponent },
{ path: '**', redirectTo: '404' }
];
#NgModule({
imports: [
BrowserModule,
RouterModule.forRoot(routes),
HttpModule,
JsonpModule
],
declarations: [
AppComponent,
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
And here is my service, where I'm trying to send a http request
import { Injectable } from '#angular/core';
import { Headers, Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class GridService {
constructor(private http: Http) { }
getTableRaws(url): Promise<any> {
return this.http.get(url)
.toPromise()
.then(response => response.json().data as any)
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
Any ideas, please
Following the docs, I guess you missed the data type for the url param:
getTableRaws(url: string): Promise<any> {
...
}
UPDATE:
You need to add GridService as a provider in app.module. Refer to this SO answer.
If you have made these changes then update your code in the question and also provide the contents of app.component here.
Here is the solution that works for me:
constructor(#Inject(Http) private http: Http) {}
Related
I am fairly new to Angular2 and I am having issues adding Dragula to my application. When I run the application an error is thrown prior to loading the home page:
Exception: Call to Node module failed with error: Prerendering failed because of error: ReferenceError: document is not defined
The error message mentions Prerending which I suspect is in relation to the project using asp-prerender-module.
I've tried to follow official tutorials from Dragula and forum posts. Below are my app.module and component file snippets (... denotes summarised code):
app.module.ts
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { UniversalModule } from 'angular2-universal';
import { AppComponent } from './components/app/app.component'
...
import { SearchComponent } from './components/search/search.component';
import { BrowserModule } from '#angular/platform-browser';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { Injectable } from '#angular/core';
import { DragulaModule } from 'ng2-dragula';
#NgModule({
bootstrap: [ AppComponent ],
declarations: [
AppComponent,
...
SearchComponent
],
imports: [
UniversalModule,
BrowserModule,
FormsModule,
DragulaModule,
CommonModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },
...
{ path: 'search', component: SearchComponent },
{ path: '**', redirectTo: 'home' }
])
]
})
export class AppModule {
}
search.component.ts
import { Component } from '#angular/core';
import { Http } from '#angular/http';
import { SearchService } from '../../services/search.service';
import { DragulaService } from 'ng2-dragula';
#Component({
selector: 'search',
template: require('./search.component.html'),
providers: [SearchService, DragulaService]
})
I suspect I am missing an a step when including Dragula, but I cannot figure out where. I have included both dragula (^3.7.2) and ng2-dragula (^1.3.0) in my package.json file.
your DragulaService initialization is wrong!! check Dragula documentation link
search.component.ts
import { Component } from '#angular/core';
import { Http } from '#angular/http';
import { SearchService } from '../../services/search.service';
import { DragulaService } from 'ng2-dragula';
#Component({
selector: 'search',
template: require('./search.component.html'),
providers: [SearchService]
})
expoert searchcomponent{
constructor(private dragulaService: DragulaService) {
console.log('DragulaService created');
}
}
Now you can play with drag and drop
If you want more control over drag and drop you can add events and options to dragulaService.
constructor(private dragulaService: DragulaService) {
dragulaService.drag.subscribe((value) => {
console.log(`drag: ${value[0]}`);
this.onDrag(value.slice(1));
});
dragulaService.drop.subscribe((value) => {
console.log(`drop: ${value[0]}`);
this.onDrop(value.slice(1));
});
dragulaService.over.subscribe((value) => {
console.log(`over: ${value[0]}`);
this.onOver(value.slice(1));
});
dragulaService.out.subscribe((value) => {
console.log(`out: ${value[0]}`);
this.onOut(value.slice(1));
});
}
private onDrag(args) {
let [e, el] = args;
// do something
}
private onDrop(args) {
let [e, el] = args;
// do something
}
private onOver(args) {
let [e, el, container] = args;
// do something
}
private onOut(args) {
let [e, el, container] = args;
// do something
}
project Structure
Error Information
This is the error i am getting , when i broadcast the message from http extender service to the app component.
Loading Interceptor(http extender)
this is my http extender ,i am unable to broadcast the messages to App component from here ,but i am able to broadcast the messages from the child components to App component ,please see the image for the error information and project structure
import { Injectable } from '#angular/core';
import { Http, RequestOptions, RequestOptionsArgs, Response, ConnectionBackend } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { EventsEmitter } from './eventsEmitter';
#Injectable()
export class LoadingInterceptor extends Http {
private currentRequests: number = 0;
public constructor(_backend: ConnectionBackend, _defaultOptions: RequestOptions, private eventsEmitter: EventsEmitter) {
super(_backend, _defaultOptions);
}
public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
this.incrementRequestCount();
var response = super.get(url, options);
response.subscribe(null, error => {
this.decrementRequestCount();
}, () => {
this.decrementRequestCount();
});
return response;
}
private decrementRequestCount() {
if (--this.currentRequests == 0) {
this.eventsEmitter.broadcast('loading-complete');
}
}
private incrementRequestCount() {
if (this.currentRequests++ == 0) {
this.eventsEmitter.broadcast('loading-started');
}
}
}
App Component
I am listening the events broadcasted in the app component to show the loader gif on the screen
import { Component } from '#angular/core';
import { EventsEmitter } from './assets/scripts/services/eventsEmitter';
import { ToasterService } from 'angular2-toaster';
#Component({
selector: 'my-app',
templateUrl:'app/app.component.html'
})
export class AppComponent {
private toasterService: ToasterService;
private message: any;
private active: any;
constructor(toasterService: ToasterService, private eventsEmitter: EventsEmitter) {
this.toasterService = toasterService;
this.eventListners();
}
eventListners() {
this.eventsEmitter.on<string>('loading-complete')
.subscribe(message => {
this.active = false;
});
this.eventsEmitter.on<string>('loading-started')
.subscribe(message => {
this.active = true;
});
}
}
Event Emitter
this is the event emittter i am using to broadcast the events
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
interface EventsEmitterInterface {
key: any;
data?: any;
}
export class EventsEmitter {
private _eventBus: Subject<EventsEmitterInterface>;
constructor() {
this._eventBus = new Subject<EventsEmitterInterface>();
}
broadcast(key: any, data?: any) {
this._eventBus.next({ key, data });
}
on<T>(key: any): Observable<T> {
return this._eventBus.asObservable()
.filter(event => event.key === key)
.map(event => <T>event.data);
}
}
App Module
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { LocationStrategy, HashLocationStrategy } from '#angular/common';
import { HttpModule, JsonpModule, Http, RequestOptions, XHRBackend, RequestOptionsArgs, Response, ConnectionBackend} from '#angular/http';
import { AppRoutingModule } from './app.routes';
import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';
import { LoadingInterceptor } from './assets/scripts/services/loadingInterceptor';
import { EventsEmitter } from './assets/scripts/services/eventsEmitter';
import { ToasterModule, ToasterService } from 'angular2-toaster';
#NgModule({
imports: [AppRoutingModule, BrowserModule, FormsModule, ReactiveFormsModule, HttpModule, JsonpModule, ToasterModule ],
declarations: [AppComponent, LoginComponent],
bootstrap: [AppComponent],
providers: [EventsEmitter,LoadingInterceptor,
{
provide: Http,
useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions, eventsEmitter: EventsEmitter) => new LoadingInterceptor(xhrBackend, requestOptions, eventsEmitter),
deps: [XHRBackend, RequestOptions]
},{ provide: LocationStrategy, useClass: HashLocationStrategy }]
})
export class AppModule { }
I am stuck here for many days, it would be really helpful if you could help me resolve this issue
You forgot to add EventsEmitter dependency within your useFactory provider:
deps: [XHRBackend, RequestOptions]
It shoul be:
deps: [XHRBackend, RequestOptions, EventsEmitter]
That's why your LoadingInterceptor constructor gets undefined for EventsEmitter dependency
I am trying to implement a global handler to manage HTTP errors in Angular2. Going through few reference: http://restlet.com/blog/2016/04/18/interacting-efficiently-with-a-restful-service-with-angular2-and-rxjs-part-3/ and https://blog.tomasandtomas.com/angular-2-http-interceptors-7e2d74b7f14e#.nxgxijnqu , I made the following:
--------------------------------------------------------------------
// Logger service - which will be able to send the error to server or log to console
import { Http } from '#angular/http';
import { Injectable } from '#angular/core';
import { Response } from '#angular/http';
#Injectable()
export class ErrorLogService {
public logError(error: any): void {
// custom error handling here
console.log(error);
}
}
--------------------------------------------------------------------
// This is the Custom HTTP that extends Http module
import { Injectable } from '#angular/core';
import { Http, ConnectionBackend, Request, RequestOptions, RequestOptionsArgs } from '#angular/http';
import { ErrorLogService } from '../ErrorHandling/error.log.service';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class CustomHttp extends Http {
constructor(_backEnd: ConnectionBackend,
defaultOptions: RequestOptions, private errorLogService: ErrorLogService) {
super(_backEnd, defaultOptions);
}
get(url: string, options?: RequestOptionsArgs): Observable<any> {
return super.request(url, options)
.catch((error: any): any => {
this.errorLogService.logError(error);
return Observable.empty();
})
.finally(() => {
console.log('Done');
});
}
}
--------------------------------------------------------------------
// This is the service that call the api to get data.
import { Http, Response } from '#angular/http';
import { Injectable } from '#angular/core';
import { IAsset } from './asset';
import { AppSettings } from '../app.settings';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class AssetService {
private _cid = 1234;
private _total = 774;
private _pageIndex = 1;
constructor(private _http: Http) { }
getAssets(pageIndex: number): Promise<IAsset[]> {
this._pageIndex = pageIndex;
let _assetApi = `${AppSettings.GET_CONFIG('assets')}?1cid=${this._cid}&count=${this._total}&index=${this._pageIndex}`;
return this._http.get(_assetApi)
.toPromise()
.then(response => response.json() as IAsset[]);
}
}
--------------------------------------------------------------------
//This is how custom Http is injected in the app module
import { NgModule, APP_INITIALIZER, ErrorHandler } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { HttpModule } from '#angular/http';
import { Http, XHRBackend, RequestOptions } from '#angular/http';
import { AppComponent } from './app.component';
import { WelcomeComponent } from './home/welcome.component';
import { ProductModule } from './products/product.module';
import { AppRoutingModule } from './app.routing.module';
import { ErrorLogService } from './shared/ErrorHandling/error.log.service';
import { CustomHttp } from './shared/Http/custom.http.service';
#NgModule({
imports: [
BrowserModule,
HttpModule,
AppRoutingModule,
ProductModule
],
declarations: [
AppComponent,
WelcomeComponent
],
providers: [
ConfigService,
AuthService,
ErrorLogService,
{
provide: Http,
useFactory: (backend: XHRBackend, defaultOptions: RequestOptions, _errorLogService: ErrorLogService) => {
return new CustomHttp(backend, defaultOptions, _errorLogService);
},
deps: [XHRBackend, RequestOptions]
}
],
bootstrap: [AppComponent],
})
export class AppModule { }
Now the problem is that I anytime there is a 500 internal server error on my data service, it is caught by by the CustomHttp, but the this.errorLogService.logError(error); >> errorLogService is undefined and does not invoke the logError on it.
I am using the Angular 2.0.0.0.
Any pointers on this issue? - Thanks.
You need to add ErrorLogService to CustomHttp's provider deps:
providers: [
ConfigService,
AuthService,
ErrorLogService,
{
provide: Http,
useFactory: (backend: XHRBackend, defaultOptions: RequestOptions, _errorLogService: ErrorLogService) => {
return new CustomHttp(backend, defaultOptions, _errorLogService);
},
deps: [XHRBackend, RequestOptions, ErrorLogService] <-- this
}
],
I am trying to extend the Angular2 HTTP module in order to create an HTTP interceptor of sorts.. the only problem is when I try to extend this module I get the following error:
No provider for ConnectionBackend!
I have no idea why this is happening and can't seem to get this error to go.
Here is my custom HTTP module:
import { Injectable } from "#angular/core";
import { Http, ConnectionBackend, RequestOptions, Request, RequestOptionsArgs, Response } from "#angular/http";
import { Observable } from "rxjs";
#Injectable()
export class HttpInterceptor extends Http {
constructor(
backend: ConnectionBackend,
defaultOptions: RequestOptions
) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
console.log('request...');
return super.request(url, options).catch(res => {
// do something
});
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
console.log('get...');
return super.get(url, options).catch(res => {
// do something
});
}
}
And here is my app.module.ts file:
import 'app/rxjs-extensions';
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { HttpModule } from "#angular/http";
import { FormsModule } from "#angular/forms";
import { AuthGuard } from "./guards/auth.guard";
import { routing } from "./app.routing";
import { AppComponent } from './app.component';
import { HomeComponent } from "./components/home/HomeComponent";
import { LoginComponent } from "./components/login/LoginComponent";
import { NavBarComponent } from "./components/navbar/NavBarComponent";
import { ProductComponent } from "./components/catalog/products/ProductComponent";
import { GlobalEventsManager } from "./services/globalEventsManager.service";
import { AuthService } from "./services/auth.service";
import { ToastModule } from 'ng2-toastr/ng2-toastr';
import { LeftNavComponent } from "./components/left-nav/left-nav-component";
import { SettingsComponent } from "./components/settings/settings-component";
import { UsersComponent } from "./components/users/users-component";
import { OptionsComponent } from "./components/catalog/options/OptionsComponent";
import { CategoriesComponent } from "./components/catalog/categories/CategoriesComponent";
import { ManufacturersComponent } from "./components/catalog/manufacturers/ManufacturersComponent";
import { ProductSearchComponent } from "./components/catalog/products/directives/ProductSearchComponent";
import { ProductListComponent } from "./components/catalog/products/directives/ProductListComponent";
import { ProductService } from "./services/product.service";
import { HttpInterceptor } from "./services/HttpInterceptor.service";
#NgModule({
imports: [
BrowserModule,
HttpModule,
FormsModule,
routing,
ToastModule
],
declarations: [
AppComponent,
HomeComponent,
LoginComponent,
NavBarComponent,
ProductComponent,
ProductSearchComponent,
ProductListComponent,
LeftNavComponent,
SettingsComponent,
UsersComponent,
OptionsComponent,
CategoriesComponent,
ManufacturersComponent
],
providers: [
AuthService,
AuthGuard,
GlobalEventsManager,
ProductService,
HttpInterceptor
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
I have tried placing the my HttpInterceptor module inside the providers array in this file and this still doesn't work. Can anyone tell me why this is not working?
Thanks!
You have to construct and provide your extended class yourself like so:
ProductService,
{
provide: HttpInterceptor,
useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) =>
new HttpInterceptor(backend, defaultOptions),
deps: [XHRBackend, RequestOptions]
}
],
Also, if you want to inject another MyService in there, you can do
{
deps: [XHRBackend, RequestOptions, MyService],
provide: HttpInterceptor,
useFactory: (backend: XHRBackend, defaultOptions: RequestOptions, myService: MyService) =>
new HttpInterceptor(backend, defaultOptions, myService),
},
After that, just inject MyService in the HttpInterceptor
Part of my code:
import {Injectable} from 'angular2/core';
import {Http, Headers, Request, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class myClass {
constructor(protected http: Http) {}
public myMethod() {
let request = new Request({
method: "GET",
url: "http://my_url"
});
return this.http.request(request)
.map(res => res.json())
.catch(this.handleError); // Trouble line.
// Without this line code works perfectly.
}
public handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
myMethod() produces exception in console of browser:
ORIGINAL EXCEPTION: TypeError: this.http.request(...).map(...).catch is not a function
Perhaps you can try adding this in your imports:
import 'rxjs/add/operator/catch';
You can also do:
return this.http.request(request)
.map(res => res.json())
.subscribe(
data => console.log(data),
err => console.log(err),
() => console.log('yay')
);
Per comments:
EXCEPTION: TypeError: Observable_1.Observable.throw is not a function
Similarly, for that, you can use:
import 'rxjs/add/observable/throw';
New service updated to use the HttpClientModule and RxJS v5.5.x:
import { Injectable } from '#angular/core';
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { catchError, tap } from 'rxjs/operators';
import { SomeClassOrInterface} from './interfaces';
import 'rxjs/add/observable/throw';
#Injectable()
export class MyService {
url = 'http://my_url';
constructor(private _http:HttpClient) {}
private handleError(operation: String) {
return (err: any) => {
let errMsg = `error in ${operation}() retrieving ${this.url}`;
console.log(`${errMsg}:`, err)
if(err instanceof HttpErrorResponse) {
// you could extract more info about the error if you want, e.g.:
console.log(`status: ${err.status}, ${err.statusText}`);
// errMsg = ...
}
return Observable.throw(errMsg);
}
}
// public API
public getData() : Observable<SomeClassOrInterface> {
// HttpClient.get() returns the body of the response as an untyped JSON object.
// We specify the type as SomeClassOrInterfaceto get a typed result.
return this._http.get<SomeClassOrInterface>(this.url)
.pipe(
tap(data => console.log('server data:', data)),
catchError(this.handleError('getData'))
);
}
Old service, which uses the deprecated HttpModule:
import {Injectable} from 'angular2/core';
import {Http, Response, Request} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
//import 'rxjs/Rx'; // use this line if you want to be lazy, otherwise:
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do'; // debug
import 'rxjs/add/operator/catch';
#Injectable()
export class MyService {
constructor(private _http:Http) {}
private _serverError(err: any) {
console.log('sever error:', err); // debug
if(err instanceof Response) {
return Observable.throw(err.json().error || 'backend server error');
// if you're using lite-server, use the following line
// instead of the line above:
//return Observable.throw(err.text() || 'backend server error');
}
return Observable.throw(err || 'backend server error');
}
private _request = new Request({
method: "GET",
// change url to "./data/data.junk" to generate an error
url: "./data/data.json"
});
// public API
public getData() {
return this._http.request(this._request)
// modify file data.json to contain invalid JSON to have .json() raise an error
.map(res => res.json()) // could raise an error if invalid JSON
.do(data => console.log('server data:', data)) // debug
.catch(this._serverError);
}
}
I use .do() (now .tap()) for debugging.
When there is a server error, the body of the Response object I get from the server I'm using (lite-server) contains just text, hence the reason I use err.text() above rather than err.json().error. You may need to adjust that line for your server.
If res.json() raises an error because it could not parse the JSON data, _serverError will not get a Response object, hence the reason for the instanceof check.
In this plunker, change url to ./data/data.junk to generate an error.
Users of either service should have code that can handle the error:
#Component({
selector: 'my-app',
template: '<div>{{data}}</div>
<div>{{errorMsg}}</div>`
})
export class AppComponent {
errorMsg: string;
constructor(private _myService: MyService ) {}
ngOnInit() {
this._myService.getData()
.subscribe(
data => this.data = data,
err => this.errorMsg = <any>err
);
}
}
There are several ways to do this. Both are very simple. Each of the examples works great. You can copy it into your project and test it.
The first method is preferable, the second is a bit outdated, but so far it works too.
1) Solution 1
// File - app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpClientModule } from '#angular/common/http';
import { AppComponent } from './app.component';
import { ProductService } from './product.service';
import { ProductModule } from './product.module';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [ProductService, ProductModule],
bootstrap: [AppComponent]
})
export class AppModule { }
// File - product.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
// Importing rxjs
import 'rxjs/Rx';
import { Observable } from 'rxjs/Rx';
import { catchError, tap } from 'rxjs/operators'; // Important! Be sure to connect operators
// There may be your any object. For example, we will have a product object
import { ProductModule } from './product.module';
#Injectable()
export class ProductService{
// Initialize the properties.
constructor(private http: HttpClient, private product: ProductModule){}
// If there are no errors, then the object will be returned with the product data.
// And if there are errors, we will get into catchError and catch them.
getProducts(): Observable<ProductModule[]>{
const url = 'YOUR URL HERE';
return this.http.get<ProductModule[]>(url).pipe(
tap((data: any) => {
console.log(data);
}),
catchError((err) => {
throw 'Error in source. Details: ' + err; // Use console.log(err) for detail
})
);
}
}
2) Solution 2. It is old way but still works.
// File - app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpModule } from '#angular/http';
import { AppComponent } from './app.component';
import { ProductService } from './product.service';
import { ProductModule } from './product.module';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpModule
],
providers: [ProductService, ProductModule],
bootstrap: [AppComponent]
})
export class AppModule { }
// File - product.service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
// Importing rxjs
import 'rxjs/Rx';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class ProductService{
// Initialize the properties.
constructor(private http: Http){}
// If there are no errors, then the object will be returned with the product data.
// And if there are errors, we will to into catch section and catch error.
getProducts(){
const url = '';
return this.http.get(url).map(
(response: Response) => {
const data = response.json();
console.log(data);
return data;
}
).catch(
(error: Response) => {
console.log(error);
return Observable.throw(error);
}
);
}
}
The RxJS functions need to be specifically imported. An easy way to do this is to import all of its features with import * as Rx from "rxjs/Rx"
Then make sure to access the Observable class as Rx.Observable.
in the latest version of angular4 use
import { Observable } from 'rxjs/Rx'
it will import all the required things.