EventEmitter does not properly capturing the event

I have been attempting to make my toolbar component send data to another component (dat.gui -> three.js). I thought creating an output emitter would be necessary, and while it is set up, it doesn't seem to be functioning properly. These components do not contain any actual HTML code.

All I want to do is emit the event with the interface containing data (currently just a boolean, but will expand in the future). My project is available on GitHub if that would help clarify things. I have been researching different ways to work with Angular, but as a beginner, I may have made a mistake. If so, please point it out as I am unsure of what I am doing wrong.

https://github.com/GrimZero/ConfiguratorAngular

settngs.service.ts

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

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

  $dataChange: Subject<any> = new Subject<any>();
}

toolbar.component.ts

import { GUI } from './../../../node_modules/three/examples/jsm/libs/dat.gui.module';
import { Settings } from '../settings';
import { SettingsService } from '../settings.service';

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

})
export class ToolbarComponent implements OnInit {
  settingsData: Settings;

  constructor(private service: SettingsService) {
    this.settingsData = this.defineSettings({ TimeNight: false });
  }

  defineSettings(config: Settings) {
    const settings = { TimeNight: true };

    if (config.TimeNight) {
      settings.TimeNight = config.TimeNight;
    }

    return settings;
  }

  onChange() {
    this.service.$dataChange.next(this.settingsData);
    console.log('emitted');
  }

  ngOnInit() {
    const gui = new GUI();
    gui.add(this.settingsData, 'TimeNight').onChange(() => {
      this.onChange();
    });
  }
}

threejs.component.ts

import { Component, OnInit } from '@angular/core';
import { Material } from '../material.js';
import { TimeOfDay } from '../time-of-day.js';
import { Threejscontroller } from '../threejscontroller.js';
import { SettingsService } from '../settings.service.js';


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

  constructor(private service: SettingsService) { }

  updateWebGL = (settingsData: any) => {
    console.log('recieved message');

    if (!settingsData.TimeNight) {
      new TimeOfDay().SetTimeDay(this.threejs.scene);
    } else {
      new TimeOfDay().SetTimeDusk(this.threejs.scene);
    }
  }

  ngOnInit() {
    this.service.$dataChange.subscribe((value: any) => {
      console.log(value);
      // this.updateWebGL(value);
    });

    this.threejs = new Threejscontroller();
    this.threejs.update();
  }
}

Answer №1

To transfer data from a child component to a parent component, the use of @Output is necessary. It seems like there might be an issue with your current approach.

In order to achieve this, consider implementing a service:

Create a service as shown below:

@Injectable()
export class MyService {
    $dataChange: Subject<any> = new Subject<any>();
}

Make sure to include it in your app.module.ts

@NgModule({    
    providers: [
        MyService
    ]
})

Inject this service into ThreejsComponent and utilize it as illustrated below:

export class ThreejsComponent implements OnInit {
  threejs: Threejscontroller;

  constructor(private myService: MyService) { }

  UpdateWebGL = (settingsData: Settings) => {
    console.log('message received');

    if (!settingsData.TimeNight) {
      new TimeOfDay().SetTimeDay(this.threejs.scene);
    } else {
      new TimeOfDay().SetTimeDusk(this.threejs.scene);
    }
  }

  ngOnInit() {
    this.threejs = new Threejscontroller();
    this.threejs.update();

    this.myService.$dataChange.subscribe((value: any) => {
            this.UpdateWebGL(value);
        });
  }
}

In ToolbarComponent, implement it in the following way:

export class ToolbarComponent implements OnInit {
  settingsData: Settings;

  @Output() event: EventEmitter<Settings> = new EventEmitter<Settings>();

  constructor(private myService: MyService) {
    this.settingsData = this.defineSettings({ TimeNight: false });
  }

  defineSettings(config: Settings) {
    const settings = { TimeNight: true };

    if (config.TimeNight) {
      settings.TimeNight = config.TimeNight;
    }

    return settings;
  }

  onChange() {
    this.myService.$dataChange.next(this.settingsData);
    console.log("emitted");

  }

  ngOnInit() {
    const gui = new GUI();
    gui.add(this.settingsData, 'TimeNight').onChange(() => {
      this.onChange();
    });
  }
}

After reviewing your git code, I noticed an issue with your imports. Please modify the import statement for ThreejsComponent as follows:

import { SettingsService } from '../settings.service'; 

I hope this information proves helpful!

Answer №2

It seems like there is a mistake in how you're declaring your event:

export class ToolbarComponent implements OnInit {
  settingsData: Settings;

  @Output() change: EventEmitter<Settings> = new EventEmitter<Settings>();


