Unable to call a component's method from a different component in Angular 7

How can I call the toggleSidebar() method of the SidebarComponent from the HeaderComponent using the callToggleSidebarOnToggleSidebarBtn() method? I am encountering an error that I cannot comprehend. What is the correct way to use a method of one component in another?

I have imported the SidebarComponent into the HeaderComponent. In the constructor of HeaderComponent, I added the SidebarComponent to use one of its methods. Even after removing the callToggleSidebarOnToggleSidebarBtn() method from header.component.ts, I still face the same issue.

sidebar.component.html :

<div id="sidebar" class="bg-gray">
<a href="" class="nav-link"><i class="fa fa-calendar"></i> Event</a>
<a href="" class="nav-link"><i class="fa fa-user-circle-o"></i> Profile</a>
<a href="" class="nav-link"><i class="fa fa-commenting-o"></i> Chat</a>
<a href="" class="nav-link"><i class="fa fa-gear"></i> Setting</a>
<a href="" class="nav-link"><i class="fa fa-question-circle-o"></i> Help</a>
<a href="" class="nav-link"><i class="fa fa-sign-out"></i> Log out</a>

header.component.html :

<div>
  <nav class="navbar navbar-expand-lg d-flex justify-content-between fixed-top">
    <button class="btn" (click)="callToggleSidebarOnToggleSidebarBtn()"><i class="fa fa-reorder"></i></button>
    <div class="d-flex p-0 m-0">
      <a href="#" class="nav-link d-none d-lg-block">Event</a>
      <a href="#" class="nav-link d-none d-lg-block">Contact Us</a>
      <a href="#" class="nav-link d-none d-lg-block">About Us</a>
      <a href="#" class="nav-link d-none d-lg-block"><i class="fa fa-user-circle"></i></a>
    </div>
    <div class="d-flex">
      <a href="#" class="nav-link"><i class="fa fa-bell"></i></a>
      <a href="#" class="nav-link"><i class="fa fa-globe"></i></a>
    </div>
  </nav>
  <div class="d-sm-flex align-items-center justify-content-between" id="secondMenu">
    <div id="logoContainer">
      <img src="../assets/images/logo.png" alt="" id="logo">
    </div>
    <div class="input-group">
      <div class="input-group-prepend">
        <button class="input-group-text btn dropdown-toggle" data-toggle="dropdown">Meeting</button>
        <div class="dropdown-menu">
          <a class="dropdown-item" class="dropdown-item">Action</a>
          <a class="dropdown-item" class="dropdown-item">Another action</a>
          <a class="dropdown-item" class="dropdown-item">Something else here</a>
        </div>
      </div>
      <input type="text" class="form-control" placeholder="What are you looking for ?" aria-label="Search">
      <div class="input-group-append">
        <button class="btn" type="submit"><i class="fa fa-search"></i></button>
      </div>
    </div>
  </div>
<div>

I expected to be able to toggle the content of sidebar.component.html by clicking on the button at the top left of the header. However, I encountered the following error:

ERROR Error: Uncaught (in promise): Error: StaticInjectorError(AppModule) 
[HeaderComponent -> SidebarComponent]: 
  StaticInjectorError(Platform: core)[HeaderComponent -> SidebarComponent]: 
    NullInjectorError: No provider for SidebarComponent!
Error: StaticInjectorError(AppModule)[HeaderComponent -> SidebarComponent]: 
  StaticInjectorError(Platform: core)[HeaderComponent -> SidebarComponent]: 
    NullInjectorError: No provider for SidebarComponent!
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:3228)
at resolveToken (core.js:3473)
at tryResolveToken (core.js:3417)
at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:3314)
at resolveToken (core.js:3473)
at tryResolveToken (core.js:3417)
at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:3314)
at resolveNgModuleDep (core.js:19784)
at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:20473)
at resolveDep (core.js:20844)
at resolvePromise (zone.js:831)
at resolvePromise (zone.js:788)
at zone.js:892
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:16147)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
at drainMicroTaskQueue (zone.js:601)

Answer №1

Components are not to be treated as dependencies that can be injected.

