Ionic 2 - Importing/Injecting Angular 2 HTTP Component - javascript

I have an ionic 2 app that I've been testing using local data. Now, I am attempting to make some Ajax requests to my api to get the data.
In my app.js file, I am defining my component like so:
import {UserProvider} from './providers/user-provider';
...
#App({
templateUrl: 'build/app.html',
providers: [UserProvider]
})
Then, my user-provider.js file is defined like so:
import {Injectable} from 'angular2/core';
import {Http, httpInjectables} from 'angular2/http';
#Injectable()
export class UserProvider {
constructor(http: Http) {
http.get('www.someURL.com').toRx().map(res => res.json())
.subscribe(data => console.log(data));
}
}
Then, lastly, I am initializing my "Sign Up" view with my signup.js file:
import {Page, NavController} from 'ionic/ionic';
import {TabsPage} from '../tabs/tabs';
import {UserProvider} from '../../providers/user-provider';
#Page({
templateUrl: 'build/pages/signup/signup.html'
})
export class SignupPage {
constructor(nav: NavController, userProvider: UserProvider) {
this.userProvider = userProvider;
this.nav = nav;
}
}
My expected result is that on initialization of my signup view, the UserProvider will be injected. As such, it's constructor will run, which will fire off the http.get function within the UserProvider's constructor. I should then see a network call in my browsers network tab.
However, I'm getting this error:
EXCEPTION: Error during instantiation of UserProvider! (SignupPage -> UserProvider)
app.bundle.js:33693 TypeError: http.get(...).toRx is not a function
at new UserProvider (app.bundle.js:60706)
Why is http.get.toRx() causing an error? I initially tried this with promises like so:
http.get('www.someURL.com').then(() => {
console.log('test');
});
but that throws a similar error.

In angular2-beta0 http.get() already returns an Observable, you don't need to call its former .toRx() method, you can just directly call .map() and such.

Related

import code from javascript file inside typescript class

I have app.js file:
var app = angular.module('app', ['kendo.directives', 'ui.router', 'app.sysSettings', 'app.globalConstants',
'pascalprecht.translate', 'ngTouch', 'ngDialog', 'ngCookies']);
And I would like to reuse this variable ("app") inside my ts file.
My app.components.ts:
import { Component, Inject } from '#angular/core';
import { UpgradeModule } from "#angular/upgrade/static";
import { app } from '../../apps/login/app';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private upgrade: UpgradeModule,
private app_private: app.name) { }
ngOnInit() {
this.upgrade.bootstrap(document.body, [this.app_private]);
}
}
I imported import { app } from '../../apps/login/app'; , then added "app" to constructor and trying to use it inside ngOnInit function but getting error :
compiler.js:486 Uncaught Error: Can't resolve all parameters for AppComponent: ([object Object], ?).
at syntaxError (compiler.js:486)
at CompileMetadataResolver.push../node_modules/#angular/compiler/esm5/compiler.js.CompileMetadataResolver._getDependenciesMetadata (compiler.js:15706)
at CompileMetadataResolver.push../node_modules/#angular/compiler/esm5/compiler.js.CompileMetadataResolver._getTypeMetadata (compiler.js:15541)
at CompileMetadataResolver.push../node_modules/#angular/compiler/esm5/compiler.js.CompileMetadataResolver.getNonNormalizedDirectiveMetadata (compiler.js:15026)
at CompileMetadataResolver.push../node_modules/#angular/compiler/esm5/compiler.js.CompileMetadataResolver._getEntryComponentMetadata (compiler.js:15854)
at compiler.js:15335
at Array.map (<anonymous>)
at CompileMetadataResolver.push../node_modules/#angular/compiler/esm5/compiler.js.CompileMetadataResolver.getNgModuleMetadata (compiler.js:15335)
at JitCompiler.push../node_modules/#angular/compiler/esm5/compiler.js.JitCompiler._loadModules (compiler.js:34413)
at JitCompiler.push../node_modules/#angular/compiler/esm5/compiler.js.JitCompiler._compileModuleAndComponents (compiler.js:34374)
Does anybody have suggestions how to make property from javascript file be accessible inside typescript class?
In order to import an object from a file, it has to be exported using the export keyword. However, your angularjs app is defined in normal javascript files outside typescript so using export is not an option. So, to have access to it from typescript, first you have to bring it to typescript level and then you will be able to import it from your component.
So you can create the following ts file to import the app to typescript:
my-angularjs-app.ts
let angular = window['angular']; // to avoid typescript syntax error
export const app = angular.module('app');
app.component.ts
Then you can use it on your module like so:
import { app } from 'my-angularjs-app';
// ...
export class AppComponent {
constructor(private upgrade: UpgradeModule) { }
ngOnInit() {
this.upgrade.bootstrap(document.body, [app.name]);
}
}
Notice, you don't have to inject it on the constructor, the value is already there.

