Difficulties in calling a method for an http request - http

I have an error message when I try to make an HTTP request:
"Cannot read property 'get' of undefined"
import {Component} from '#angular/core';
import {IonicPage, NavController, NavParams} from 'ionic-angular';
import {Observable} from 'rxjs/Observable';
import {HttpClient} from "#angular/common/http";
import {ContactGdzPage} from "../contact-gdz/contact-gdz";
import {ListeServicePage} from "../liste-service/liste-service";
import {ApiGdz} from "../../services/apiGdz.service";
#IonicPage()
#Component({
selector: 'page-dashboard',
templateUrl: 'dashboard.html',
})
export class DashboardPage {
constructor(private apiGdz: ApiGdz, public http: HttpClient) {
this.apiGdz.callApi().then(
(data) => {
console.log('ok', data);
},
(error) => {
console.log('!ok', error);
}
);
}
}
import {HttpClient} from "#angular/common/http";
export class ApiGdz {
public http: HttpClient;
constructor() {}
callApi() {
return new Promise(
(resolve, reject) => {
this.http.get('https://swapi.co/api/films').subscribe(
(data) => {
resolve(data);
},
(error) => {
reject(error);
}
);
}
);
}
}
import {BrowserModule} from '#angular/platform-browser';
import {ErrorHandler, NgModule} from '#angular/core';
import {IonicApp, IonicErrorHandler, IonicModule} from 'ionic-angular';
import {SplashScreen} from '#ionic-native/splash-screen';
import {StatusBar} from '#ionic-native/status-bar';
import {MyApp} from './app.component';
import {HomePage} from '../pages/home/home';
import {AuthService} from "../services/auth.service";
import {DashboardPage} from "../pages/dashboard/dashboard";
import {ConnectionPage} from "../pages/connection/connection";
import {HelpPage} from "../pages/help/help";
import {ContactGdzPage} from "../pages/contact-gdz/contact-gdz";
import {ListeServicePage} from "../pages/liste-service/liste-service";
import {ApiGdz} from "../services/apiGdz.service";
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
MyApp,
HomePage,
DashboardPage,
ConnectionPage,
HelpPage,
ContactGdzPage,
ListeServicePage,
],
imports: [
BrowserModule,
HttpClientModule,
IonicModule.forRoot(MyApp),
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
DashboardPage,
ConnectionPage,
HelpPage,
ContactGdzPage,
ListeServicePage,
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler},
AuthService,
ApiGdz,
]
})
export class AppModule {
}
The problem may be that 'HttpClient' must come from the constructor ... In this case how to instantiate the 'http' object in 'DashboardPage' with parameters?
Thanks for your help

Let me start by saying I am not an Ionic developer so there may well be something specific required for that environment that I am unaware of, I can only speak to the Angular portion of your code.
Given that, I have to make the assumption from what you have posted in your question above that in spite of how it appears, in reality you posted code from 3 DIFFERENT files. My assumption is that file #1 is the component, probably has a name like dashboard.component.ts and looks like the first part of what you posted:
import {Component} from '#angular/core';
import {IonicPage, NavController, NavParams} from 'ionic-angular';
import {Observable} from 'rxjs/Observable';
import {HttpClient} from "#angular/common/http";
import {ContactGdzPage} from "../contact-gdz/contact-gdz";
import {ListeServicePage} from "../liste-service/liste-service";
import {ApiGdz} from "../../services/apiGdz.service";
#IonicPage()
#Component({
selector: 'page-dashboard',
templateUrl: 'dashboard.html',
})
export class DashboardPage {
constructor(private apiGdz: ApiGdz, public http: HttpClient) {
this.apiGdz.callApi().then(
(data) => {
console.log('ok', data);
},
(error) => {
console.log('!ok', error);
}
);
}
}
Then there is a separate service file (which appears to be imported in the component above), is called apiGdz.service.ts, and looks like this:
import {HttpClient} from "#angular/common/http";
export class ApiGdz {
public http: HttpClient;
constructor() {}
callApi() {
return new Promise(
(resolve, reject) => {
this.http.get('https://swapi.co/api/films').subscribe(
(data) => {
resolve(data);
},
(error) => {
reject(error);
}
);
}
);
}
}
And finally you also included your base module file, probably called something like app.module.ts, which looks like this:
import {BrowserModule} from '#angular/platform-browser';
import {ErrorHandler, NgModule} from '#angular/core';
import {IonicApp, IonicErrorHandler, IonicModule} from 'ionic-angular';
import {SplashScreen} from '#ionic-native/splash-screen';
import {StatusBar} from '#ionic-native/status-bar';
import {MyApp} from './app.component';
import {HomePage} from '../pages/home/home';
import {AuthService} from "../services/auth.service";
import {DashboardPage} from "../pages/dashboard/dashboard";
import {ConnectionPage} from "../pages/connection/connection";
import {HelpPage} from "../pages/help/help";
import {ContactGdzPage} from "../pages/contact-gdz/contact-gdz";
import {ListeServicePage} from "../pages/liste-service/liste-service";
import {ApiGdz} from "../services/apiGdz.service";
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
MyApp,
HomePage,
DashboardPage,
ConnectionPage,
HelpPage,
ContactGdzPage,
ListeServicePage,
],
imports: [
BrowserModule,
HttpClientModule,
IonicModule.forRoot(MyApp),
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
DashboardPage,
ConnectionPage,
HelpPage,
ContactGdzPage,
ListeServicePage,
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler},
AuthService,
ApiGdz,
]
})
export class AppModule {
}
If all that is correct, then I would suggest a minor change to both the component and the service.
First the service. One of the benefits of using services in Angular is that they can hide details from the component such as the fact that you are getting real data from the back-end server via http. Therefore your service would look something like this:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({ providedIn: 'root' })
export class ApiGdz {
constructor(private http: HttpClient) {}
callApi() {
return new Promise(
(resolve, reject) => {
this.http.get('https://swapi.co/api/films').subscribe(
(data) => {
resolve(data);
},
(error) => {
reject(error);
}
);
}
);
}
}
Now your component can be changed to know nothing about http, just rely on the injected service to handle those details. It would now look something like this:
import {Component} from '#angular/core';
import {IonicPage, NavController, NavParams} from 'ionic-angular';
import {Observable} from 'rxjs/Observable';
// import {HttpClient} from "#angular/common/http"; // <-- DELETE THIS LINE
import {ContactGdzPage} from "../contact-gdz/contact-gdz";
import {ListeServicePage} from "../liste-service/liste-service";
import {ApiGdz} from "../../services/apiGdz.service";
#IonicPage()
#Component({
selector: 'page-dashboard',
templateUrl: 'dashboard.html',
})
export class DashboardPage {
constructor(private apiGdz: ApiGdz) {
this.apiGdz.callApi().then(
(data) => {
console.log('ok', data);
},
(error) => {
console.log('!ok', error);
}
);
}
}

