Navigating to Angular component from Mapbox popup

I'm currently working on a mobile app with Ionic and Angular. The app features various Mapbox markers that open custom popups when clicked, each displaying unique content. I want the button within the popup to redirect users to a page with more information about that specific location. Here is a snippet of my code:

ionViewWillEnter(){
    this.businessService
    .getBusinessCoords()
    .subscribe(data=>{
      for(const key in data){
        let popup = new mapboxgl.Popup({
          className:'popup-class'
        }).setHTML(
            `<div>
            <img src= ${data[key].profile_picture} width="150">
            <b style="text-align: center;"> ${data[key].name}</b><br>
            <i>${data[key].location.address}</i><br>
            <a id="${key}">Tap to see available offers!</a>
            </div>
            `
          )
        new mapboxgl.Marker({
          color:"#cc0000",
          draggable: false
        }).setLngLat([data[key].location.coord.lng, data[key].location.coord.lat])
          .setPopup(popup)
          .addTo(this.map);
      }
    })//end subscribe
  }

An ideal solution would involve using the href attribute within the <a> tag, but I prefer an Angular-specific routing method to direct users to individual business pages based on the ${key} value. I've experimented with different approaches like

document.getElementByClassName("some-test-class")[0].addEventListener('click',()=>{console.log("hello!"});
, following discussions on Stack Overflow, but encountered errors such as "Cannot read property 'addEventListener' of undefined." Other solutions involving ComponentFactoryResolver seem overly complex for this task. Any suggestions for a simpler, more direct approach or insights on why previous attempts failed would be greatly appreciated.

https://i.sstatic.net/0neW8.png

Answer №1

If you're working with mapboxgl.Source and mapboxgl.Layer for your data, there's another approach you can take.

  1. Convert your data into GeoJson format where the dynamic popup content is stored in the features' properties.
  2. Set up a mapboxgl.Source with type: "geojson" using your transformed GeoJson data.
  3. Create a mapboxgl.Layer with the created source and apply your preferred styling.
  4. Include a popup container in your component template that will be referenced in the setDOMContent method. Check out the example below for guidance.

This integration allows for seamless interaction between the Popup and Angular framework (beyond just routing).

<!-- component.html -->
<div #popupContainer class="popup-container">
  <div *ngIf="popup">
    <img [src]="popup.profile_picture" width="150">
    <b style="text-align: center;">{{ popup.name }}</b><br>
    <i>{{ popup.location.address }}</i><br>
    <a routerLink="/foodrevolution/profile">Tap to see available offers!</a>
  </div>
</div>
// component.ts
@ViewChild("popupContainer") popupContainer: any;
popup: any;

ionViewDidEnter() {
  this.businessService
    .getBusinessCoords()
    .subscribe((data) => {
      const geoJson = toGeoJson(data);
      this.map.getSource("source-id").setData(geoJson);
    });
  this.map.on("click", "points-layer", (e) => {
    const coordinates = e.features[0].geometry.coordinates.slice();
    this.popup = e.features[0].properties;
    new mapboxgl.Popup()
      .setLngLat(coordinates)
      .setDOMContent(this.popupContainer.nativeElement)
      .addTo(this.map);
  });
}

An individual Feature within the GeoJson FeatureCollection should resemble something like this:

{
  type: "Feature",
  geometry: {
    type: "Point",
    coordinates: [
      data[key].location.coord.lng,
      data[key].location.coord.lat
    ]
  },
  properties: {
    key: key,
    name: data[key].name
    // ...
  }
}

Answer №2

After some trial and error, I managed to resolve the issue by implementing the solution provided in the initial response on this thread. Here is my updated code snippet:

ionViewDidEnter(){
    this.businessService
    .getBusinessCoords()
    .subscribe(data=>{
      for(const key in data){
        const popupContent = document.createElement('div');
        popupContent.innerHTML = `<img src= ${data[key].profile_picture} width="150">
                                  <b style="text-align: center;"> ${data[key].name}</b><br>
                                  <i>${data[key].location.address}</i><br>`;
        const atag = document.createElement('div');
        atag.innerHTML = `<a id="${key}">Tap to see available offers!</a>`
        popupContent.appendChild(atag); 
        atag.addEventListener('click', (e)=>{
          console.log('Button was clicked' + key);
          this.router.navigateByUrl('/foodrevolution/profile')
        })
        let popup = new mapboxgl.Popup({
        }).setDOMContent(popupContent); 
          
        new mapboxgl.Marker({
          color:"#cc0000",
          draggable: false
       }).setLngLat([data[key].location.coord.lng, data[key].location.coord.lat])
         .setPopup(popup)
         .addTo(this.map);
      }
    })//end subscribe
  }

In this revised version, note that the router variable is declared as type Router from the @angular/router package. Interestingly, the functionality remains consistent even when using ionViewWillEnter, suggesting that the choice of a lifecycle hook may not be critical in this scenario.

Answer №3

It is not possible to access any htmlElement in ionViewWillEnter since the view has not been created yet. Consider moving this code to ionViewDidEnter for proper execution.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to remove the border of the MUI Select Component in React JS after it has been clicked on

I am struggling to find the proper CSS code to remove the blue border from Select in MUI after clicking on it. Even though I managed to remove the default border, the blue one still persists as shown in this sandbox example (https://codesandbox.io/s/autumn ...

Obtaining the display name and phone numbers of a contact

Using the Ionic Contacts Native feature, I am able to retrieve a list of contacts from my phone. .ts: import { Contacts } from 'ionic-native'; ///////// export class ContactPage { contactsfound = [] constructor(public navCtrl: NavCont ...

"Encountering issues with NPM run build not working during Docker build process

Encountering an error while running docker build is causing frustration. Docker runs npm install -f, and changing it to npm install did not solve the problem. The lengthy logs cannot be posted here, but can be viewed in detail here. Here's a snippet o ...

What are some effective techniques for handling asynchronous operations while utilizing [displayWith] in an autocomplete

In my angular reactive form, I am struggling with an autocomplete functionality. I want to show the name (myObject.name) but use the ID (myObject.id) as the value. However, when the form is populated with existing values, there is a delay in retrieving th ...

How to attach input to function invocation in Angular 2

Can we connect the @Input() property of a child component to a parent component's function call like this: <navigation [hasNextCategory]="hasNextCategory()" [hasPreviousCategory]="hasPreviousCategory()" (nextClicked)="next ...

TypeError thrown by Basic TypeScript Class

I'm encountering an issue where TypeScript is throwing a TypeError when trying to use the class Literal from file Classes.tsx in file App.tsx, even though they are in the same file. Strangely, everything works fine on typescriptlang.org/play. // Class ...

Issue with Discord.js (14.1) - Message Handling Unresponsive

After developing a sizable Discord Bot in Python, I decided to expand my skills and start learning JS. Despite thoroughly studying the documentation and comparing with my original Python Bot regarding intents, I am facing difficulties getting the message ...

In what scenarios would it be more advantageous to utilize ngStyle over creating a custom directive?

I had the need to dynamically change the width of a column, so I created a unique custom directive for that specific purpose: @Directive({ selector: '[rq-column-size]' }) export class ColumnSizeDirective { @Input('rq-column-size') ...

Guide to releasing a NestJs library on npm using the nrwl/nx framework

Struggling with creating a publishable NestJS library using NX. Despite reading numerous documentations, I still can't figure it out. I've developed a NestJS library within an NX monorepository and now I want to publish just this library on NPM, ...

Storing JSON data in LocalStorage or within the App on Ionic 2

I am currently in the process of developing a mobile app for both IOS and Android platforms. The app will feature a list of objects including images, names, etc., which are stored on a backend server powered by node.js. My goal is to allow users of the ap ...

Create a nested array of subcategories within an array object

Currently, I am working on integrating Django Rest and Angular. The JSON array received from the server includes category and subcategory values. My goal is to organize the data such that each category has its related subcategories stored as an array withi ...

The attribute 'sandwiches' cannot be found within the data type 'string'

In my app, I require an object that can store strings or an array of strings with a string key. This object will serve as a dynamic configuration and the keys will be defined by the user, so I cannot specify types based on key names. That's why I&apos ...

Separating Angular code into distinct components

My page contains two input fields: one is for email and the other is a text field. Currently, everything is functioning correctly. However, I now want to split the component into two parts. For example, I have a 'basic-info' component currently. ...

Creating personalized properties for a Leaflet marker using Typescript

Is there a way to add a unique custom property to each marker on the map? When attempting the code below, an error is triggered: The error "Property 'myCustomID' does not exist on type '(latlng: LatLngExpression, options?: MarkerOptions) ...

How to fix the error: ui-switch is not a recognized element in Angular 5?

Currently, I am attempting to utilize the ui-switch feature mentioned in this link. However, I have encountered an error: ng : ui-switch is not a known element ng : if ui-switch is An angular component then verify it's a part of this module ...

Altering a public variable of a component from a sibling component

Within my application, I have two sibling components that are being set from the app.component: <my-a></my-a> <my-b></my-b> The visibility of <my-a> is determined by a public variable in its component: @Component({ module ...

Is the return type of 'void' being overlooked in TypeScript - a solution to avoid unresolved promises?

When working in TypeScript 3.9.7, the compiler is not concerned with the following code: const someFn: () => void = () => 123; After stumbling upon this answer, it became apparent that this behavior is intentional. The rationale behind it makes sens ...

Encountering a Difficulty while attempting to Distinguish in Angular

I am currently working on a form where I need to dynamically add controls using reactiveForms. One specific task involves populating a dropdown menu. To achieve this, I am utilizing formArray as the fields are dynamic. Data: { "ruleName": "", "ruleD ...

The installation of npm failed with the error message "Error! Code ENO

I encountered an error while trying to write code in the nodejs console using npm install -g ionic. I have been stuck on this issue for a week and have tried every possible solution. Here are my versions: nodejs -v 6.4 npm 3.10.6 cordova 6.3 1) The problem ...

Creating Angular unit test modules

When it comes to creating unit test cases for an Angular app, the application functionality is typically divided into modules based on the requirements. In order to avoid the need for repeated imports in component files, the necessary components, modules, ...