add custom image to azure maps - azure

I am using this wrapper for the azure maps library. I am currently implementing a symbol layer and using one of the default markers works well, but I am not able to add my own marker. I tried to add a custom marker like in my mapReady function, but the response is always undefined and the image is not added.
this is my component:
import {Component, Input, OnInit} from '#angular/core';
import * as atlas from 'azure-maps-control';
#Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit {
private markerImagePath = 'assets/images/map-marker.png';
public dataSource: atlas.source.DataSource;
markerDescription: 'marker';
public options: atlas.IconOptions = {
image: this.markerDescription
};
points = [
[52.52437, 13.41053],
[51.50853, -0.12574]
];
ngOnInit() { }
mapReady(map: atlas.Map) {
map.imageSprite.add(this.markerDescription, this.markerImagePath).then(r => {
console.log(r);
console.log(map.imageSprite.getImageIds());
this.dataSource = new atlas.source.DataSource('markers');
this.points.forEach(p => {
const point = new atlas.Shape(new atlas.data.Point([p[1], p[0]]));
this.dataSource.add([point]);
});
});
}
}
this is my html:
<section>
<div class="row">
<div class="col-12 map-dimensions my-2 mx-auto" azure-map zoom="2"
[dataSources]="[dataSource]" (onReady)="mapReady($event.map)">
<map-symbol-layer dataSourceId="markers"
[iconOptions]="options"></map-symbol-layer>
</div>
</div>
</section>
I suspect, that I access the map data wrongly... Do any of you guys know, how I can add a custom image to the imageSprites in order for me to use it as a marker in the symbol layer?

Your code looks fine. imageSprite.add returns a Promise<void>, so your console.log will always log undefined. Could your icon be the issue ? I have been trying a similar solution and all works fine on my side :
import { Component } from '#angular/core';
import * as atlas from 'azure-maps-control';
#Component({
selector: 'app-root',
template: '<azure-map zoom="2" [dataSources]="[dataSource]" (onReady)="mapReady($event.map)">' +
'<map-symbol-layer [id]="blueLayerId" dataSourceId="blue" [iconOptions]="blueIconOptions"></map-symbol-layer>' +
'</azure-map>',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
public dataSource: atlas.source.DataSource;
public blueLayerId: string = "blueLayer";
public blueIconOptions: atlas.IconOptions = {
image: 'campground'
};
mapReady(map: atlas.Map) {
map.imageSprite.add('campground', 'assets/campground.png').then(() => {
this.dataSource = new atlas.source.DataSource('blue');
for (let i = 0; i < 10; i++) {
const point = new atlas.Shape(new atlas.data.Point([i * 5, i * 5]));
this.dataSource.add([point]);
}
});
}
}

Related

Angular8 http and services missunderstand

I'm here because I do not understand how Http works in angular. I would create a "news" thread on my website. To do that I have created a service in my angular app that calls a .net core web API.
Also, I would add a paginate to my thread (I want to display news by 5 on the page).
I can get my values, that is not my issue here. But, to create my paginate, I need to have values for number of pages calculation.
I tried to add code to create my paginate (number of pages, number of elements...) but I always get 0 to these values and my array of news is filled after the onInit(). This is what I don't understand.
This is my component:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { NewsService } from '../news.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
title = 'News';
news = [];
displayed = [];
numberOfPages = 0;
constructor(private newsService: NewsService) { }
ngOnInit() {
// I don't really understand these lines (mainly the subscribe part)
this.newsService.getAllNews().subscribe((data) => {
this.news = Array.from(Object.keys(data), k => data[k]);
// this console.log appears after the onInit(), why ?
console.log(this.news);
});
this.numberOfPages = this.news.length / 5; // Get 0 here, why ?
}
}
My service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class NewsService {
private finalData = [];
private apiUrl = 'https://localhost:5001/api/v1/posts';
constructor(private http: HttpClient) { }
getAllNews() {
return this.http.get(this.apiUrl);
}
}
In the browser console, I get this:
console screen
Maybe I forgot something in my code or I don't know what.
Someone can help me to achieve my goal? I want to understand how to proceed to make a working paginate for my news.
You should add
this.numberOfPages = this.news.length / 5;
inside the subscribe
this.newsService.getAllNews().subscribe((data) => {
this.news = Array.from(Object.keys(data), k => data[k]);
// this console.log appears after the onInit(), why ?
console.log(this.news);
});
like so:
this.newsService.getAllNews().subscribe((data) => {
this.news = Array.from(Object.keys(data), k => data[k]);
// this console.log appears after the onInit(), why ?
console.log(this.news);
this.numberOfPages = this.news.length / 5;
});
My guess is that when you try to initialise the this.numberOfPagesthe this.news.length is not yet set(data are not yet retrieved from the API). Hope this helps

value is undefined when passed in component in angular 6

