setting google map API key from angular 2 service - google-maps

Im using sebastine google map in angular 2 application. I know AgmCoreModule.forRoot({ apiKey: "xxxxxxxx" }) can be used to set API key but I need to set API key from a angular service in my #component is it possible....help needed.

You may need to update provide a custom provider like this { provide: MapsAPILoader, useClass: CustomLazyAPIKeyLoader } where you have imported AgmCoreModule.
And in CustomLazyAPIKeyLoader class override the load method.
import { Injectable, Inject } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { MapsAPILoader, LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral, GoogleMapsScriptProtocol } from 'angular2-google-maps/core';
import { DocumentRef, WindowRef } from 'angular2-google-maps/core/utils/browser-globals';
#Injectable()
export class CustomLazyAPIKeyLoader extends MapsAPILoader {
private _scriptLoadingPromise: Promise<void>;
private _config: LazyMapsAPILoaderConfigLiteral;
private _windowRef: WindowRef;
private _documentRef: DocumentRef;
constructor( #Inject(LAZY_MAPS_API_CONFIG) config: any, w: WindowRef, d: DocumentRef, private http: Http) {
super();
this._config = config || {};
this._windowRef = w;
this._documentRef = d;
}
load(): Promise<void> {
if (this._scriptLoadingPromise) {
return this._scriptLoadingPromise;
}
const script = this._documentRef.getNativeDocument().createElement('script');
script.type = 'text/javascript';
script.async = true;
script.defer = true;
const callbackName: string = `angular2GoogleMapsLazyMapsAPILoader`;
this.http.get("getKey")
.subscribe((res: any) => {
this._config.apiKey = res._body;
script.src = this._getScriptSrc(callbackName);
this._documentRef.getNativeDocument().body.appendChild(script);
});
this._scriptLoadingPromise = new Promise<void>((resolve: Function, reject: Function) => {
(<any>this._windowRef.getNativeWindow())[callbackName] = () => { console.log("loaded"); resolve(); };
script.onerror = (error: Event) => { reject(error); };
});
return this._scriptLoadingPromise;
}
private _getScriptSrc(callbackName: string): string {
let protocolType: GoogleMapsScriptProtocol =
(this._config && this._config.protocol) || GoogleMapsScriptProtocol.HTTPS;
let protocol: string;
switch (protocolType) {
case GoogleMapsScriptProtocol.AUTO:
protocol = '';
break;
case GoogleMapsScriptProtocol.HTTP:
protocol = 'http:';
break;
case GoogleMapsScriptProtocol.HTTPS:
protocol = 'https:';
break;
}
const hostAndPath: string = this._config.hostAndPath || 'maps.googleapis.com/maps/api/js';
const queryParams: { [key: string]: string | Array<string> } = {
v: this._config.apiVersion || '3',
callback: callbackName,
key: this._config.apiKey,
client: this._config.clientId,
channel: this._config.channel,
libraries: this._config.libraries,
region: this._config.region,
language: this._config.language
};
const params: string =
Object.keys(queryParams)
.filter((k: string) => queryParams[k] != null)
.filter((k: string) => {
// remove empty arrays
return !Array.isArray(queryParams[k]) ||
(Array.isArray(queryParams[k]) && queryParams[k].length > 0);
})
.map((k: string) => {
// join arrays as comma seperated strings
let i = queryParams[k];
if (Array.isArray(i)) {
return { key: k, value: i.join(',') };
}
return { key: k, value: queryParams[k] };
})
.map((entry: { key: string, value: string }) => { return `${entry.key}=${entry.value}`; })
.join('&');
return `${protocol}//${hostAndPath}?${params}`;
}
}
this.http.get("getKey")
.subscribe((res: any) => {
this._config.apiKey = res._body;
script.src = this._getScriptSrc(callbackName);
this._documentRef.getNativeDocument().body.appendChild(script);
});
Above code will make it async.

I added an resolver to get the API key
import { Resolve, ActivatedRouteSnapshot } from '#angular/router'
import { Injectable, Inject } from '#angular/core'
import { SomeService } from '../services/some.service'
import { LazyMapsAPILoaderConfigLiteral, LAZY_MAPS_API_CONFIG } from '#agm/core'
import { Observable, of } from 'rxjs'
import { map, catchError } from 'rxjs/operators'
#Injectable()
export class GoogleMapAPiResolver implements Resolve<boolean> {
constructor(
private someService: SomeService,
#Inject(LAZY_MAPS_API_CONFIG)
private config: LazyMapsAPILoaderConfigLiteral
) {}
resolve(router: ActivatedRouteSnapshot): Observable<boolean> {
return this.someService.getGoogleMapApiKey().pipe(
catchError(error => {
return of(false)
}),
map(response => {
this.config.apiKey = response
return true
})
)
}
}
The SomeService consume an endpoint that return the Key

