Since yesterday, I'm stuck with an issue and I don't find anything to help me T.T
I'm working on an Angular 8 with Ionic 5 app for Android. I just want to make a POST request to an API. Yep, that's all ^^
I have a register.page.html with a register form, then on submit it calls the submitForm() function in register.page.ts.
This function calls the registerUser() function in user.service.ts. This is where I make the POST request to my API.
But everything goes wrong, and all I got is an error values is null in my console. The request is never send, and when I console.log my variables, everything seems fine.
Here are the files.
register.page.html:
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>Créer un compte</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form (ngSubmit)="submitForm()">
<ion-item lines="full">
<ion-label position="floating">Nom d'utilisateur</ion-label>
<ion-input [(ngModel)]="user.username" name="username" type="text" required></ion-input>
</ion-item>
<ion-item lines="full">
<ion-label position="floating">Email</ion-label>
<ion-input [(ngModel)]="user.email" name="email" type="email" required></ion-input>
</ion-item>
<ion-item lines="full">
<ion-label position="floating">Mot de passe</ion-label>
<ion-input [(ngModel)]="user.password" name="password" type="password" required></ion-input>
</ion-item>
<ion-row>
<ion-col>
<ion-button type="submit" color="danger" expand="block">Créer un compte</ion-button>
</ion-col>
</ion-row>
</form>
</ion-content>
register.page.ts:
import {Component, OnInit} from '#angular/core';
import {UserService} from '../services/user.service';
import {User} from '../classes/user';
#Component({
selector: 'app-register',
templateUrl: './register.page.html',
styleUrls: ['./register.page.scss'],
})
export class RegisterPage implements OnInit {
user: User;
constructor(
private userService: UserService,
) {
this.user = new User();
}
ngOnInit() {
}
submitForm(): void {
this.userService.registerUser(this.user)
.subscribe(res => {
console.log(res);
}, err => {
console.error(err);
});
}
}
user.service.ts:
import {Injectable} from '#angular/core';
import {User} from '../classes/user';
import {ApiService} from './api.service';
import {HttpClient} from '#angular/common/http';
import {catchError, retry} from 'rxjs/operators';
import {Observable} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class UserService {
currentUser: User;
constructor(
private http: HttpClient,
private apiService: ApiService
) {
}
registerUser(user: User): Observable<any> {
return this.http
.post<any>(this.apiService.apiUrl + '/users', user, this.apiService.httpOptions)
.pipe(
retry(3),
catchError(this.apiService.handleError)
);
}
}
api.service.ts:
import {Injectable} from '#angular/core';
import {HttpHeaders} from '#angular/common/http';
import {Observable, throwError} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ApiService {
apiUrl = 'http://127.0.0.1:3000/api/v1';
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: null,
})
};
token = null;
constructor() {
}
handleError(error): Observable<never> {
let errorMessage = '';
if (error.error instanceof ErrorEvent) {
errorMessage = error.error.message;
} else {
errorMessage = 'Error code: ' + error.status + '\nMessage: ' + error.message;
}
return throwError(errorMessage);
}
}
app.module.ts:
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {RouteReuseStrategy} from '#angular/router';
import {IonicModule, IonicRouteStrategy} from '#ionic/angular';
import {SplashScreen} from '#ionic-native/splash-screen/ngx';
import {StatusBar} from '#ionic-native/status-bar/ngx';
import {AppComponent} from './app.component';
import {AppRoutingModule} from './app-routing.module';
import {HttpClientModule} from '#angular/common/http';
#NgModule({
declarations: [
AppComponent,
],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
HttpClientModule,
],
providers: [
StatusBar,
SplashScreen,
{
provide: RouteReuseStrategy,
useClass: IonicRouteStrategy,
},
],
bootstrap: [
AppComponent,
],
})
export class AppModule {
}
I don't understand why it doesn't works... If you have any idea, I really appreciate your help!
Thanks!
Finally got it!
In api.service.ts, one header was initialized with a null value like this:
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: null, // The bad guy.
})
};
I have to change it with an empty value:
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: '', // The good guy.
})
};
Related
I have built a geolocation service that I wish to use the getUserPosition() method on the home.page
location.service.ts
import { Injectable } from '#angular/core';
import { Geolocation, GeolocationOptions, Geoposition, PositionError } from '#ionic-native/geolocation/ngx';
#Injectable({
providedIn: 'root'
})
export class LocationService {
options: GeolocationOptions;
currentPos: Geoposition;
loc: any;
constructor( private geolocation: Geolocation ) { }
getUserPosition() {
return new Promise((resolve, reject) => {
this.options = {
maximumAge: 3000,
enableHighAccuracy: true
};
this.geolocation.getCurrentPosition(this.options).then((pos: Geoposition) => {
this.currentPos = pos;
const location = {
lat: pos.coords.latitude,
lng: pos.coords.longitude,
time: new Date(),
};
console.log('loc', location);
resolve(pos);
}, (err: PositionError) => {
console.log("error : " + err.message);
reject(err.message);
});
});
}
}
I access the service in my home.page
home.ts
import { Component, OnInit } from '#angular/core';
import { LocationService } from '../../services/geolocation/location.service';
#Component({
selector: 'app-home',
templateUrl: './home.page.html',
styleUrls: ['./home.page.scss'],
})
export class WorkalonePage implements OnInit {
getPosition: any;
constructor(
private LocationService: LocationService
) {}
ngOnInit() {
this.getPosition = this.LocationService.getUserPosition;
}
}
home.html
<ion-content>
<ion-button expand="full" color="primary" (click)="getUserPosition()">Get Location Sevice</ion-button>
</ion-content>
but when I click on (click)="getUserPosition()" on my html I get the error getUserPosition() is not a function. I have have been looking online for answers, but all answers involve using the geolocation in the home.ts file. Any help would be greatly appreciated.
From what I see in home.ts, you haven't defined a function named getUserPosition.
Add something along the lines of what's below to home.ts:
getUserPosition() {
this.LocationService.getUserPosition().then((pos) => {
this.getPosition = pos;
});
}
You can directly call your service method in html like this
LocationService.ts
getUserPosition() {
this.LocationService.getUserPosition().then((pos) => {
this.getPosition = pos;
});
}
Define service object in home.ts
constructor(public ls:LocationService){}
At home.html
<ion-button expand="full" color="primary" (click)="ls.getUserPosition()">
Get Location Sevice
</ion-button>
I have an Angular app that contains a load button. When you click the load button it renders a remote UMD library.
The first time I click the load button I have the following error while importing my library using SystemJS:
core.js:15714 ERROR Error: Uncaught (in promise): TypeError: Cannot read property '__source' of undefined
TypeError: Cannot read property '__source' of undefined
at StaticInjector.push../node_modules/#angular/core/fesm5/core.js.StaticInjector.get (core.js:8984)
when I click a second time, no errors and the library renders correctly.
I narrowed the issue to this statement in my code:
export class PostService {
constructor(private httpClient: HttpClient) { }
If I remove the httpClient service, the library loads correctly but I don't have access to the HttpClient.
If anyone has an idea why my code behaves that way it would be greatly appreciated!
Here is my setup below:
I have the following components im my remote library:
sample-pack-lib.component
|_db2-chart2.component
|_post.service
The library 'samplePack-lib' is compiled with 'ng build samplePack-lib' and I exposed the following output through an express server:
dist/sample-pack-lib/sample-pack-lib.umd.js
db2-chart2.component.ts:
import { Component, ElementRef, ViewChild, AfterViewInit, OnInit } from '#angular/core';
import * as vis from 'vis';
import { Graph2d, PointItem } from 'vis';
import { PostService } from '../services/post.service';
#Component({
selector: 'izoa-db2-chart2',
templateUrl: './db2-chart2.component.html',
styleUrls: ['./db2-chart2.component.scss']
})
export class Db2Chart2Component implements OnInit {
#ViewChild('vizchart') vizchart: ElementRef;
data: Row[] = [];
constructor(private postService: PostService) { }
post.service.ts:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class PostService {
constructor(private httpClient: HttpClient) { }
sample-pack-lib.module.ts:
import { NgModule } from '#angular/core';
import { SamplePackLibComponent } from './sample-pack-lib.component';
import { Db2Chart2Component } from './db2-chart2/db2-chart2.component';
import { Db2Chart1Component } from './db2-chart1/db2-chart1.component';
// import { HttpClientModule } from '#angular/common/http';
import {
MatButtonModule,
MatCardModule,
MatMenuModule,
MatToolbarModule,
MatIconModule,
MatSidenavModule,
MatGridListModule,
MatListModule
} from '#angular/material';
#NgModule({
declarations: [
Db2Chart2Component,
SamplePackLibComponent,
Db2Chart1Component
],
imports: [
// HttpClientModule,
MatButtonModule,
MatMenuModule,
MatCardModule,
MatToolbarModule,
MatIconModule,
MatSidenavModule,
MatGridListModule,
MatListModule
],
exports: [
SamplePackLibComponent,
Db2Chart2Component,
Db2Chart1Component
]
})
export class SamplePackLibModule { }
public-api.ts
import { NgModule } from '#angular/core';
import { SamplePackLibComponent } from './sample-pack-lib.component';
import { Db2Chart2Component } from './db2-chart2/db2-chart2.component';
import { Db2Chart1Component } from './db2-chart1/db2-chart1.component';
// import { PostService } from './services/post.service';
// import { HttpClientModule } from '#angular/common/http';
import {
MatButtonModule,
MatCardModule,
MatMenuModule,
MatToolbarModule,
MatIconModule,
MatSidenavModule,
MatGridListModule,
MatListModule
} from '#angular/material';
#NgModule({
declarations: [
Db2Chart2Component,
SamplePackLibComponent,
Db2Chart1Component
],
// providers: [PostService],
imports: [
// HttpClientModule,
MatButtonModule,
MatMenuModule,
MatCardModule,
MatToolbarModule,
MatIconModule,
MatSidenavModule,
MatGridListModule,
MatListModule
],
exports: [
SamplePackLibComponent,
Db2Chart2Component,
Db2Chart1Component
]
})
export class SamplePackLibModule { }
package.json:
{
"name": "sample-pack-lib",
"version": "0.0.1",
"dependencies": {
},
"peerDependencies": {
"#angular/common": "^7.2.0",
"#angular/core": "^7.2.0",
"#angular/material": "7.3.0"
}
}
The main app:
#Component({
selector: 'app-admin',
template: '<button (click)="load()">Load</button><ng-container #vc></ng-container>',
styleUrls: ['./admin.component.scss']
})
export class AdminComponent {
#ViewChild('vc', { read: ViewContainerRef }) vc: ViewContainerRef;
private cfr: any;
constructor(public compiler: Compiler, private injector: Injector, private r: ComponentFactoryResolver) { }
load() {
// register the modules that we already loaded so that no HTTP request is made
// in my case, the modules are already available in my bundle (bundled by webpack)
SystemJS.set('#angular/core', SystemJS.newModule(AngularCore));
SystemJS.set('#angular/common', SystemJS.newModule(AngularCommon));
SystemJS.set('#angular/material',SystemJS.newModule(AngularMaterial));
SystemJS.set('#angular/router', SystemJS.newModule(AngularRouter));
SystemJS.set('vis', SystemJS.newModule(Vis));
SystemJS.set('#angular/common/http', SystemJS.newModule(HttpClientModule));
const url = '../bundles/sample-pack-lib.umd.js';
SystemJS.import(url).then((module) => {
this.compiler.compileModuleAndAllComponentsAsync(module['SamplePackLibModule'])
.then((moduleFactory) => {
const moduleRef = moduleFactory.ngModuleFactory.create(this.injector);
const factory = moduleFactory.componentFactories.find(
item => item.componentType.name === 'SamplePackLibComponent');
if (factory) {
const component = this.vc.createComponent(factory);
const instance = component.instance;
}
});
});
The problem was with the HttpCLientModule.
Previously I imported it that way:
import { HttpClientModule } from '#angular/common/http';
It should be:
import * as HttpClientModule from '#angular/common/http';
I get an error while running npm test
Can't bind to 'errorStateMatcher' since it isn't a known property of 'input'. ("dth">
<input matInput placeholder="Product Name" formControlName="prod_name"
[ERROR ->][errorStateMatcher]="matcher">
My Spec file is as follows
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import { ReactiveFormsModule } from '#angular/forms';
import { ProductAddComponent } from './product-add.component';
import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from '#angular/forms';
describe('ProductAddComponent', () => {
let component: ProductAddComponent;
let fixture: ComponentFixture<ProductAddComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, ReactiveFormsModule],
declarations: [ ProductAddComponent ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProductAddComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
How do I provide errorStateMatcher to test unit?
I think you need to import MatInputModule.
I had to add matInput attribute to the input element.
If You are getting this error while testing make sure you mock matInput aswell. That was my Issue. I imported MatInputModule in spec file, but that caused more errors later.
I, am using the Angular template in visual studio 2017. Then I updated to angular 5.2. I, tried to find the solution. But didn't got exact solution.
The service class is calling the http call.However I, am getting an error as
Service.TS
import { Injectable } from '#angular/core';
import { LoginViewModel as loginVM } from "../../viewmodel/app.viewmodel"
import { HttpClient, HttpHeaders } from "#angular/common/http";
#Injectable()
export class LoginService {
private loginUrl = "Account/Authentication";
private _httpClientModule: HttpClient;
constructor(httpClientModule: HttpClient) {
this._httpClientModule = httpClientModule;
}
public LoginHttpCall(_loginVM: loginVM) {
const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8');
this._httpClientModule.post(this.loginUrl, _loginVM, { headers }).
subscribe(data => {
console.log(data);
},
err => {
console.log("Error occured.");
});
}
}
Here is my Component class
import { Component } from '#angular/core';
import { AppComponent } from "../app/app.component";
import { LoginService } from "../../service/account/app.service.account.login";
import { LoginViewModel } from "../../viewmodel/app.viewmodel";
declare var componentHandler: any;
#Component({
selector: 'login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
providers: [LoginViewModel, LoginService]
})
export class LoginComponent {
private _appComponent: AppComponent;
private _loginService: LoginService;
constructor(private appComponent: AppComponent, loginService: LoginService) {
this._appComponent = appComponent;
this._appComponent.menulist = false;
this._loginService = loginService;
}
}
app.shared.module.ts
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { RouterModule } from '#angular/router';
import { AppComponent } from './components/app/app.component';
import { HomeComponent } from './components/home/home.component';
import { LoginComponent } from './components/login/login.component';
import { MobileComponent } from './components/mobile/mobile.component';
#NgModule({
declarations: [
AppComponent,
HomeComponent,
LoginComponent,
MobileComponent
],
imports: [
CommonModule,
HttpModule,
FormsModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'mobile', component: MobileComponent },
{ path: '**', redirectTo: 'home' }
])
]
})
export class AppModuleShared {
}
I, don't know where I, am doing mistake. Since I , am new in angular. I tried to add HttpClient under #NgModule but gives some other error . Since As per my knowledge I don't need to add in app.shared.module.ts file. Since HttpClient is used in service and component level.
Can anyone please tell me where I, am doing wrong .
HttpClient needs for the module HttpClientModule instead of HttpModule to be imported and added in the imports of the module.
For more see Documentation
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
...
],
imports: [
...
HttpClientModule,
...
]
})
export class AppModuleShared { }
npm clear cache
npm update
rm -rf /node_modules
npm i --save
Then import same module into app root module.
Hope it works for you.
I'm using angular 2 and in this part (home page) I have a google autocomplete place input that if you click it goes another page(map) and it shows the map with that latitude and longitude user clicked previous page. However the point is I want in the URL, lat and long will be shown.It's complicated for me and don't know what to do,also I have read https://angular.io/tutorial/toh-pt5#parameterized-route but didn't understand.
app-routing.module:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { HomeComponent } from './home/home.component';
import { MapComponent } from './search/map.component';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'map/'+this.latitude+','+this.longitude, component:
MapComponent },
];
#NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
in the path I wrote like this but don't know is correct or not.
home.html:
<div class="col-md-8 col-md-push-2 container search-location">
<div class="form-group">
<input id="search" placeholder="select place"
autocorrect="off" autocapitalize="off" spellcheck="off" type="text"
class="form-control"
#search [formControl]="searchControl">
</div>
</div>
home.component.ts:
import { Component, ElementRef, NgModule, NgZone, OnInit, ViewChild } from
'#angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from
"#angular/forms";
import { BrowserModule } from "#angular/platform-browser";
import { AgmCoreModule, MapsAPILoader } from '#agm/core';
import { Router } from '#angular/router';
import {} from '#types/googlemaps';
declare let google: any;
import 'rxjs/add/observable/of';
#Component({
selector: 'home-search',
templateUrl: './home-search.html',
styles: [`
agm-map {
height: 300px;
}
`],
})
export class HomeSearchComponent implements OnInit {
public google:any;
public latitude: number;
public longitude: number;
public searchControl: FormControl;
public zoom: number;
#ViewChild("search")
public searchElementRef: ElementRef;
constructor(
private mapsAPILoader: MapsAPILoader,
private ngZone: NgZone,
private router:Router,
) {}
ngOnInit() {
let options = {
types: ["address"],
componentRestrictions: {country: "ir"}
};
//set google maps defaults
this.zoom = 4;
this.latitude = 39.8282;
this.longitude = -98.5795;
//create search FormControl
this.searchControl = new FormControl();
//set current position
this.setCurrentPosition();
//load Places Autocomplete
this.mapsAPILoader.load().then(() => {
let autocomplete = new
google.maps.places.Autocomplete(this.searchElementRef.nativeElement,
{options});
autocomplete.addListener("place_changed", () => {
this.ngZone.run(() => {
//get the place result
let place: google.maps.places.PlaceResult = autocomplete.getPlace();
//verify result
if (place.geometry === undefined || place.geometry === null) {
return;
}
//set latitude, longitude and zoom
this.latitude = place.geometry.location.lat();
this.longitude = place.geometry.location.lng();
this.zoom = 12;
this.router.navigate(['/map/'+this.latitude+','+this.longitude]);
});
});
});
}
private setCurrentPosition() {
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
this.zoom = 12;
});
}
}
}
map.html:
<div class="col-md-8 col-md-push-2 container search-location">
<agm-map [latitude]="latitude" [longitude]="longitude" [scrollwheel]="true"
[zoom]="zoom">
<agm-marker [latitude]="latitude" [longitude]="longitude"></agm-marker>
</agm-map>
</div>
map.component.ts:
import { Component, ElementRef, NgModule, NgZone, OnInit, ViewChild } from
'#angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from
"#angular/forms";
import { BrowserModule } from "#angular/platform-browser";
import { AgmCoreModule, MapsAPILoader } from '#agm/core';
import { Router } from '#angular/router';
import {} from '#types/googlemaps';
declare let google: any;
#Component({
selector: 'map',
templateUrl: './map.html',
styles: [`
agm-map {
height: 300px;
}
`],
})
export class MapComponent implements OnInit{
private google:any;
private latitude: number;
private longitude: number;
private searchControl: FormControl;
private zoom: number;
ngOnInit(){
}
}
It relates to parameters but I don't know how to write the code.
Could you please help me,I'm confused.
Thank you.