Search code examples
angulartypescriptdat.gui

EventEmitter not catching event


I've been trying to get my toolbar component to emit data to another component (dat.gui -> three.js). What I assumed would be needed is creating an output emitter and that is working, but it is not working somehow. There is no actual html code inside these components.

All I need to do is emit the event with the interface holding data (currently just a boolean, but will be expanded later). My project is also on github, if that would be clearer. I ve been reading up on a variety of ways to work with Angular, but am still pretty new. In that regard, if I made a dumb mistake please tell me because I have no idea what I am doing wrong here.

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();
  }
}


Solution

  • You could only use @Output to pass data from child component to parent component. I think here your approach is wrong

    So you have to achieve it by using a service:

    Defined a Service like bellow

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

    Make sure to add it to your app.module.ts

    @NgModule({    
        providers: [
            MyService
        ]
    })
    

    And inject it to ThreejsComponent and use it like bellow

    export class ThreejsComponent implements OnInit {
      threejs: Threejscontroller;
    
      constructor(private myService: MyService) { }
    
      UpdateWebGL = (settingsData: Settings) => {
        console.log('recieved message');
    
        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 use like bellow:

    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();
        });
      }
    }
    

    I checked your git code, the issue with your imports please change the import of ThreejsComponent

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

    to

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

    Hope this will help you!