you have put the API key in the app.module.ts under the #NgModule
and make sure to enable Maps JavaScript API in the google cloud console
https://console.cloud.google.com/apis/library/maps-backend.googleapis.com
Thanks!
#NgModule({
imports: [
BrowserModule,
FormsModule,
AgmCoreModule.forRoot({
// please get your own API key here:
// https://developers.google.com/maps/documentation/javascript/get-api-key?hl=en
apiKey: 'API_KEY'
})
],
declarations: [ AppComponent, HelloComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }

Related

how to resolve problem whem import repository in nestjs

im new in nestjs and i have one problem when i try to export my custom Repository, i dont any idea about how to resolve it.
gas-station.repository.ts i create custom repository:
#Injectable()
class GasStationRepository implements IGasStationRepository {
constructor(
#InjectRepository(GasStation)
private readonly gasStationRepository: Repository<GasStation>,
) {}
//...
public async createGasStation(
gasStationDto: ICreateGasStationDto,
): Promise<GasStation> {
const gasStation = this.gasStationRepository.create(gasStationDto);
await this.gasStationRepository.save(gasStation);
return gasStation;
}
public async bulkCreateGasStation(
gasStations: ICreateGasStationDto[],
): Promise<GasStation[]> {
return Promise.all(gasStations.map(this.createGasStation));
}
}
export default GasStationRepository;
gas-station.module.ts i thin it is normal formule to export my repository:
#Module({
imports: [TypeOrmModule.forFeature([GasStation])],
controllers: [GasStationController],
providers: [
GasStationService,
{
useClass: GasStationRepository,
provide: GAS_STATION_REPOSITORY,
},
],
exports: [
{
useClass: GasStationRepository,
provide: GAS_STATION_REPOSITORY,
},
],
})
export class GasStationModule {}
user.module.ts i import gasStationModule for use repository
#Module({
imports: [TypeOrmModule.forFeature([User]), GasStationModule],
controllers: [UserController],
providers: [
UserService,
{
useClass: UserRepository,
provide: USER_REPOSITORY,
},
],
})
export class UserModule {}
user.service.ts i will use repository :
#Injectable()
export class UserService {
constructor(
#Inject(USER_REPOSITORY) private readonly userRepository: IUserRepository,
#Inject(GAS_STATION_REPOSITORY)
private readonly gasStationRepository: IGasStationRepository,
) {}
async create(createUserDto: CreateUserDto) {
const {
type,
branches,
gasStations,
email,
password,
...props
} = createUserDto;
const existedUser = await this.userRepository.findByEmail(email);
if (existedUser) {
throw new BadRequestException('Usuário já cadastrado');
}
let gasStationList: ICreateGasStationDto[] = [];
let branchList: ICreateBranchDto[] = [];
if (type === 1 && gasStations && gasStations.length > 0) {
gasStationList = await this.gasStationRepository.bulkCreateGasStation(
gasStations,
);
} else if (type === 2 && branches && branches.length > 0) {
branchList = [];
}
const hashedPassword = await hash(password, 8);
const user = await this.userRepository.createUser({
type,
email,
password: hashedPassword,
...(branchList.length > 0 && { branches: branchList }),
...(gasStationList.length > 0 && { gasStations: gasStationList }),
...props,
active: false,
} as ICreateUserDto);
delete user.password;
return user;
}
//...
}
ERROR:
TypeError: Cannot read property 'gasStationRepository' of undefined
at createGasStation (/media/michelkuguio/Novo volume/easypetro/nest/epetro/dist/modules/gas-station/gas-station.repository.js:30:33)
at Array.map (<anonymous>)
at GasStationRepository.bulkCreateGasStation (/media/michelkuguio/Novo volume/easypetro/nest/epetro/dist/modules/gas-station/gas-station.repository.js:35:40)
at UserService.create (/media/michelkuguio/Novo volume/easypetro/nest/epetro/dist/modules/user/user.service.js:45:62)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async /media/michelkuguio/Novo volume/easypetro/nest/epetro/node_modules/#nestjs/core/router/router-execution-context.js:46:28
at async /media/michelkuguio/Novo volume/easypetro/nest/epetro/node_modules/#nestjs/core/router/router-proxy.js:9:17
[Nest] 9228 - 19/04/2021 08:42:22 [HttpExceptionFilter] Http Status: 500 Error Message: {} +13880ms
The issue is in your bulkCreateGassStation method. gasStations.map(this.createGasStations) doesn't preserve the context where it is called from. You can either .bind(this) and set the context to be properly bound, or you can gasStations.map(station => this.createStations(station))

