角度2/传单地图,如何从标记弹出窗口链接到组件? ... routerLink? [英] Angular 2 / leaflet map, How to link to a component from marker popup ? ... routerLink?

查看:54
本文介绍了角度2/传单地图,如何从标记弹出窗口链接到组件? ... routerLink?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的angular 2应用程序中,我有一个传单地图,其中包含一个绑定到onClick事件的弹出窗口.

弹出窗口的内容具有指向角度组件的链接.但是,当我在.setContent()函数中使用routerLink时,链接未显示.

我猜想这是因为.setContent()无法呈现有角度的2指令.我该怎么用呢?

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.css']
})

export class MapComponent implements AfterViewInit {

  openmap: any;

  constructor() { }

  ngAfterViewInit() {

    let openmap = L.tileLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}", {
      attribution: 'terms and feedback'
    });

    let map = L.map("map", {
      center: [33.2148, -97.1331],
      zoom: 5,
      zoomControl: true,
      maxZoom: 18 
    }).addLayer(openmap);

    let marker = L.marker([39.2148, -98.1331]).addTo(map);

    let popup = L.popup();

    function onMapClick(e) {
      popup
        .setLatLng(e.latlng)
        .setContent("Facility" + "<br/>" + "<a routerLink='/view2'>" + "View Two" + "</a>")
        .openOn(map);
    }

    map.on('click', onMapClick);
  }

}

针,如果我将其更改为

 .setContent("Facility" + "<br/>" + "<a href='../view2'>" + "View Two" + "</a>")

将执行我想要的操作,但这将导致页面刷新,因此这不是一个选择.

解决方案

有一种非常简单的方法,也有一种非常复杂的方法.

简单的方法是将原始HTML与锚元素一起使用在angular之外,而无需 RouterLink .注册以点击该锚点元素,然后使用 Router 服务进行导航.

任务是触发链接,但实际问题要深得多,现在它在下次显示一个角度分量时进行链接...

因此,对于复杂的解决方案:

这是一个非常高级的主题...不仅涉及使用高级角度技术,而且在传单实施中也具有先进性.

我会尽力传达信息,但是由于复杂性,示例将非常简单并且需要工作.

首先-角域.

包含指令,组件或管道的HTML字符串将永远无法工作,唯一的方法是初始化视图

让我们定义一个视图作为参考,以查看组件模板的实例.

这些被称为 ComponentRef TemplateRef

因此,我们有2种方法可以解决此问题.由于不能同时使用这两种方法,因此我将使用 ComponentRef ,但请注意,您也可以使用 TemplateRef . 使用模板,您首先需要获取在组件中定义的模板以及 ViewContainerRef 以便将该模板附加到该模板.

我们将构建一个服务,该服务接受传单 Marker 并绑定到标记的click事件,单击该服务将打开一个弹出窗口,该弹出窗口是一个有角组件.

该组件很简单,它呈现了一个链接.

@Component({
  selector: 'facility-link',
  template: `Facility <br/> <a routerLink="{{link}}"> View Two</a>`
})
export class FacilityLinkComponent {
  public link: string;
  constructor() { }
}

现在,为该服务:

@Injectable()
export class LinkPopupService {

  constructor(private cfr: ComponentFactoryResolver,
              private injector: Injector,
              private appRef: ApplicationRef) { }


  register(marker: leaflet.Marker, link: string): void  {
    marker.on('click', ($event: leaflet.MouseEvent)  => this.popup($event.target, link) );
  }

  popup(marker: leaflet.Marker, link: string) {
    const cmpFactory = this.cfr.resolveComponentFactory(FacilityLinkComponent);
    const componentRef = cmpFactory.create(this.injector);
    componentRef.instance.link = link;
    this.appRef.attachView(componentRef.hostView);
    const markerElement = marker.getElement();
    markerElement.parentElement.appendChild(componentRef.location.nativeElement);

    const markerPos = leaflet.DomUtil.getPosition(markerElement);
    const markerClass = leaflet.DomUtil.getClass(markerElement);


    leaflet.DomUtil.setTransform(componentRef.location.nativeElement, markerPos);
    leaflet.DomUtil.setClass(componentRef.location.nativeElement, markerClass);
  }
}

注册方法接受标记和链接并注册到click事件.

触发 popup 方法时,它使用角度工具创建 FacilityLinkComponent 的视图实例,设置链接以供将来绑定,将视图附加到该视图并将其附加到DOM.

这一切都发生在代码的前5行中.

一些注意事项:

  • 我们必须附加一个视图,这样变更检测才能起作用
  • 正确的实现将允许设置 ViewContainerRef 和/或 Injector -使用延迟加载时这是必须的.
  • 最好通过Injector而不是通过分配(ReflectiveInjector)将数据发送到组件
  • 需要正确清理(销毁组件并分离视图)
  • 需要添加切换逻辑,也要在导航时保持简洁.

传单

第六行的代码执行弹出窗口的定位.