If you wish to achieve a specific functionality, locate the sidebar within your header and create a reference for it:

<app-sidebar #sidebarReference></app-sidebar>

You now have the option to utilize it in your template:

<button (click)="sidebarReference.toggleSidebar()">...</button>

Alternatively, you can access it from your component:

@ViewChild(SidebarComponent) sidebar: SidebarComponent;
// or, if multiple sidebars exist in the template,
@ViewChild('sidebarReference') sidebar: SidebarComponent;
this.sidebar.toggleSidebar();

Answer №2

To streamline the process, rather than directly creating an instance of a sidebar component within the Header component, it is more efficient to establish a service named appService.ts. This can be achieved by executing the following command:

ng generate service app

Within this service file, incorporate the provided code snippet:

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

@Injectable({
  providedIn: 'root'
})
export class AppService {

  flagChange:Subject<boolean> = new Subject<boolean>();

  constructor() { }

  setFlag(flagValue){
    this.flagChange.next(flagValue);
  }
}

After setting up the service, proceed to inject the service instance into our header.component.ts:

import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {

   flag:boolean = false;

  constructor(private appService :  AppService) { }

  ngOnInit() {
  }

  callToggleSidebarOnToggleSidebarBtn() {

    this.appService.setFlag(!this.flag);
  }
}

In the sidebar.component.ts, make the necessary updates as shown below:

import { Component, OnInit } from '@angular/core';
import * as $ from 'jquery';
import { AppService } from './app.service';

@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html',
  styleUrls: ['./sidebar.component.css']
})
export class SidebarComponent implements OnInit {

  constructor(private appService: AppService) { }

  ngOnInit() {
   this.appService.flagChange.subscribe((flag) => {
      $("#sidebar").animate({width: 'toggle'});
    })
  }
}

By implementing this structure, when the user interacts with the icon, the flag status in the header component undergoes a toggle effect. This modification is then relayed and captured via the flagChange variable in the AppService utilizing the next() function, subsequently observed through the subscribe method within the sidebar component.

Answer №3

In order to address this issue, I began by removing the import of the sidebar in header.component.ts along with its constructor. The final version of my header.component.ts looks like this:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }
}

The modifications made are highlighted above.

Next, I included the following code in the header component to establish a reference to the SidebarComponent:

<app-sidebar #sidebarReference></app-sidebar>

With this setup, you can now easily utilize it within your template in header.component.ts

<button class="btn" (click)="sidebarReference.toggleSidebar()"><i class="fa fa-reorder"></i></button>

Answer №4

From what I understand, it is not possible to inject a component into another component. If you need inter-component communication, you have a couple of options: 1. Utilize a service 2. Or utilize @Input or @Output constructs depending on the connection between the components.

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

Is it possible to execute an HTTP request using a functional resolver?

Previously, I used a class-based resolver where I could inject HttpClient in the constructor. However, this approach has now been deprecated - see the source for more information. Now, I am looking to implement an HTTP get request in a functional resolver ...

What exactly does "blocking and tackling" refer to in the Angular2 documentation?

