Trigger a modal from one sibling Angular component to another

My application utilizes an Angular6 component architecture with the following components:

<app-navbar></app-navbar>
<app-dashboard></app-dashboard>

The Dashboard component consists of:

<app-meseros>
</app-meseros>
<app-ultimospedidos></app-ultimospedidos>
<app-modal></app-modal>

I am attempting to call the modal from the navbar.component, which is located within the dashboard in the modal.component.

Here is my attempted code:

<!--navbar.component.html -->
<a class="nav-link btn btn-primary" (click)="openModal()">Crear pedido</a> 

<!--navbar.component.ts -->
import { Component, OnInit } from '@angular/core';
import { BootstrapService } from '../../services/bootstrap.service';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
  constructor(public bootstrapService: BootstrapService) {}
  ngOnInit() {}
  openModal() {
    this.bootstrapService.toggle();
  }
}

To establish communication between the navbar.component and modal.component, I have created a service named BootstrapService:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class BootstrapService {
  isOpen: any = false;
  constructor() {}
  toggle() {
    console.log(!this.isOpen);
    return (this.isOpen = !this.isOpen);
  }
}

In the modal.component.ts file, I intend to subscribe to changes to launch the modal based on boolean value change:

import { Component, OnInit } from '@angular/core';
import { BootstrapService } from '../../services/bootstrap.service';
import { NgbModal, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {
  isOpen;
  closeResult: string;
  modalname: string;
  constructor(
    public modalService: NgbModal,
    public bootstrapService: BootstrapService
  ) {}
  open(content) {
    // console.log(this.bootstrapService.popup);
    this.modalService
      .open(content, { ariaLabelledBy: 'modal-basic-title' })
      .result.then(
        result => {
          this.closeResult = `Closed with: ${result}`;
        },
        reason => {
          this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
        }
      );
  }
  private getDismissReason(reason: any): string {
    if (reason === ModalDismissReasons.ESC) {
      return 'by pressing ESC';
    } else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
      return 'by clicking on a backdrop';
    } else {
      return `with: ${reason}`;
    }
  }
  ngOnInit() {
    this.bootstrapService.toggle().subscribe(isOpen => {
      this.isOpen = isOpen;
      console.log(isOpen);
    });
  }
}

However, I encounter an error when trying to subscribe to changes from the BootstrapService:

"ERROR in src/app/components/modal/modal.component.ts(41,36): error TS2339: Property 'subscribe' does not exist on type 'boolean'."

If I attempt to subscribe to the value on the service directly like this:

this.bootstrapService.isOpen.subscribe(isOpen => {
  this.isOpen = isOpen;
  console.log(isOpen);
});

I receive the following error in the browser console:

"DashboardComponent.html:1 ERROR TypeError: this.bootstrapService.isOpen.subscribe is not a function"

I would appreciate any insights or recommendations on this implementation approach. Thank you!

Answer №1

Fixed it by correcting the EventEmitter reference and updating the code to make it functional.

First, I invoke the service from the component where I intend to trigger my modal:

import { Component, OnInit } from '@angular/core';
import { BootstrapService } from '../../services/bootstrap.service';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
  constructor(public bootstrapService: BootstrapService) {}
  ngOnInit() {}
  openModal() {
    this.bootstrapService.toggle();
  }
}

Next, I emit the changes so that I can subscribe to them from the modal component:

import { Injectable, Output, EventEmitter } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class BootstrapService {
  isOpen: any = 'isOpen';
  @Output() change: any = new EventEmitter();
  constructor() {}
  toggle() {
    this.change.emit(this.isOpen);
    console.log(this.isOpen);
  }
}

I link my template using `@ViewChild('crearpedido') modalInstance;`
and then subscribe to changes and call the modal upon receiving those changes.

import { Component, OnInit, ViewChild } from '@angular/core';
import { BootstrapService } from '../../services/bootstrap.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {
  isOpen;
  closeResult: string;
  @ViewChild('crearpedido') modalInstance;
  constructor(
    public modalService: NgbModal,
    public bootstrapService: BootstrapService
  ) {}
  ngOnInit() {
    this.bootstrapService.change.subscribe(isOpen => {
      this.isOpen = isOpen;
      console.log(this.isOpen);
      this.modalService.open(this.modalInstance);
    });
  }
}

Check out the working repository here!! https://github.com/soyisraelortiz/componentscommunication

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

Retrieve all the records from the collection that have a specific reference number in their ID field

Is it feasible to pull together all documents with an ID that includes a specific value? I am working with Angular 7. I attempted using db.collection('items').where.. but unfortunately, this method is not supported. For instance: (collection) ...

What is the best method for uploading images and form content simultaneously in a Vue application?

