How do use geolocation service in multiple ionic 4 pages? - geolocation

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>

Related

Angular 12. Inject service via forRoot into an external library, loaded from a module which has been lazy loaded by Compiler

I've created a library with a directive that injects a service. This library is loaded with a forRoot method in each lazy loaded component where is going to be used.
*** library.module ***
export const SERVICE_INYECTION_TOKEN: InjectionToken<any> = new InjectionToken('service')
export interface IDirectiveModuleConfig {
serviceAdapterConfiguration?: {provider: Provider, moduleName: string};
}
#NgModule({
imports: [
CommonModule
],
declarations: [DirectiveDirective],
exports: [DirectiveDirective]
})
export class LibraryModule {
public static forRoot(config: IDirectiveModuleConfig = {}): ModuleWithProviders<LibraryModule> {
console.log("Library loaded in module " + config.serviceAdapterConfiguration.moduleName)
return {
ngModule: LibraryModule,
providers: [
config.serviceAdapterConfiguration.provider
]
};
}
}
*** directive.directive ***
#Directive({
selector: '[directive]',
})
export class DirectiveDirective implements AfterViewInit {
#Input() methodName: string;
constructor(
private element: ElementRef,
private renderer: Renderer2,
#Inject(SERVICE_INYECTION_TOKEN) private service: any
) {}
ngAfterViewInit(): void {
this.element.nativeElement.innerText += this.service[this.methodName]()
this.renderer.setValue(this.element.nativeElement, this.service[this.methodName]())
}
}
In my main project, I have two lazy-loadeds modules, and each one have a component. One of this modules and its component are lazylodaded by the RouterModules. It works OK
*** app-routing.module ***
const routes: Routes = [
{
path: 'a',
loadChildren: () =>
import('./modules/module-a/module-a.module').then((m) => m.ModuleAModule),
},
{
path: 'b',
loadChildren: () =>
import('./modules/module-b/module-b.module').then((m) => m.ModuleBModule),
},
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
The other one is created by compileModuleAndAllComponentsAsync() and viewContainerRef.createComponent() in the parent component. It works ok without the service inection, but when I inject the service I get a NullInjectorError.
*** app.component ***
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
#ViewChild("viewContainerRef", { read: ViewContainerRef }) viewContainerRef: ViewContainerRef
component = null;
title = 'component-overview';
constructor(private compiler: Compiler, private injector: Injector) {}
async createModuleAndComponetC() {
const componentInjector: Injector = Injector.create({providers:[{provide:'service', useExisting: ServiceCService}]})
this.viewContainerRef.clear()
const module = (await import('./modules/module-c/module-c.module'))
.ModuleCModule;
this.compiler.compileModuleAndAllComponentsAsync(module).then((factory) => {
factory.ngModuleFactory.create(this.injector);
const componentFactory = factory.componentFactories[0]
const component: ComponentRef<any> = this.viewContainerRef.createComponent(componentFactory);
});
}
}
MODULE A (lazy loaded by routerModule working OK) with its component and service
const serviceConfig: IDirectiveModuleConfig = {
serviceAdapterConfiguration: {
provider: { provide: SERVICE_INYECTION_TOKEN, useClass: ServiceAService },
moduleName: 'A',
}
};
#NgModule({
imports: [
LibraryModule.forRoot(serviceConfig),
CommonModule,
ModuleARoutingModuleModule,
],
declarations: [ComponentAComponent],
exports: [ComponentAComponent],
})
export class ModuleAModule {
constructor(){
console.log("moduleA loaded")
}
}
#Component({
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css'],
})
export class ComponentAComponent implements OnInit {
constructor() {}
ngOnInit() {}
}
#Injectable({
providedIn: 'root'
})
export class ServiceAService {
constructor() { }
serviceA(){
return(" service A!")
}
}
MODULE C (loaded manually with compileModuleAndAllComponentsAsync() and viewContainerRef.createComponent()
export const serviceConfig: IDirectiveModuleConfig = {
serviceAdapterConfiguration: {
provider: { provide: SERVICE_INYECTION_TOKEN, useClass: ServiceCService },
moduleName: 'C',
},
};
#NgModule({
imports: [CommonModule, LibraryModule.forRoot(serviceConfig)],
declarations: [ComponentCComponent],
})
export class ModuleCModule {
constructor() {
console.log('moduleC loaded');
}
static
}
#Component({
selector: 'app-component-c',
templateUrl: './component-c.component.html',
styleUrls: ['./component-c.component.css'],
providers: [ServiceCService],
})
export class ComponentCComponent implements OnInit {
constructor() {
console.log('component C constructor');
}
ngOnInit() {
console.log('component C OnInit');
}
}
#Injectable({
providedIn: 'root',
})
export class ServiceCService {
constructor() {}
serviceC() {
return ' service C!';
}
}
In this example Modules A and B are used with router outlet, and module C is loaded with Compiler and the component is used in a *ngCompilerOutlet
I think that the problem is in the way I load my ComponentC... but I'm a little bit lost...
In adition... i've founded that the module C create a new instance each time I load this, and is not working like singleton...
stackblitz with the test project
Finally, I got success!
I saw that I could pass an injector to the viewContainerRef. CreateComponent () method. I tried with the same injector I had used to create the module in the noModuleFactory. Create () method, but it was still wrong.
Finally y realized that NgModule class exports an injector, I suposed this injector provide al the providers in this module and it works ok!!
Now my createModuleAndComponetC() is:
async createModuleAndComponetC() {
this.viewContainerRef.clear();
const module = (await import('./modules/module-c/module-c.module'))
.ModuleCModule;
this.compiler.compileModuleAndAllComponentsAsync(module).then((factory) => {
const module = factory.ngModuleFactory.create(this.injector);
const componentFactory = factory.componentFactories[0];
const component: ComponentRef<any> =
this.viewContainerRef.createComponent(
componentFactory,
0,
module.injector
);
});
}
here is the corrected stackbliz