Type 'Observable<DataListeItem[]>' is not assignable to type 'DataListeItem[]'

Full error message:
"Type 'Observable' is not assignable to type 'DataListeItem[]'.
Property 'includes' is missing in type 'Observable'."
I'm using material Table Schematic and now I want to fill the list from my Rest service.
data-liste-datasource.ts
import { DataSource } from '#angular/cdk/collections';
import { MatPaginator, MatSort } from '#angular/material';
import { map } from 'rxjs/operators';
import { Observable, of as observableOf, merge } from 'rxjs';
import { AuthService } from '../auth.service';
export interface DataListeItem {
name: string;
id: number;
email: string;
number: number;
}
export class DataListeDataSource extends DataSource<DataListeItem> {
data: DataListeItem[] = this.authservice.GetUser(); <-- error here!
constructor(private paginator: MatPaginator, private sort: MatSort, private authservice: AuthService) {
super();
}
connect(): Observable<DataListeItem[]> {
const dataMutations = [
observableOf(this.data),
this.paginator.page,
this.sort.sortChange
];
this.paginator.length = this.data.length;
return merge(...dataMutations).pipe(map(() => {
return this.getPagedData(this.getSortedData([...this.data]));
}));
}
disconnect() { }
private getPagedData(data: DataListeItem[]) {
const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
return data.splice(startIndex, this.paginator.pageSize);
}
private getSortedData(data: DataListeItem[]) {
if (!this.sort.active || this.sort.direction === '') {
return data;
}
return data.sort((a, b) => {
const isAsc = this.sort.direction === 'asc';
switch (this.sort.active) {
case 'name': return compare(a.name, b.name, isAsc);
case 'email': return compare(a.email, b.email, isAsc);
case 'id': return compare(+a.id, +b.id, isAsc);
case 'number': return compare(+a.number, +b.number, isAsc);
default: return 0;
}
});
}
}
function compare(a, b, isAsc) {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}
auth.service.ts
import { Injectable } from '#angular/core';
import { HttpHeaders, HttpClient } from '../../node_modules/#angular/common/http';
import { Observable } from '../../node_modules/rxjs';
import { DataListeItem } from './data-liste/data-liste-datasource';
#Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private http: HttpClient) { }
GetUser(): Observable<DataListeItem[]> {
return this.http.get<DataListeItem[]>("DataListeItem.online");
}
So all in all how to I make a call to my REST and get the list shown.
Should I make the call directly in " data-liste-datasource.ts" or should that be in the service.
thanks for reading
You need to use Observable<DataListeItem[]> instead of DataListeItem[].
data: Observable<DataListeItem[]> = this.authservice.GetUser();

TypeError: Cannot read property 'map' of undefined with Angular v6