I have a Service that calls an API (Http get request) then I call the service within my component to get the data and then assign it to a value. after that I pass the value in the html to another component but it showing as undefined
import { Component } from '#angular/core';
import { AuthService } from '../../src/app/services/auth.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
passData: any
constructor(private authService: AuthService) {
}
ngOnInit() {
this.authService.test().subscribe(data => {
for (var i = 0; i < data.length; i++) {
data[i].date = new Date(
data[i].date.substring(0, 4)+'-'+
data[i].date.substring(4, 6)+'-'+
data[i].date.substring(6, 10)+ ' '+data[i].minute)
}
this.passData = data;
});
}
}
below is where I pass in my value to the new component, but showing undefined
<div class="card-deck">
<app-stock-bar [customTitle]=passData></app-stock-bar>
The value of passData when passed is undefined, but if I log it, it will display the value in the console
the answer was very simple after some research I found that you can simply use *ngIF to check if the value is present before you load
<app-stock-bar *ngIf="passData" [customTitle]="passData"></app-stock-bar>
When you are passing the value from parent to child component. You can access it inside onChanges LifeCycle hook.
Component
#Component({})
export class AppStockBar implements OnChanges{
#Input() customTitle;
ngOnChanges(){
console.log(this.customTitle);
}
}
I think the property binding missing double quotes
<app-stock-bar [customTitle]="passData"></app-stock-bar>

Perform action in parent on child event click

So I'm trying to perform some action on the parent component of the child component when a click event is fired in the child component. Currently I have a dynamic loader which is able to load different child components. The problem I have is that the #Output() is being emitted but the parent component doesn't seem to have any knowledge when this event is fired. Is there something I am missing?
child2.component.ts
import {Component, Injector, Output, EventEmitter} from '#angular/core';
#Component({
selector: 'hello-world',
template: `
<div>Hello World {{showNum}}</div>
<li (click)="childButtonClicked(false)"> </li>
`,
})
export class HelloWorldComponent {
showNum = 0;
#Output() childEvent = new EventEmitter<boolean>();
constructor(private injector: Injector) {
this.showNum = this.injector.get('showNum');
console.log("HelloWorldComponent");
}
childButtonClicked(agreed: boolean) {
this.childEvent.emit(agreed);
console.log("clicked");
}
}
child1.component.ts
import {Component, Injector, Output, EventEmitter} from '#angular/core';
#Component({
selector: 'world-hello',
template: `
<div>World Hello {{showNum}}</div>
<li (click)="childButtonClicked(false)"> </li>
`,
})
export class WorldHelloComponent {
showNum = 0;
#Output() childEvent = new EventEmitter<boolean>();
constructor(private injector: Injector) {
this.showNum = this.injector.get('showNum');
console.log("WorldHelloComponent");
}
childButtonClicked(agreed: boolean) {
this.childEvent.emit(agreed);
console.log("clicked");
}
}
dynamic.componentloader.ts
import {Component, Input, ViewContainerRef,ComponentRef, ViewChild, ReflectiveInjector, ComponentFactoryResolver} from '#angular/core';
#Component({
selector: 'dynamic-component',// Reference to the components must be here in order to dynamically create them
template: `
<div #dynamicComponentContainer></div>
`,
})
export class DynamicComponent {
currentComponent:any = null;
#ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef;
// component: Class for the component you want to create
// inputs: An object with key/value pairs mapped to input name/input value
#Input() set componentData(data: {component: any, inputs: any }) {
if (!data) {
return;
}
// Inputs need to be in the following format to be resolved properly
let inputProviders = Object.keys(data.inputs).map((inputName) => {return {provide: inputName, useValue: data.inputs[inputName]};});
let resolvedInputs = ReflectiveInjector.resolve(inputProviders);
// We create an injector out of the data we want to pass down and this components injector
let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicComponentContainer.parentInjector);
// We create a factory out of the component we want to create
let factory = this.resolver.resolveComponentFactory(data.component);
// We create the component using the factory and the injector
let component = factory.create(injector);
// We insert the component into the dom container
this.dynamicComponentContainer.insert(component.hostView);
// We can destroy the old component is we like by calling destroy
if (this.currentComponent) {
this.currentComponent.destroy();
}
this.currentComponent = component;
}
constructor(private resolver: ComponentFactoryResolver) {
}
}
main.component.ts
import { Component, OnInit } from '#angular/core';
import { HelloWorldComponent } from '../../views/main/sidebar-views/comps/hello-world.component';
import { WorldHelloComponent } from '../../views/main/sidebar-views/comps/world-hello.component';
#Component({
selector: 'main-component',
template: require('./main.component.html')
})
export class MainComponent {
private pressed: boolean = false;
componentData:any = null;
constructor() { }
createHelloWorldComponent(){
this.componentData = {
component: HelloWorldComponent,
inputs: {
showNum: 9
}
};
}
createWorldHelloComponent(){
this.componentData = {
component: WorldHelloComponent,
inputs: {
showNum: 2
}
};
}
test(){
console.log("some click event");
}
};
main.component.html
<div>
<h2>Lets dynamically create some components!</h2>
<button (click)="createHelloWorldComponent()">Create Hello World</button>
<button (click)="createWorldHelloComponent()">Create World Hello</button>
<dynamic-component [componentData]="componentData" (childEvent)="test()"></dynamic-component>
</div>
Since you are passing a parameter to the EventEmitter, you need to change your event binding on your component selector in your template to this:
<dynamic-component [componentData]="componentData" (childEvent)="test($event)"></dynamic-component>
Also, don't forget to change function signature in your component to accept the parameter:
test(agreed: boolean){
console.log("some click event");
}
More info on official docs.