Edit is not enabled for custom datepicker control in angular

I created an angular material custom date picker control, it is working and able select and update the date but when I tried to edit the input box it was not allowed. always it is readonly
Below is the code for reference. Can someone suggest this?
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '#angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor} from '#angular/forms';
import { MatDatepickerInputEvent } from '#angular/material/datepicker';
import { formatDate } from '#angular/common';
import { DateAdapter, MAT_DATE_FORMATS, NativeDateAdapter } from '#angular/material/core';
type Value=number;
export const PICK_FORMATS = {
parse: {dateInput: {month: 'short', year: 'numeric', day: 'numeric'}},
display: {
dateInput: 'input',
monthYearLabel: {year: 'numeric', month: 'short'},
dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
monthYearA11yLabel: {year: 'numeric', month: 'long'}
}
};
class PickDateAdapter extends NativeDateAdapter {
format(date: Date, displayFormat: Object): string {
if (displayFormat === 'input') {
return formatDate(date,'MM/dd/yyyy',this.locale);;
} else {
return date.toDateString();
}
}
}
#Component({
selector: 'app-date',
templateUrl: './date.component.html',
styleUrls: ['./date.component.css'],
providers:[
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(()=>DateComponent),
multi:true
},
{provide: DateAdapter, useClass: PickDateAdapter},
{provide: MAT_DATE_FORMATS, useValue: PICK_FORMATS}
]
})
export class DateComponent implements OnInit,ControlValueAccessor {
value: Value;
isDisable:boolean;
#Input() placeholder:string;
#Input() min: Date;
#Input() max:Date;
#Output() changed = new EventEmitter<Value>();
constructor() { }
ngOnInit(): void {
}
get inputValue():Date{
return this.value ? new Date(this.value):null;
}
private propagateChange: any = () =>{ };
private propagateTouched: any = () =>{ };
writeValue(value: Value): void {
this.value=value
}
registerOnChange(fn: any): void {
this.propagateChange=fn;
}
registerOnTouched(fn: any): void {
this.propagateTouched=fn;
}
setDisabledState(isDisabled: boolean): void {
this.isDisable=isDisabled;
}
onChanged( event:MatDatepickerInputEvent<Date>):void{
const value=event.value ? event.value.getTime():null;
this.value=value;
this.propagateChange(value);
this.changed.emit(value);
}
OnClosed():void{
this.propagateTouched();
}
}
// Custome Control HTML
<div>
<input type="text"
[matDatepicker]="picker"
(dateChange)="onChanged($event)"
(click)="picker.open()"
[attr.disabled]="isDisable ? true : null"
[value]="inputValue" [min]="min" [max]="max"
placeholder="{{placeholder || 'Choose a date '}}"
>
<mat-datepicker-toggle matSuffix [for]="picker" [disabled]="isDisable"></mat-datepicker-toggle>
<mat-datepicker #picker (closed)="OnClosed()"></mat-datepicker>
</div>
//custom field
<app-date formControlName="Activedate" placeholder="Date" ></app-date>
I created an angular material custom date picker control, it is working and able select and update the date but when I tried to edit the input box it was not allowed. always it is readonly
Below is the code for reference. Can someone suggest this?
Thanks in advance

Custom mat-radio-group in Angular 12 not working?

I have problem when custom using mat-radio-group and mat-radio-button in Angular 12.
I have my-radio-group that wrap mat-radio-group and some my-radio-button as the ContentChildrens,
my-radio-button component wrap mat-radio-button.
But i cannot use ngModel to binding and handle change event when select radio.
It used to work well in Angular 7 before.
Can anyone help me this issue?
Sorry if my english is not quite good,
Thank you so much :)
My code here:
app.component.ts
_selection: any = 1;
get selection() {
return this._selection;
}
set selection(val: any) {
this._selection = val;
}
onChange($event: any): void {
}
app.component.html:
<my-radio-group [(ngModel)]="selection" (change)="onChange($event)">
<br/>
<my-radio-button [value]="1">Radio 1</my-radio-button>
<br/>
<my-radio-button [value]="2">Radio 2</my-radio-button>
<br/>
<my-radio-button [value]="3">Radio 3</my-radio-button>
<br/>
<my-radio-button [value]="4">Radio 4</my-radio-button>
</my-radio-group>
my-radio-group.component.ts:
export const MY_RADIO_GROUP_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MyRadioGroupComponent),
multi: true
};
#Directive({
selector: "my-radio-group",
providers: [
MY_RADIO_GROUP_CONTROL_VALUE_ACCESSOR,
{provide: MatRadioGroup, useExisting: MyRadioGroupComponent}
]
})
export class MyRadioGroupComponent extends MatRadioGroup {
}
my-radio-button.component.ts
#Component({
selector: "my-radio-button",
templateUrl: "./my-radio-button.component.html"
})
export class MyRadioButtonComponent {
#Input() value: any;
#Input() disabled: boolean | undefined;
}
my-radio-button.component.html
<mat-radio-button [value]="value" [disabled]="disabled">
<ng-content></ng-content>
</mat-radio-button>

NullInjectorError: No provider for HttpClient! Angular 5

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.

how to route parameters latitude and longitude from google autocomplete place angular 2?

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.

Resources