For some reason the response JSON is not mapping correctly
Here is my html.
profile-search.component.html
<h3>Enter Username</h3>
<input (keyup)="search($event.target.value)" id="name" placeholder="Search"/>
<ul>
<li *ngFor="let package of packages$ | async">
<b>{{package.name}} v.{{package.repos}}</b> -
<i>{{package.stars}}</i>`enter code here`
</li>
</ul>
Here is component that the html pulls from.
profile-search.component.ts
import { Component, OnInit } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
import { NpmPackageInfo, PackageSearchService } from './profile-search.service';
#Component({
selector: 'app-package-search',
templateUrl: './profile-search.component.html',
providers: [ PackageSearchService ]
})
export class PackageSearchComponent implements OnInit {
withRefresh = false;
packages$: Observable<NpmPackageInfo[]>;
private searchText$ = new Subject<string>();
search(packageName: string) {
this.searchText$.next(packageName);
}
ngOnInit() {
this.packages$ = this.searchText$.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(packageName =>
this.searchService.search(packageName, this.withRefresh))
);
}
constructor(private searchService: PackageSearchService) { }
toggleRefresh() { this.withRefresh = ! this.withRefresh; }
}
Service that component pulls from.
profile-search.service.ts
import { Injectable, Input } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { HttpErrorHandler, HandleError } from '../http-error-handler.service';
export interface NpmPackageInfo {
name: string;
}
export const searchUrl = 'https://api.github.com/users';
const httpOptions = {
headers: new HttpHeaders({
'x-refresh': 'true'
})
};
function createHttpOptions(packageName: string, refresh = false) {
// npm package name search api
// e.g., http://npmsearch.com/query?q=dom'
const params = new HttpParams({ fromObject: { q: packageName } });
const headerMap = refresh ? {'x-refresh': 'true'} : {};
const headers = new HttpHeaders(headerMap) ;
return { headers, params };
}
#Injectable()
export class PackageSearchService {
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('HeroesService');
}
search (packageName: string, refresh = false): Observable<NpmPackageInfo[]> {
// clear if no pkg name
if (!packageName.trim()) { return of([]); }
// const options = createHttpOptions(packageName, refresh);
// TODO: Add error handling
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
return data.results.map(entry => ({
name: entry.any[0],
} as NpmPackageInfo )
)
}),
catchError(this.handleError('search', []))
);
}
}
I have tried to alter
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
return data.results.map(entry => ({
name: entry.any[0],
} as NpmPackageInfo )
)
to
login: data.login, and login: entry.login but keep getting the below error.
http-error-handler.service.ts:33 TypeError: Cannot read property 'map'
of undefined
at MapSubscriber.project (profile-search.service.ts:49)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next
(map.js:75)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next
(map.js:81)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next
(filter.js:85)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber.notifyNext
(mergeMap.js:136)
at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/InnerSubscriber.js.InnerSubscriber._next
(InnerSubscriber.js:20)
at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next
(Subscriber.js:93)
results in data.results is probably undefined, check that the data object matches the schema you're expecting it to.
map working on array but this.http.get(${searchUrl}/${packageName}) return object not array.
so data.results is undefined.
This is how I converted my object into an array, if anyone has a better way of doing please let me know.
return this.http.get(`${searchUrl}/${packageName}`).pipe(
map((data: any) => {
console.log(data);
var profile = Object.keys(data).map(function(key) {
return [(key) + ': ' + data[key]];
}
);
console.log(profile);
data = profile;
return data;
}),
catchError(this.handleError<Error>('search', new Error('OOPS')))
);
}
}
I fixed this issue by eliminating ".results"
from
.map((data: any) => this.convertData(data.results))
to
.map((data: any) => this.convertData(data))
To avoid the error, change
map((items) => items.map
to
map((items) => items?.map
Then set your result set as an empty array:
this.list = data ?? [];
PS: Used with Angular 14. In older versions you may need to change last one to data ? data : []

Angular 4 map certain JSON data to class and return observable

So I am trying to learn some basic Angular by creating an application that fetches and displays the current weather of a location using OpenWeather API.
This is what I have in my code currently:
app.component.ts:
import { Component } from '#angular/core';
import { WeatherService } from './weather.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [WeatherService]
})
export class AppComponent {
title = 'Ng-Weather';
cityName: string;
weather: Weather;
constructor(private weather: WeatherService) { }
search() {
this.weather.getWeatherbyName(this.cityName)
.subscribe(res => this.weather = res);
console.log(this.weather);
}
}
weather.service.ts:
import { Injectable } from '#angular/core';
import { Http, Response, URLSearchParams } from '#angular/http';
import { Observable } from 'rxjs';
import { Weather } from './weather';
#Injectable()
export class WeatherService {
APIurl = "http://api.openweathermap.org/data/2.5/weather";
Appid = "xxx";
weather: Weather;
constructor(private http: Http) { }
getWeatherbyName(name: string): Observable<any> {
let myParams = new URLSearchParams();
myParams.append('appid', this.Appid);
myParams.append('q', name);
return this.http.get(this.APIurl , { search: myParams} )
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
this.weather.city = body.name;
this.weather.description = body.weather[0].main;
this.weather.temp = body.main.temp;
console.log(this.weather);
}
private handleError(error: Response | any) {
console.error(error.message || error);
return Observable.throw(error.message || error);
}
}
weather.ts:
export class Weather {
city: String;
description: String;
temp: String;
}
So basically I am trying to map a JSON returned from OpenWeather API and get only some parts of the data and not the whole thing. The JSON returned is like following:
{
"coord":{
"lon":80.28,
"lat":13.09
},
"weather":[
{
"id":802,
"main":"Clouds",
"description":"scattered clouds",
"icon":"03n"
}
],
"base":"stations",
"main":{
"temp":303.15,
"pressure":1008,
"humidity":79,
"temp_min":303.15,
"temp_max":303.15
},
"visibility":6000,
"wind":{
"speed":3.1,
"deg":210
},
"clouds":{
"all":40
},
"dt":1504805400,
"sys":{
"type":1,
"id":7834,
"message":0.0017,
"country":"IN",
"sunrise":1504744074,
"sunset":1504788314
},
"id":1264527,
"name":"Chennai",
"cod":200
}
When the above code is executed, I get this error:
weather.service.ts:32 Cannot set property 'city' of undefined
Also how do I return an observable of type Weather and return that variable weather and catch it on the app.component.ts?
You are not creating an instance of the weather object before assigning its properties. You can do that explicitly like this:
this.weather = new Weather();
this.weather.city = body.name;
this.weather.description = body.weather[0].main;
this.weather.temp = body.main.temp;
console.log(this.weather);
OR
You can do something like this:
this.weather = {
city: body.name,
description: body.weather[0].main,
temp: body.main.temp
}
console.log(this.weather);
And to answer the second part of your question, you should be able to do this:
getWeatherbyName(name: string): Observable<Weather> {
// your other code
}
private extractData(res: Response) {
// your other code
return this.weather;
}
And to answer the third part of your question ... Observables are asynchronous. This means that they do not immediately return a value. Rather they provide for definition of a callback function that is executed when the data is returned. That means that the data is undefined until the data is returned and the callback function is executed.
So if you want to access the returned data in your code, you need to do in WITHIN the callback function. Like this:
search() {
this.weather.getWeatherbyName(this.cityName)
.subscribe(res => {
this.weather = res;
console.log(this.weather);
});
}

