I have a nested set of StencilJS components. I would like to attach a function to my nested component so that my React app, which hosts the parent component, can read.
Example
<pw-actionbar
actions={getActions}
/>
In this actionbar component, I have another nested button
component. It looks like this
return (
<Host>
<div class="container">
{
// iterate through array
this.actions.map((action) => {
// take object.icon and make an icon
const XmlIcon = `${action.icon}`;
==> I WANT A FUNCTION ON PW-BUTTON THAT PASSES 'action' which my react app reads
return <pw-button-side-menu
// shade the selected pages button
isselected={action.onpage ? 'selected' : 'notselected'}
class="displace"
>
<span slot="label">{action.name}</span>
<i slot="icon">
<XmlIcon
class="icon-position"
fillcolor={this.iconfillcolor}
strokecolor={this.iconstrokecolor}/>
</i>
</pw-button-side-menu>
})
}
</div>
</Host>
);
}
My react app has some component
functionEmittedFromPwButton(action) {
console.log(action) <=== I WANT THIS TO WORK IN MY REACT APP WHICH IS EMITTED FROM THE PW-BUTTON COMPONENT NESTED IN THE PW-ACTIONBAR COMPONENT
}
return (
<MyComponent>
<pw-actionbar actions={getActions}/> <=== that takes an array of objects. I want to capture the 'action' object emitted by the pw-button nested in this component in my react app
</MyComponent>
)
I have tried all sorts of different methods like this one to try to emit the object from stencil to react
On the stenciljs side
import { Component, h, Host, Prop, Event, EventEmitter } from "@stencil/core";
@Component({
tag: "pw-actionbar",
styleUrl: "pw-actionbar.scss",
shadow: true,
})
export class PwActionbar {
@Prop() actions: any = [];
@Prop() iconfillcolor: "white" | "black" = "white";
@Prop() iconstrokecolor: "white" | "black" = "white";
@Event() emitAction: EventEmitter;
render() {
const handleClick = (action) => {
this.emitAction.emit(action);
};
return (
<Host>
<div class="container">
{
// iterate through array
this.actions.map((action) => {
// take object.icon and make an icon
const XmlIcon = `${action.icon}`;
// cast the button
return (
<pw-button-side-menu
// shade the selected pages button
isselected={action.onpage ? "selected" : "notselected"}
class="displace button-lines"
onClick={() => handleClick(action)}
>
<span slot="label">{action.name}</span>
<i slot="icon">
<XmlIcon
class="icon-position"
fillcolor={this.iconfillcolor}
strokecolor={this.iconstrokecolor}
/>
</i>
</pw-button-side-menu>
);
})
}
</div>
</Host>
);
}
}
On the react side
const handleAction = async (action, history, i18n) => {
Metrics.track("Changed Page", { action });
if ("sign-out" === action) {
await authActions.logout();
history.push(`/${i18n.locale}`);
} else if ("help-desk" === action) {
history.push(`/${i18n.locale}/zendesk`);
} else if ("advisors" === action) {
pageActionsObjAdmin[0].onpage = true;
history.push(`/${i18n.locale}/admin/advisors`);
} else if ("users" === action) {
pageActionsObjAdmin[1].onpage = true;
history.push(`/${i18n.locale}/admin/users`);
} else if ("forecast" === action) {
pageActionsObjAdmin[3].onpage = true;
history.push(`/${i18n.locale}/admin/forecast`);
} else if ("stats" === action) {
pageActionsObjAdmin[4].onpage = true;
history.push(`/${i18n.locale}/admin/stats`);
}
};
const Layout = ({ children }) => {
const { i18n } = useLingui();
const [, setContext] = useContext(StripeErrorContext);
const history = useHistory();
useEffect(() => {
const listener = (e) => {
// set page button to be "Active"
pageActionsObjAdmin.forEach((element) => {
element.onpage = false;
});
handleAction(e.detail.page, history, i18n, setContext);
};
// listen for events emitted form the action bar
document.body.addEventListener("emitAction", listener);
return () => {
document.body.removeEventListener("emitAction", listener);
};
}, []); // eslint-disable-line
// refs for the actionbar
const elementRef = useRef(null);
useEffect(() => {
if (elementRef.current !== null) {
elementRef.current.actions = pageActionsObjAdmin;
}
}, [elementRef]);
return (
<Wrapper>
<Header />
<BodyLayout>
<pw-actionbar
ref={(el) => (elementRef.current = el)}
style={{ paddingTop: "56px", zIndex: "99" }}
class="action-bar"
/>
<div className="main-layout" style={{ width: "100%" }}>
{children}
</div>
</BodyLayout>
</Wrapper>
);
};
export default Layout;