How can I simultaneously upload images and form content? Is it possible to upload both to the client first and then to the server together with the form content? I'm looking to submit the form content along with the image to the server in one go when ...

Removing a key from an index signature in Typescript - a step-by-step guide

In my web application built with Angular, we encountered a need for a data type to store translations of strings in different languages. To address this requirement, a team member defined the following type: export class TranslatedString { [language: str ...

NgZone is no longer functioning properly

Seemingly out of the blue, my NgZone functionality has ceased to work. I'm currently in the process of developing an application using Ionic, Angular, and Firebase. An error is being thrown: Unhandled Promise rejection: Missing Command Error ; Zon ...

JavaScript on Ruby on Rails stops functioning in js.erb file

I have encountered an issue with pagination using AJAX in a view. Initially, I had two paginations working perfectly fine with their respective AJAX calls. However, when I tried to add a third pagination (following the same method as the previous two), it ...

potential issues with memory leakage and browser crashes in three.js

Currently working on an app that features a spherical panorama photo with a jpg size of around 4Mb. Throughout the development process, I find myself constantly refreshing the page to see changes and browsing through various three.js example pages for insp ...

Can a placeholder dropzone be created at the bottom of Vue Draggable lists?

Currently, I am utilizing Vue.Draggable (accessible at https://github.com/SortableJS/Vue.Draggable) to develop a kanban board that enables me to drag items from one list to another. A challenge I face is that when dragging a list item to the bottom of anot ...

The Angular 14 HTTP requests are being made twice

I am facing an issue with my API calling flow, which goes from the Controller to Service to BaseService. Controller code: this.salesManagerService.getNotificationsCounts(token).subscribe((response:any) => { if(response.response.status){ this.noti ...

Calling Node Express request inside a GET route

I am currently utilizing nodejs as an intermediary layer between my public website and an internal server within our network. Through the use of express.js, I have created a basic REST api where the endpoint should trigger a request call to a webservice a ...

How to eliminate ampersands from a string using jQuery or JavaScript

I'm having trouble with a seemingly simple task that I can't seem to find any help for online. My CSS class names include ampersands in them (due to the system I'm using), and I need to remove these using jQuery. For example, I want to chan ...

How can we increase the accuracy of numerical values in PHP?

When performing a math operation in JavaScript, the result is: 1913397 / 13.054 = 146575.53240386088 However, when the same operation is performed in PHP, the result is slightly different: 1913397 / 13.054 = 146575.53240386 This discrepancy may be due ...

Improving JavaScript function by restructuring and eliminating conditional statements from within a loop

Looking for advice on how to refactor my function and eliminate the if statement inside the loop. Any suggestions would be helpful as I suspect the else condition is unnecessary. function quantitySum(array) { let sum = 0; for (let i = 0; i < array ...

Updating className in React by responding to button clicks without relying on numerous conditional statements

I've been working on a small project for the past few weeks. The main idea is to have a stepper with different steps that the user can click on to see their tasks for each step. There is also a completion button for each step, but I'm struggling ...

Issue with scroll down button functionality not functioning as expected

Is there a way to create a simple scroll down button that smoothly takes you to a specific section on the page? I've tried numerous buttons, jQuery, and JavaScript methods, but for some reason, it's not working as expected. The link is set up co ...

A JavaScript function written without the use of curly braces

What makes a function good is how it is declared: export declare class SOMETHING implements OnDestroy { sayHello() { // some code to say hello } } However, while exploring the node_modules (specifically in angular material), I stumbled up ...

Understanding the process of linking JavaScript code to a database within the ASP.NET framework

I have been successfully using an ASP.NET application to connect to a SQL Server 2016 database. However, I now have a new task of incorporating Javascript into the code in order to retrieve data from the database and present it to the user. I am aware of t ...

Error encountered with Angular JS Express JS File Upload: "undefined is not a function"

There seems to be an error displaying in the console: TypeError: undefined is not a function at C:\nodefiles\new\server.js:101:16 at Layer.handle [as handle_request] (C:\nodefiles\new\node_modules\express\li ...

Can you explain the significance of `Component<Props>` in React Native?

Recently, I started a new react-native project and noticed a change in the component syntax. It now reads export default class WelcomeScreen extends Component<Props>, which is different from what it used to be, export default class WelcomeScreen exte ...

Resolving a Tricky Challenge with jQuery's

I am facing an issue with a function that animates images through crossfading. This function is responsible for rotating banners on a website. By calling the function as animateSlideshow("play"), it starts animating and sets up a timeout. On the other hand ...

Display a unique button and apply a strike-through effect specifically for that individual list item

I've encountered an issue with my code that is causing problems specifically with nested LI elements under the targeted li element: $('#comment-section .comment-box a#un-do').hide(); $('#comment-section ul li[data-is-archived="true"]& ...