Related

Firebase Storage is not working with ionic 3 & AngularFire 4.0.0 rc

Firebase Storage is not working with ionic 3 & AngularFire 4.0.0 rc .
returning with this error message.
firebase.storage() takes either no argument or a Firebase App instance
//error
TypeError: this.fb.storage is not a function
//Module
import {NgModule} from '#angular/core';
import {IonicPageModule} from 'ionic-angular';
import {ProfilePage} from './profile';
import 'firebase/storage'
#NgModule({
declarations: [
ProfilePage,
],
imports: [
IonicPageModule.forChild(ProfilePage),
],
exports: [
ProfilePage
]
})
export class ProfilePageModule {
}
//components
import {Component, Inject} from '#angular/core';
import {NavController, IonicPage} from 'ionic-angular';
import {NgForm} from "#angular/forms";
import {AngularFireAuth} from 'angularfire2/auth';
import {AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable} from 'angularfire2/database';
import * as firebase from 'firebase'; // for typings
import { FirebaseApp } from 'angularfire2';
#ionicpage()
#component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class ProfilePage {
file:any;
forUpLoadRef: FirebaseListObservable;
userRef: FirebaseObjectObservable;
storageRef:any;
constructor(public navCtrl: NavController, public af: AngularFireAuth,
public db: AngularFireDatabase, private fb: FirebaseApp) {}
UploadNewImage(){
this.file = (document.getElementById('inputFileId')).files[0];
console.log("file recived"+ JSON.stringify(this.file.name));
let storageRef = this.fb.storage().ref();
var metadata = {
contentType: 'image/*'
};
this.storageRef.child('images/'+this.file.name).put(this.file,metadata)
}
}
//error
TypeError: this.fb.storage is not a function
just add import 'firebase/storage'; in your parent module
https://github.com/angular/angularfire2/issues/1015

Injected Logger is undefined in Custom Http in angular2

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
}
],

Extending HTTP module in Angular2 throws error

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

Child routes error with RC6 upgrade

