J'ai essayé de faire en sorte que mon composant de barre d'outils émette des données vers un autre composant (dat.gui -> three.js). Ce que j'ai supposé qu'il faudrait créer, c'est créer un émetteur de sortie et cela fonctionne, mais cela ne fonctionne pas d'une manière ou d'une autre. Il n'y a pas de code html réel à l'intérieur de ces composants.
Tout ce que j'ai à faire est d'émettre l'événement avec l'interface contenant des données (actuellement juste un booléen , mais sera développé plus tard). Mon projet est également sur github, si cela serait plus clair. J'ai lu sur une variété de façons de travailler avec Angular, mais je suis encore assez nouveau. À cet égard, si j'ai fait une erreur stupide, veuillez me le dire car je n'ai aucune idée de ce que je fais de mal ici.
https://github.com/GrimZero/ConfiguratorAngular
settngs.service.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();
}
}
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 p>
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class SettingsService {
$dataChange: Subject<any> = new Subject<any>();
}
3 Réponses :
Vous ne pouvez utiliser @Output que pour transmettre les données du composant enfant au composant parent. Je pense qu'ici votre approche est erronée
Vous devez donc y parvenir en utilisant un service:
Définition d'un service comme ci-dessous
import { SettingsService } from '../settings.service';
Assurez-vous pour l'ajouter à votre app.module.ts
import { SettingsService } from '../settings.service.js';
Et l'injecter dans ThreejsComponent et l'utiliser comme ci-dessous
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();
});
}
}
Dans ToolbarComponent utilisez comme ci-dessous:
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);
});
}
}
J'ai vérifié votre code git, le problème avec vos importations, veuillez changer l'importation de ThreejsComponent
@NgModule({
providers: [
MyService
]
})
en
@Injectable()
export class MyService {
$dataChange: Subject<any> = new Subject<any>();
}
J'espère que ce sera vous aider!
Hmm cela n'a pas vraiment fonctionné. Cela me donne une erreur assez importante en disant que mon UpdateWebGL n'est pas une fonction. Naturellement, parce que ma barre d'outils n'a pas cette fonction. Cela mettra à jour ma scène et doit donc être appelé dans le threejs.component pour référencer correctement les données. Cependant, ces composants ne sont pas liés les uns aux autres et je ne suis pas non plus totalement attaché à cette approche. Tout ce dont j'ai besoin, c'est d'une interface passant entre les composants et d'appeler une fonction lorsque cela se produit.
oui, c'est correct car ce n'est pas dans votre composant de barre d'outils. vous devez le définir ici. ou vous avez défini votre événement dans un mauvais composant
Mais si je le définit là-bas, je dois référencer le threejs.component pour pouvoir le mettre à jour ou accéder aux données? N'est-ce pas juste une version inversée de ce que j'ai?
Hmm. semble être que vous devez utiliser un service pour ce faire et définir une variable de type Subject pour transmettre vos données
vous ne pouvez utiliser @Output que pour transmettre les données du composant enfant au composant parent. Je pense qu'ici votre approche est fausse
J'ai essayé d'injecter le service dans le constructeur, mais il n'accepte pas this.service.subscribe () dans le ngOnInit (), la seule chose à laquelle je peux accéder est la propriété dataChange.
désolé, j'ai fait une erreur. Je l'ai corrigé s'il vous plaît vérifier. devrait être comme ceci this.myService. $ dataChange.subscribe
D'après ce que je comprends jusqu'à présent, les services ressemblent à un singleton en c # (que je connais bien). Cependant, je ne peux pas le faire fonctionner encore ... J'ai exactement suivi votre code et tout a du sens pour moi. pourtant je n'obtiens aucun événement à capturer.
dose ne pas déclencher la méthode this.myService. $ dataChange.subscribe? quand onChange () est appelé
J'ai vérifié que la méthode onChange est appelée, et c'est le cas. onChange est déclenché mais l'abonnement au service ne semble pas répondre.
$ dataChange aime-t-il ceci $ dataChange: Subject sur le service?
J'ai mis à jour ma question avec la situation actuelle. Je compare actuellement le vôtre et le mien.
J'ai vérifié votre code git le problème avec vos importations s'il vous plaît changer l'importation de ThreejsComponent import {SettingsService} de '../settings.service.js'; à importer {SettingsService} depuis '../settings.service'; alors cela devrait fonctionner
Il semble que vous ayez incorrectement déclaré votre événement:
<app-threejs (change)="hello($event)"></app-threejs>
export class ThreejsComponent implements OnInit {
hello(event:any) {
console.log(event);
}
}
et dans votre composant app-threejs , vous devez gérer (change) événement:
export class ToolbarComponent implements OnInit {
settingsData: Settings;
@Output() change: EventEmitter<Settings> = new EventEmitter<Settings>();
onClick(){
this.change.emit(this.settingsData);
}
Premièrement, Output émet un événement du composant enfant au composant parent, et dans votre code il n'y a pas de relation parent-enfant dans votre code (vous pouvez aller avec des services dans ce cas). Mais pour gérer les événements à l'aide de composants parent-enfant, vous devez effectuer les modifications ci-dessous,
Dans app.component.html , vous devez inclure uniquement le composant threejs.
<app-toolbar><app-toolbar> <!-- when the emit function get called to looks for the parent component from here -->
Ajouter une barre d'outils dans threejs.component.html comme,
<app-threejs (event)='UpdateWebGL($event)'><app-threejs>
Serais-je préférable d'utiliser un service pour cela? Gardez à l'esprit qu'il s'agit d'une preuve de concept et d'un test de performance? Ou devrais-je pas vraiment prendre la peine de le faire dans ce cas?