As I delved into the online documentation for angular2, I stumbled upon a puzzling term - "blocking and tackling" in the ADVANCED - Angular Module chapter (https://angular.io/docs/ts/latest/guide/ngmodule.html). ... "It's all just basic blocking and t ...

The value is currently unset in the TypeScript language

The variable `this.engenes_comparte` is showing up as undefined inside the subscribe function, but it works fine outside of it. baja(){ this._restService.getEngines(this._globalService.currentFisherMan.nid).subscribe((data : any[]) => { le ...

Angular 6 - Unlocking the Secrets of Filtered Results

I need help accessing the filteredArray in my .ts component. Currently, it is only accessible within the ng-container. <ng-container *ngIf="(userList | filter: 'name' : value) as filteredArray"> <tr *ngFor="let user of filteredArray ...

Steps for displaying a 404 page on a server-side rendered dynamic route following a client-side page transition

I'm currently developing a next.js project using Contentful as the Content Management System. My goal is to display a 404 page for a server-side rendered dynamic route after a client-side page transition. When I directly request the page (by entering ...

What is the reason behind permitting void functions in the left part of an assignment in Typescript?

Take a look at this Typescript snippet: let action = function (): void { //perform actions }; let result = action(); What makes it suitable for the TypeScript compiler? ...

What is the benefit of utilizing ngSubmit over just using a basic button and function?

Lately, I've been pondering whether to utilize ngSubmit or simply bind a (click)="submit()" on a button. There's been much debate about using submit and ngSubmit, but is it necessary to rely on the traditional HTML submit method? Particularly wh ...

retrieve document data from firestore using the service

Is there a way to get real-time data from a Firestore document using a service? According to Firebase's documentation, you can achieve this by following this link: https://firebase.google.com/docs/firestore/query-data/listen?hl=es#web-modular-api I ...

Combine an array of objects that are dynamically created into a single object

Having trouble transforming the JSON below into the desired JSON format using JavaScript. Current JSON: { "furniture": { "matter": [ { "matter1": "Matter 1 value" }, { "matter2": "Matter 2 value" }, { ...

Organize items within an array based on dual properties rather than a single one

Here is an array of objects that I would like to group based on certain keys (JSON format): [ { "name": "john", "lastName": "doe", "gender": "male" }, { "name": &qu ...

What is the process for transitioning global reusable types to package types within turborepo?

When creating an app within the apps folder, a global.d.ts file is required with specific types defined like this: interface Window{ analytics: any; } This file should be designed to be reusable and placed in the packages/types directory for easy acce ...

Issue with retrieving the positions of two numbers in an array

I encountered a challenge: I have an array of integers nums and an integer target. My goal is to find the indices of two numbers in the array that add up to the specified target. Example 1: Input: nums = [2,7,11,15], target = 9 Output: [0,1] Output: Thi ...

Volar and vue-tsc are producing conflicting TypeScript error messages

During the development of my project using Vite, Vue 3, and TypeScript, I have set up vue-tsc to run in watch mode. I am utilizing VS Code along with Volar. This setup has been helpful as it displays all TypeScript errors in the console as expected, but I ...

Exploring the depths of useDispatch and dispatch in React-Redux

I am currently analyzing the code written by a former colleague of mine. Based on my understanding, useDispatch accepts an object containing the action type and payload, which is then compared to all reducers to update the state accordingly. However, in t ...

Guide on combining vendor CSS files in a React application using Webpack

Incorporating third-party libraries is an essential part of my project. For example, I have Mapbox GL installed via npm, which comes with CSS files needed for its functionality. The Mapbox GL CSS file can be found at mapbox-gl/dist/mapbox-gl.css in the no ...

Tips for implementing HTTP requests in Angular 2 without TypeScript

The demonstrations provided by the angular team only illustrate injecting Http for typescript. https://angular.io/docs/js/latest/api/http/Http-class.html How can this be accomplished in JavaScript? import {Http, HTTP_PROVIDERS} from 'angular2/http& ...

Struggling to integrate Docker compatibility into an established NextJS project, encountering the frustrating "stat app/.next/standalone: file does not exist" message

I'm currently in the process of enhancing my existing NextJS + TypeScript project with Docker support and preparing to deploy it on Google Cloud Run. To achieve this, I've been referring to a helpful guide available at: https://github.com/vercel/ ...

The issue with Angular 2's Parameterised router link component not fully refreshing

I'm trying to figure out how to show a set of images when I click on a specific menu item. The menu structure looks like this: <ul id="demo23" class="collapse"> <li> <a [routerLink]="['image-gallery','Picasso ...

Tips for utilizing a ternary operator to set a className in an element

I'm in the process of developing a website using React and Next.js. One of the components on my site is section.tsx, which displays a subsection of an article based on the provided props. I'm looking to add an 'align' property to this c ...

What might be the underlying reason for Chrome displaying a net::ERR_FAILED error when attempting to make a request from a Vue frontend to a C# API using Axios?

I have a C# Backend+API that I interact with from my Vue Application using axios to make requests. In the C# code, there is an endpoint that looks like this: // GET: api/Timezone public HttpResponseMessage GetTimezoneData() { ...