  onClick(){
    this.change.emit(this.settingsData);
  }

Additionally, make sure to handle the (change) event in your app-threejs component:

<app-threejs (change)="hello($event)"></app-threejs>


export class ThreejsComponent implements OnInit {
    hello(event:any) {
        console.log(event);
    }
}

Answer №3

Initially, Output sends an event from child to parent component. However, in the given code, there is no parent-child relationship established (consider using services). To handle events between parent and child components, make the following adjustments:

In app.component.html, only include the threejs component.

<app-threejs (event)='UpdateWebGL($event)'></app-threejs>

Include a toolbar in threejs.component.html as follows:

<app-toolbar></app-toolbar> <!-- This is where the emit function will look for the parent component -->

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

Please upload a collection of chosen files

function uploadImages(images: FileList) { const formData = new FormData(); formData.append('images', images); return this.http.post(`url`, formData); } console.log(images) shows a FileList with uploaded files. What is the best way to se ...

Tips for resolving the error message "termsOfUse must be a boolean type, but the final value was: 'on'," using a combination of Ionic, React, Yup, and Resolvers

I need to develop a registration form with all fields mandatory using React Hook Form and Yup for validation. The issue I'm facing is related to two checkboxes that are required. Upon form submission, I encounter the following error message for the ch ...

Tips for sending information back to the previous screen in React Native Navigation version 5

Recently, I upgraded to react native navigation version 5 and now I am facing an issue with sending data back to the previous screen when making a goBack() call. To navigate to the next view, I use: const onSelectCountry = item => { console.log(it ...

Encountering difficulties upgrading to Angular 8 as the necessary command cannot be located

Looking to enhance my ionic application, I embarked on the journey of upgrading. Initially, I attempted using ng update However, it was met with an error message saying bash: ng: command not found Determined to make progress, I then turned to np ...

Validating forms in Angular 6 upon submission

In my current scenario, I am faced with the need to validate fields only upon submission. Due to the complexity of my form, which includes FormArrays and FormGroup, I have segmented it into multiple components such that each component represents a distinc ...

Mapping fields in Angular collectively

I'm currently working on implementing a modal, and I'm looking to link values from the formBuilder to a specific property. Here's the snippet of code I'm working with: submit(data?: any) { // THE FOLLOWING CODE WORKS, BUT IT'S ...

Eliminate unnecessary spacing from the sticky container

Trying to implement a sticky menu in an angular 14 project using angular material 14 has been quite challenging for me. Initially, I attempted to use the 'fixed' position, but encountered issues where the menu would consistently return to the to ...

Exploring function overloading in Typescript using custom types

I encountered an issue here that I believe has 2 possible solutions. Let's start with my initial implementation using function overloading: type PostgresConnectionOptions = { dialect: "postgres"; config: pg.PoolConfig; }; type MysqlConne ...

Utilizing a compiled Electron application built with Angular and ready to launch

I am facing an issue with my Electron app that is built using Angular. Everything works perfectly until I package the app as an installable one with electron-builder. After installation, when I run the app, it opens up with a blank screen. Upon checking th ...

Exploring Real-Time Typescript Validation in Next.JS

Checking for TypeScript errors in Next.JS can only be done with npm run build (or yarn build). Unfortunately, running npm run dev won't display TypeScript errors, which is quite inconvenient as it would be better to have them visible in the Terminal ...

What could be causing the malfunction of getter/setter in a Vue TypeScript class component?

Recently delving into the world of vue.js, I find myself puzzled by the unexpected behavior of the code snippet below: <template> <page-layout> <h1>Hello, Invoicer here</h1> <form class="invoicer-form"> ...

What is the recommended TypeScript type for the NextJS _app.tsx Component and pageProps?

Take a look at the default _app.tsx code snippet from NextJS: function MyApp({ Component, pageProps }) { return ( <Component {...pageProps} /> ) } The issue arises when transitioning to TypeScript, as ES6Lint generates a warning indicating t ...

Adding a new key to a specific position in an array using Angular

After organizing my array, here is what it currently looks like: 0: Object { row: 0 } 1: Object { row: 1 } 2: Object { row: 2 } 3: Object { row: 3 } Now, I need to add a new key to position 2. The updated structure should resemble this: 0: Object { row: 0 ...

Textbox within ng-for directive will be displayed only if there is data available

I am currently working with Angular and have encountered an issue. I have implemented text boxes on a page, and upon clicking a button, I retrieve data from a database and display it in the textbox. The textbox remains hidden until the data is loaded. As ...

How can a particular route parameter in Vue3 with Typescript be used to retrieve an array of strings?

Encountered a build error: src/views/IndividualProgramView.vue:18:63 - error TS2345: Argument of type 'string | string[]' is not assignable to parameter of type 'string'. Type 'string[]' is not assignable to type 'strin ...

Util Deprecations resolved with TSLint Autofix

Is there a feature in VSCode that can automatically fix deprecations related to the util library? For example: if (isNullOrUndefined(this.api)) { Would be better written as: if (this.api === null || this.api === undefined) { While there isn't an ...

Encountering challenges when trying to incorporate error-handling functionality into Highcharts

I've been attempting to incorporate custom error handling in Highcharts by utilizing the Highcharts.error function within my Angular 7 application, but it's resulting in an error. Highcharts.error = function (code: string): void { }; Error T ...

Is there a way to define type information for a global variable when utilizing dynamic import within a function?

Here is a simplified version of my server code: server.ts import google from "googleapis"; const androidPublisher = google.androidpublisher("v3"); app.use('something', function(req, res, n){ ... }) ...(only one of the dozens of other meth ...

Using a custom validator in Angular that accepts an array as input

My special code: <input mdInput [mdAutocomplete]="auto" [(ngModel)]="formData.areaName" (keyup)="updateFilteredAreas(formData.areaName)" class="form-control {{areaName.errors ...

Ways to secure mat tab for verification

When clicking on a mat tab, I want it to display a warning asking if the user is sure. If the user selects yes, then the tab should change; otherwise, the user should remain on the same tab. However, currently, when I click on a tab, it changes before sh ...