Ionic 2 - How to reach a component from inside a directive?

I'm trying to build a directive to display a custom numpad when
the control (input) on which the directive is applied is clicked.
I'm Working on Ionic 2 RC5.
myPage.html
<ion-content>
<ion-item>
<ion-label stacked>Label</ion-label>
<ion-input dirNumpad type="text" [(ngModel)]="myField"></ion-input>
</ion-item>
</ion-content>
<ion-footer>
<numpad #idNumpad hidden></numpad>
</ion-footer>
The Numpad component is in the DOM, at the bottom of the page.
dirNumpad.ts
import { Directive, ElementRef, ViewChild } from '#angular/core';
import { Numpad } from '../../components/numpad/numpad';
#Directive({
selector: '[dirNumpad]', // Attribute selector
host: {
'(click)': 'onClick()'
}
})
export class DirNumpad {
#ViewChild('idNumpad') numpad: Numpad;
constructor( private el: ElementRef ) {
}
onClick() {
this.showNumpad();
}
showNumpad() {
console.log(this.numpad); => undefined
this.numpad.show(); => error: show property does not exist on undefined
}
}
numpad.html
<div class="numpad" style="position:absolute; top:auto; left:0;
right:0; bottom:0; height:150px;">My Numpad</div>
numpad.ts
import { Component, Input } from '#angular/core';
#Component({
selector: 'numpad',
templateUrl: 'numpad.html'
})
export class Numpad {
constructor() {}
}
My problem: I can not reach the numpad component from inside the directive through ViewChild.
console.log(this.numpad) always returns "undefined"!
I need it to show the numpad only if user clicks on the input on which the directive is applied...
What am I doing wrong?
I'm stucked with this problem, so any help will be appreciated.
ViewChild only applies to the children items of the item. Since the component is not a child in any way of the directive but rather a sibling it cant be received in ViewChild.
You can pass it as part of an input
Declare an input in your component
import { Directive, ElementRef, Input } from '#angular/core';
import { Numpad } from '../../components/numpad/numpad';
#Directive({
selector: '[dirNumpad]', // Attribute selector
host: {
'(click)': 'onClick()'
}
})
export class DirNumpad {
#Input('numpad') numpad: Numpad;
constructor( private el: ElementRef ) {
}
onClick() {
this.showNumpad();
}
showNumpad() {
console.log(this.numpad); => undefined
this.numpad.show(); => error: show property does not exist on undefined
}
}
and set it in your html
<ion-content>
<ion-item>
<ion-label stacked>Label</ion-label>
<ion-input dirNumpad [numpad]="idNumpad" type="text" [(ngModel)]="myField"></ion-input>
</ion-item>
</ion-content>
<ion-footer>
<numpad #idNumpad hidden></numpad>
</ion-footer>

Data-binding not working with dynamic component loader in angular2-universal-starter [duplicate]

This question already has an answer here:
Error if don't check if {{object.field}} exists
(1 answer)
Closed 6 years ago.
I am using angular2-universal-starter project.
So i was trying to pass an object to a child component using #Input , but its not working correctly.
I have used dynamic component loader to load child component and I want to pass the object to child component.
Following is my code snippet:
app.component.ts
import {Component, Directive, Renderer, DynamicComponentLoader, ElementRef} from 'angular2/core';
import {Http} from 'angular2/http';
import {headingComponent} from './heading.component';
#Directive({
selector: '[x-large]'
})
export class XLarge {
constructor(element: ElementRef, renderer: Renderer) {
// we must interact with the dom through Renderer for webworker/server to see the changes
renderer.setElementStyle(element.nativeElement, 'fontSize', 'x-large');
}
}
#Component({
selector: 'app',
directives: [
XLarge
],
template: `
<div>
<div>
<span x-large>Hello, {{ user.name }}!</span>
</div>
<icici-heading [user]="user"></icici-heading>
</div>
`
})
export class App {
public user;
constructor(dcl: DynamicComponentLoader, elementRef: ElementRef) {
dcl.loadNextToLocation(headingComponent, elementRef);
}
ngOnInit(){
this.user = { "id": 11, "name": "Mr. Nice" };
}
}
heading.component.ts
import {Component, OnInit,Input} from 'angular2/core';
#Component({
selector: 'icici-heading',
template: `
<div>
<!--{{user.name}}-->this is not working
{{name}}
</div>
`
})
export class headingComponent implements OnInit {
#Input() user;
name: string;
constructor() { }
ngOnInit() {
this.name="heading is rendered";
}
}
I guess you just need to make your code more forgiving when the value is not yet available.
This will work:
{{user?.name}}
The Elvis or safe-navigation operator only evaluates .name when user != null
For dynamically added components you also need to pass values imperatively
dcl.loadNextToLocation(headingComponent, elementRef)
.then(cmpRef => cmpRef.instance.user = this.user);

Resources