How to handle errors of same type globally?

The Below code is only to explain the purpose of my question, and not to write a code to answer it.
page1.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { HomePage } from '../home/home';
import { AuthData } from '../../app/provider/authdata.service';
import { SignUp } from '../signup/signup';
import 'rxjs/add/operator/catch';
import { ResetPage } from '../reset/reset';
import { Push, PushToken } from '#ionic/cloud-angular';
import { Mixpanel,GoogleAnalytics } from 'ionic-native';
//import {Formsmodule} from '#angular/forms';
#Component({
selector: 'page-login',
templateUrl: 'login.html',
})
export class Login {
public email: string;
public password: string;
constructor(public nav: NavController, public authData: AuthData,public push:Push) { }
loginUser() {
this.authData.loginUser(this.email, this.password).then(
() => this.nav.setRoot(HomePage),
(error) => console.log('unable to load HomePage' + error.message));
}
doSomething(){
this.authData.doSomeWork();
}
myClick1() {
console.log('it is in SignUp');
this.nav.setRoot(SignUp);
}
}
I have a service class named authdata.service.ts, which contains a series of functions such as login, signup, do something etc.Which in turn makes a REST API calls to the server.
So, In the UI I try to make a call to any of these functions that finally makes a req to REST API, and throws back some error response(note: error response will be same for all these functions) and I want to handle that in the UI, so I put an alert controller in one of those functions, then I realise that it will be needed in other functions too.
Question1: Instead to write code in all the functions and catching them and using an alert controller is there any better way that exists, so that I can handle the same types of errors globally and write the code only once?Please suggest some references or some descriptions.
Using ionic2 as a framework.

Ionic2, Angular2, HTTP and Observables

