Reputation: 935
I am trying to understand the flow of the custom event emitter. I have the rolling code where the mouse events work but not the custom events. Tracing it through dev tools, it is emitting but not getting picked up by the listener.
The top-level component is here:
import { Component, Prop, Listen, State, Event, EventEmitter } from "@stencil/core"
@Component ({
tag: "control-comp"
})
export class SmsComp1 {
@Prop() compTitle:string;
@State() stateData: object = {name: "Fred"};
@Event() stateChanged: EventEmitter;
@Listen('inBox')
inBoxHandler(ev) {
console.log('In box', ev);
this.stateData["name"] = ev.name;
console.log('Emitting')
this.stateChanged.emit(this.stateData);
}
render () {
let index = [1, 2, 3, 4, 5]
return (
<div>
<h1>{this.compTitle}</h1>
{index.map( (i) => {
return <my-component first={i.toString()} last="Don't call me a framework" width={i*40} height={i*40}></my-component>
})}
<my-component first={this.stateData["name"]} last="'Don't call me a framework' JS"></my-component>
</div>
)
}
}
The component is here:
import { Component, Prop, Listen, State, Event, EventEmitter } from '@stencil/core';
@Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true
})
export class MyComponent {
@Prop() first: string;
@Prop() last: string;
@Prop() width: number = 120;
@Prop() height: number = 100;
@State() colour: string = 'red';
@Event() inBox: EventEmitter;
@Listen('mouseover')
clickHandler() {
this.colour = 'white';
this.inBox.emit({action: 'IN_BOX',
name: this.first+' '+this.last})
}
@Listen('mouseout')
mouseOutHandler() {
this.colour = 'red';
}
@Listen('stateChanged')
stateChangedHandler(state) {
console.log('Received', state);
}
render() {
return (
<svg width={this.width+10} height={this.height+10}>
<rect width={this.width} height={this.height} fill='green'></rect>
<circle cx={this.width/2} cy={this.height/2} r={this.width*0.1} fill={this.colour}></circle>
<text fill='white' x='10' y='10'>{this.first+' '+this.last}</text>
</svg>
);
}
}
Finally the index.html is here:
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0">
<title>Stencil Component Starter</title>
<script src="/build/mycomponent.js"></script>
</head>
<body>
<control-comp compTitle="Stencil Example"></control-comp>
<my-component first="My Dead" last='Component' width=100 height=120></my-component>
</body>
</html>
Can you suggest why the stateChanged event is not being noticed by my-component
?
Upvotes: 0
Views: 7217
Reputation: 4339
Maybe it's to late but you can use the options for @Listen
export interface ListenOptions {
target?: 'parent' | 'body' | 'document' | 'window';
capture?: boolean;
passive?: boolean;
}
(Source: https://stenciljs.com/docs/events#listen-s-options)
If you attach the Listener to document
you will get the expected event
@Listen('inBox', { target: 'document' })
...
Upvotes: 6
Reputation: 1862
Stencil events, like other CustomEvent
s only bubble up a component tree, not down.
Since my-component
is a child of control-comp
, the parent's stateChanged
event can't seen by control-comp
.
You'll want to find another approach to have a parent communicate to a child component. The "standard" way to do this is to set a @Prop
and maybe a @Watch
on the child, and update the prop in the parent's render()
function.
Or, you could use a more robust approach like stencil-redux or stencil-state-tunnel.
Upvotes: 3