这是一个非常简单的逻辑,它只是复制标记中的所有内容.

这就是为什么我使用标记的原因,所以我将有一个参考来获取位置.

在一个真实的示例中,您需要获取一个面板并将组件推入其自己的层中,以计算位置.既然传单包含了所有的帮助者,这并不是那么困难,但是这样做太繁琐了.

希望有帮助.

Inside my angular 2 app I have a leaflet map with a popup bound to a onClick event.

The content of the popup has a link to an angular component. however when I use routerLink inside the .setContent() function the link doesn't show.

I'm guessing this is happening because .setContent() is not able to render angular 2 directives which makes sense. what can I use instead?

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.css']
})

export class MapComponent implements AfterViewInit {

  openmap: any;

  constructor() { }

  ngAfterViewInit() {

    let openmap = L.tileLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}", {
      attribution: 'terms and feedback'
    });

    let map = L.map("map", {
      center: [33.2148, -97.1331],
      zoom: 5,
      zoomControl: true,
      maxZoom: 18 
    }).addLayer(openmap);

    let marker = L.marker([39.2148, -98.1331]).addTo(map);

    let popup = L.popup();

    function onMapClick(e) {
      popup
        .setLatLng(e.latlng)
        .setContent("Facility" + "<br/>" + "<a routerLink='/view2'>" + "View Two" + "</a>")
        .openOn(map);
    }

    map.on('click', onMapClick);
  }

}

Needles, to say if I change it to

 .setContent("Facility" + "<br/>" + "<a href='../view2'>" + "View Two" + "</a>")

Will do what I want, but this will cause a page refresh, so this is not an option.

解决方案

There is a very simple approach and a very complex one.

The simple approach is to use raw HTML with anchor element outside of angular without RouterLink. Register to clicks on that anchor element and use the Router service to navigate.

The task was to fire links but the actual problem is far deeper, now it links next time its showing an angular component...

So, for the complex solution:

This is an highly advanced topic... Not only it involves using advanced angular techniques it's also advanced in the leaflet implementation.

I'll do my best to convey the message but due to the complexity the examples will be very simple and will require work.

First - Angular realm.

An HTML string that contains directives, components or pipes will never work, the only way is to initialize a View

Let's define A View as a reference to view instance of a component or a template.

These are called ComponentRef and TemplateRef

So, we have 2 ways to solve this problem. Since I can't do both i'll go with ComponentRef but note that you can also use TemplateRef. With templates you'll first need to obtain a template defined in the component as well as a ViewContainerRef to attach that template to.

We will build a service that accepts a leaflet Marker and binds to the click event of the marker, on click it will open a popup which is an angular Component.

The component is simple, it renders a link.

@Component({
  selector: 'facility-link',
  template: `Facility <br/> <a routerLink="{{link}}"> View Two</a>`
})
export class FacilityLinkComponent {
  public link: string;
  constructor() { }
}

Now, for the service:

@Injectable()
export class LinkPopupService {

  constructor(private cfr: ComponentFactoryResolver,
              private injector: Injector,
              private appRef: ApplicationRef) { }


  register(marker: leaflet.Marker, link: string): void  {
    marker.on('click', ($event: leaflet.MouseEvent)  => this.popup($event.target, link) );
  }

  popup(marker: leaflet.Marker, link: string) {
    const cmpFactory = this.cfr.resolveComponentFactory(FacilityLinkComponent);
    const componentRef = cmpFactory.create(this.injector);
    componentRef.instance.link = link;
    this.appRef.attachView(componentRef.hostView);
    const markerElement = marker.getElement();
    markerElement.parentElement.appendChild(componentRef.location.nativeElement);

    const markerPos = leaflet.DomUtil.getPosition(markerElement);
    const markerClass = leaflet.DomUtil.getClass(markerElement);


    leaflet.DomUtil.setTransform(componentRef.location.nativeElement, markerPos);
    leaflet.DomUtil.setClass(componentRef.location.nativeElement, markerClass);
  }
}

The register method accepts a marker and the link and registers to the click event.

When the popup method fires it uses angular tools to create a view instance of FacilityLinkComponent, set the link for future binding, attach a view to it and attach it to the DOM.

This all happens in the first 5 lines of code.

Some notes:

  • We must attach a view so change detection works
  • A Proper implementation will allow to set ViewContainerRef and / or an Injector - this is a must when using lazy loading.
  • It is preferred sending data to the component via Injector and not by assignment (ReflectiveInjector)
  • Proper clean up is required (destroy the component and detach the view)
  • Need to add toggle logic, also clean on navigation.

Leaflet

The code from the 6th line performs positioning of the popup.

This is a very simple logic, it just copies everything from the marker.

This is why I used a marker, so I'll have a reference to take the positioning from.

In a realworld example you'll need to get a panel and push the components into their own layer, computing the position. This is not that difficult since leaflet has all the helper, but it was too much for this.

Hope it helps.

这篇关于角度2/传单地图,如何从标记弹出窗口链接到组件? ... routerLink?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