I am getting this runtime error with my routing when upgrading to RC6 (this includes child routes):
ListingComponent is not part of any NgModule or the module has not
been imported into your module
This error indicates that I have not added ListingComponent to ngModule but it is there as a declaration.
In app.module I have all my components as declarations. I also import my routing component. The routing component has a sub routing component called listing.routes.
Here is my app.module.ts:
import {NgModule, CUSTOM_ELEMENTS_SCHEMA, ReflectiveInjector } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import {FormsModule, FormBuilder} from '#angular/forms';
import { NgClass, NgStyle} from '#angular/common';
import { AppComponent } from './app.component';
import {routing} from './app.routes';
import {ListingModule} from './components/listing/listingmodule';
import {ListingComponent} from './components/listing/listing.Component';
#NgModule({
imports: [BrowserModule, routing],
providers: [],
declarations: [AppComponent, ListingComponent, ListingModule],
bootstrap: [AppComponent]
})
export class AppModule {
}
Here is my app.routes.ts (which I import as routes):
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import {ListingRoutes} from './components/listing/listing.routes';
import {SplashComponent} from './components/splash/splash.component';
export const appRoutingProviders: Routes = ([
{ path: '', component: SplashComponent },
{ path: 'login', component: SplashComponent },
...ListingRoutes
]);
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutingProviders);
And here is my listing.routes.ts:
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import {ListingModule} from './repairreturnmodule';
import {ListingComponent} from '../listing/listing.component';
export const ListingRoutes: Routes = [
{
path: '',
component: ListingModule,
children: [
{ path: 'listing', component: ListingComponent},
]
}
];
export const ListingRouting: ModuleWithProviders = RouterModule.forChild(ListingRoutes);
Have I missed anything?
EDIT: you are importing your ListingComponent from
import {ListingComponent} from './components/listing/listing.Component';
if you using the same convention from the AppComponent (which you should) you should import from
import {ListingComponent} from './components/listing/listing.component';
See what is the name of the file. The rest of the code looks right.
I'm not sure if this is the source of the problem, but you are declaring a module there in the AppModule, when you should be importing it...
Try moving the ListingModule from declarations array to the imports array.

Angular 2 Meteor change route reactively

I'm playing with angular2 and meteor (i'm new with both) and i'd like to change route if i can find a certain document in a collection. I read in the Angular 2 Meteor tutorial that the class MeteorComponent has methods subscribe and autorun so i'm trying to use this methods to get the job done (not sure if this is the best way to do it - i didn't remove autopublish).
But right now it isn't working.
My component is:
import {View, OnInit, Component} from 'angular2/core'
import {MeteorComponent} from 'angular2-meteor'
import {Navbar} from 'client/navbar/navbar'
import {FakePlayground} from 'client/intro/fake-playground/fake-playground'
import {PlayerList} from 'client/player-list/player-list'
import {PlayerService} from 'client/player/player-service'
import {Player} from 'client/player/player'
import {ProtectedDirective} from 'client/directives/protected-directive'
import {SentInvitation} from 'client/invitation/sent-invitation'
import {ReceivedInvitation} from 'client/invitation/received-invitation'
import {Invitations} from 'lib/invitations'
import {Router} from 'angular2/router'
#Component({
selector: 'intro'
})
#View({
templateUrl: 'client/intro/intro.html',
directives: [
Navbar,
PlayerList,
FakePlayground,
ProtectedDirective,
SentInvitation,
ReceivedInvitation
]
})
export class Intro extends MeteorComponent implements OnInit {
currentPlayer: Player
invitation: Mongo.Cursor<Object>
constructor(
public playerService: PlayerService,
private _router:Router
) {
super()
}
getInvitation() {
this.subscribe('invitations', () => {
this.invitation = Invitations.find({$or: [
{$and: [
{"sender._id": this.currentPlayer._id},
{status: 1}
]},
{$and: [
{"recipient._id": this.currentPlayer._id},
{status: 1}
]}
]})
this.autorun(() => {
console.log('autorun')
if(this.invitation){
console.log('game started')
this._router.navigate(['Game'])
}
})
})
}
getPlayer() {
this.currentPlayer = this.playerService.getCurrentPlayer()
}
ngOnInit() {
this.getPlayer()
this.getInvitation()
}
}
And in my fantasy getInvitation() called in ngOnInit should subscribe to
'invitations' collection and autorun() should check if the document is found and if it's found should change route.
But i'm not getting errors neither the route change.
Which should be the right way to change the route reactively to collection change?
Well, i was using this.autorun() the worng way.
It was much simpler:
import {View, OnInit, Component} from 'angular2/core'
import {MeteorComponent} from 'angular2-meteor'
import {Navbar} from 'client/navbar/navbar'
import {FakePlayground} from 'client/intro/fake-playground/fake-playground'
import {PlayerList} from 'client/player-list/player-list'
import {PlayerService} from 'client/player/player-service'
import {Player} from 'client/player/player'
import {ProtectedDirective} from 'client/directives/protected-directive'
import {SentInvitation} from 'client/invitation/sent-invitation'
import {ReceivedInvitation} from 'client/invitation/received-invitation'
import {Invitations} from 'lib/invitations'
import {Router} from 'angular2/router'
#Component({
selector: 'intro'
})
#View({
templateUrl: 'client/intro/intro.html',
directives: [
Navbar,
PlayerList,
FakePlayground,
ProtectedDirective,
SentInvitation,
ReceivedInvitation
]
})
export class Intro extends MeteorComponent implements OnInit {
currentPlayer: Player
constructor(
public playerService: PlayerService,
private _router:Router
) {
super()
}
getPlayer() {
this.currentPlayer = this.playerService.getCurrentPlayer()
}
ngOnInit() {
this.getPlayer()
this.autorun(() => {
if (Invitations.findOne({
$or: [
{$and: [{"sender._id": this.currentPlayer._id},{status: 1}]},
{$and: [{"recipient._id": this.currentPlayer._id},{status: 1}]}
]
})) {
this._router.navigate(['Game'])
}
})
}
}

Resources