Data are not showing when two api called in` iondidenter`

I have one screen, which have two gridview . each grid view will populate some value after api calling. so my page will have 2 api calling. so when i call my api call method under constructor or ionViewDidEnter its not working. it allowing only one method to exeute.
here is my two api call method on one page .ts
Even i put under my constructor. But its not showing the data. so if i want to call the both api and need to display the data means how can i do that.please help me out. i was not able to find it out !!
Thanks in advance
updated:
import { Component, ViewChild } from '#angular/core';
import { AlertController, App, FabContainer, ItemSliding, List, ModalController, NavController, ToastController, LoadingController, Refresher } from 'ionic-angular';
import { CategoryDetailPage } from '../categorydetail/categorydetail';
import { ConferenceData } from '../../providers/conference-data';
import { UserData } from '../../providers/user-data';
import { SessionDetailPage } from '../session-detail/session-detail';
import { ScheduleFilterPage } from '../schedule-filter/schedule-filter';
import {Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { AuthService } from '../../providers/AuthService';
#Component({
selector: 'page-speaker-list',
templateUrl: 'speaker-list.html'
})
export class SpeakerListPage {
loading: any;
data: any;
Catdata: any;
Catdatanames: any;
resdata: any;
resCatdata: any;
resCatdatanames: any;
loginData: {username?: string} = {};
resloginData: {username?: string} = {};
constructor(
public alertCtrl: AlertController,
public app: App,
public loadingCtrl: LoadingController,
public modalCtrl: ModalController,
public navCtrl: NavController,
public toastCtrl: ToastController,
public confData: ConferenceData,
public user: UserData,
public http:Http,
public authService: AuthService
) {
}
ionViewDidEnter() {
this.show();
this.another();
}
show() {
this.showLoader();
this.authService.subs(this.loginData).then((result) => {
this.loading.dismiss();
this.data = result;
if(this.data.status == 1)
{
this.Catdata = this.data.SubjectList;
//this.Catdata.forEach(category => console.log(category.CatID));
for(let i=0; i<this.Catdata.length; i++) {
// console.log(this.Catdata[i].SubjectName);
}
}
else if(this.data.status == 0) {
let alert = this.alertCtrl.create({
title: 'Error',
subTitle: 'Please Enter Valid Username & Password',
buttons: ['OK']
});
alert.present();
}
}, (err) => {
this.loading.dismiss();
});
}
another() {
this.authService.allresources(this.resloginData).then((result) => {
this.resdata = result;
if(this.resdata.status == 1)
{
this.resCatdata = this.resdata.SubjectList;
for(let i=0; i<this.resCatdata.length; i++) {
// console.log(this.resCatdata[i].FileName);
}
}
else if(this.resdata.status == 0) {
let alert = this.alertCtrl.create({
title: 'Error',
subTitle: 'Please Enter Valid Username & Password',
buttons: ['OK']
});
alert.present();
}
}, (err) => {
});
}
showLoader(){
this.loading = this.loadingCtrl.create({
content: 'Authenticating...'
});
this.loading.present();
}
}