After reading almost everything I found about observables, I still don't understand pretty well how they work.
I am doing the http request here:
import { Component, OnInit, Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { NavController } from 'ionic-angular';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
#Injectable()
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
webs: any;
getWebs(): any{
return this.http.get( 'here the url' )
.map((res: Response) => res.json());
}
constructor(public navCtrl: NavController, private http: Http) {}
ngOnInit(){
this.getWebs().subscribe(response => {
this.webs = response;
console.log(this.webs);
});
}
}
On the console, this.webs is correctly printed. That means, the get request ist working fine and I am retrieving the object I want. That is a normal JSON object.
The problem is, on the view, if I try to print some property of the object (the same properties I see on the console) like that
{{ webs.name }}
I get the whole time that error:
Error in ./HomePage class HomePage - caused by: Cannot read property 'name' of undefined
That was sooo easy with Angular 1 :( I already read a lot of tutorials but I can't find any answer to my problem.
Thanks for your help.
The view is shown before the http response is returned.
{{webs?.name}}
should work.
Or do this.webs=getWebs()
and {{webs.name | async}}
It should be something
this.getWebs().then((webs) => {
webs.subscribe(response => {
this.webs = response;
resolve(webs);
console.log(this.webs);
});
})
so after you getWebs do this.This is untested code but you get the logic.
You are calling before you get data.
ngOnInit(){
return new Promise(resolve => {
this.http.get('webs.json')
.map(res => res.json())
.subscribe(webs => {
this.webs = webs;
resolve(this.webs);
});
});
}

Angular 2 - How to pass URL parameters?

I have created a single page mortgage calculator application in Angular 2, which acts like a learning playground for me (trying to get more accustomed to technology stack currently used at work)... It's running at http://www.mortgagecalculator123.com if you want to look at it. I've made it open source with a Fork Me link right on the page if you want to look at it.
Anyhow, what I want to do, is to be able to pass variables to my app, straight from the URL, so they can be consumed by my Angular 2 app. Something like this: http://www.mortgagecalculator123.com/?var1=ABC&var2=DEF
I've tried following, in my app.component.ts, I've added following:
import { Router, ActivatedRoute, Params } from '#angular/router';
AppComponent {
private var1: string;
private var2: string;
constructor(
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
this.route.params.forEach((params: Params) => {
this.var1 = params['var1'];
this.var2 = params['var2'];
});
console.log(this.var1, this.var2);
}
...
}
But this won't work, when I run npm start, I get following error:
aot/app/app.component.ngfactory.ts(45,30): error TS2346: Supplied parameters do not match any signature of call target.
Thank you, any help would be much appreciated.
I created a pull request with the query params working. I will try to explain everything I did.
The reason why the previous answers doesn't work is because you aren't using the router at all. You created a massive app component without routes. To fix that we need to start using the route module, I also advise you to read these two tutorials: Routing and Routing & Navigation.
First we need to change your index.html, add this to your <head>:
<base href="/">
See here why it's important to add that.
Then since you are using your AppComponent to show everything we need to create a new component, which we will call RootComponent. On your index.html change <my-app> to <root>; it will look like this:
<root>Loading...</root>
Now inside your app folder we need to create two files the first one will be root.component.ts which will look like this:
import { Component } from '#angular/core';
#Component({
selector: 'root',
template: `<router-outlet></router-outlet>`,
})
export class RootComponent {
constructor() { }
}
Look that we have the <router-outlet></router-outlet> as a template, Angular will inject our components based on the route.
We still need to create one more file, which will be main.route.ts, this is what it looks like:
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
export const mainRoutes: Routes = [
{ path: '', component: AppComponent }
];
export const mainRoutingProviders: any[] = [];
export const routing = RouterModule.forRoot(mainRoutes);
In this file we are saying that for our base route, we want to render our AppComponent
We have created our new files, now we need to tell our App Module about them, in your app.module.ts so we import the new files and declare the new component. We also need to change our boostrap component:
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {FormsModule, ReactiveFormsModule} from "#angular/forms";
import {AppComponent} from './app.component';
import {RootComponent} from './root.component'; // we import our new RootComponent
import {ChartModule} from 'primeng/primeng';
import {TooltipModule} from 'primeng/primeng';
import { routing, mainRoutingProviders } from './main.routes'; // We also import our Routes
#NgModule({
imports: [
BrowserModule,
ChartModule,
FormsModule,
mainRoutingProviders, // we also need to import our route provider into the module
ReactiveFormsModule,
routing, // and also import our routes declarations
TooltipModule
],
declarations: [AppComponent, RootComponent], // we declare our new RootCpmponent
bootstrap: [RootComponent] // Notice that we are now using our RootComponent to bootstrap our app
})
export class AppModule {
}
Now with all this in place we can now finally start passing parameters to our app, on your AppComponent import the Router, ActivatedRoute and the Params from #angular/router so your AppComponent will look something like this:
import { Component, OnDestroy, OnInit } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { Subscription } from 'rxjs/Subscription';
export class AppComponent implements OnInit, OnDestroy {
private var1: string;
private var2: string;
private sub: Subscription;
constructor(
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
// assign the subscription to a variable so we can unsubscribe to prevent memory leaks
this.sub = this.route.queryParams.subscribe((params: Params) => {
this.var1 = params['var1'];
this.var2 = params['var2'];
console.log(this.var1, this.var2);
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
...
}
You can see the pull request here
It seems you are dealing with Queryparams . So to access them, you can try below code,
this.var1= this.route
.queryParams
.map(params => params['var1']);

Accessing a service in #CanActivate hook

I can't figure out a way to access a service and properly configure it's dependencies when that service is accessed from Angular's #CanActivate hook.
Before I instantiate a component I need to first check that the user is authenticated. My hook looks like:
import {AuthenticationService} from '../authentication/authentication.service';
.................
#CanActivate((next, prev) => {
var injector = Injector.resolveAndCreate([
AuthenticationService
])
var authService = injector.get(AuthenticationService);
return authService.getUser();
})
export class ShellComponent { }
The error I get is EXCEPTION: No provider for Http! (AuthenticationService -> Http). It should be noted that HTTP_PROVIDERS are injected when the application is bootstrapped.
My authentication service is the following:
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
#Injectable()
export class AuthenticationService {
constructor(private _http:Http) {}
getUser() {
var resolver = function(resolve, reject) {
setTimeout(function doneCounting() {
resolve(true);
}, 5000);
}
return new Promise<Boolean>(resolver);
}
}
Any help or insight would be appreciated.
All you need is to add this dependencies to resolveAndCreate, so your code will will be:
var injector = Injector.resolveAndCreate([HTTP_PROVIDERS, AuthenticationService])

Categories

Resources