Webcomponent Custom Element pass function onClick - javascript

I want to pass a function to Custom Element using ReactJS
ReactJS Component
import React from 'react';
import './SampleComponent';
export class Button extends React.Component {
handleClick = (event) => {
console.log(event)
}
render() {
return (
<div>
<sample-component onclick="handleClick"></sample-component>
</div>
)
}
};
Custom Element
class SampleComponent extends HTMLElement {
static get observedAttributes() {
}
// custom methods
render() {
this.innerHTML = `Custom Element`;
}
// lifecycle hooks
connectedCallback() {
this.render();
}
}
window.customElements.define('sample-component', SampleComponent);
As I understand, when I pass onclick function handleClick JS will search for it in Custom Element implementation (that's why I get an error in console). So how to pass a function? I tried "this.handle" but it also didn't work.

Due to the react Documentation you html should look like this
<sample-component onClick={handleClick}></sample-component>

Related

How to pass callback function to litelement from React?

I'm trying to use lit-element component in my React project, and I'd like to pass in the callback function to lit-element component from React but with no luck.
I've tried a couple of different ways, like change property type, and pass function in as a string, but none of them works.
lit-element component code:
import { LitElement, html } from "lit-element";
class MyButton extends LitElement {
static get properties() {
return {
clickHandler: {
type: String
},
bar: {
type: String
}
};
}
render() {
const foo = this.clickHandler; //value is undefined
const bar = this.bar; //value is "it's bar"
return html`
<button #click=${this.clickHandler}>click me</button>
`;
}
}
customElements.define("my-button", MyButton);
react side code:
<my-button clickHandler={() => alert("clicked")} bar="it's bar" />
I put a break point in the render section of the component, and I can see the 'bar' value get passed in correctly, but the value of 'clickHandler' is undefined.
Does anyone have any idea on how to pass function from React to lit-element?
Thanks!
This question probably isn't just valid for react. It's quite general, how do I pass a handler from parent to child component, either it's a lit-element or html element.
According to the property doc, https://lit-element.polymer-project.org/guide/properties
<my-element
mystring="hello world"
mynumber="5"
mybool
myobj='{"stuff":"hi"}'
myarray='[1,2,3,4]'>
</my-element>
Doesn't seem that it supports (callback) function at the moment. So how does Element handle event from parent level ?
According to the event doc, https://lit-element.polymer-project.org/guide/events, you can dispatch any event to the dom tree, including your parent. Dom event system is much broader than React prop system.
class MyElement extends LitElement {
...
let event = new CustomEvent('my-event', {
detail: {
message: 'Something important happened'
}
});
this.dispatchEvent(event);
}
and then in either lit or non-lit context, use the following to handle the event,
const myElement = document.querySelector('my-element');
myElement.addEventListener('my-event', (e) => {console.log(e)});
This way you can allow children to fire implementation for parent, which is exactly the definition for callback.
What I found that works is adding a ref in the react component to the lit element, then literally setting the property on it.
So, for the following JSX:
<some-webcomponent ref={this.myRef}></some-webcomponent>
You can pass a property to ‘some-webcomponent’ in i.e. componentDidMount:
componentDidMount () {
const element = this.myRef.current;
element.someCallback = () => // ...
}
It’s not too pretty, but I wouldn’t consider it a hack either. Requires quite a lot of boilerplate though :/
Here’s a full React component for reference:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <some-webcomponent ref={this.myRef}></some-webcomponent>;
}
componentDidMount() {
const element = this.myRef.current;
element.someCallback = () => console.log(“call!”);
}
}
Where the lit element is:
import { LitElement, html } from "lit-element";
class SomeWebcomponent extends LitElement {
static get properties() {
return {
someCallback: { type: Function }
};
}
render() {
return html`
<button #click=${this.someCallback}>click me</button>
`;
}
}
customElements.define("some-webcomponent", SomeWebcomponent);
Have a look at the menu button click function for the no redux pwa-starter-kit at https://github.com/Polymer/pwa-starter-kit/blob/template-no-redux/src/components/my-app.js. I believe that provides the example that may work for you.

React pass function to dynamic created child with additional parameter

I want to dynamically create child components, receiving an onClick event from their parent/grandparent component in React. During the creation I want to add a parameter to the onClick-event. Basically the desired flow is:
When rendering parent component
Pass the reference to the desired function to the creation of the dynamic component
In process of creating the dynamic component I want to add a parameter, defined by the creator
the onClick event in the child should call the onClick function in the parent using the parameter it got from the creator of the dynamic component
For the code: this is the dynamic component creator and the parent
import React from 'react';
// This is the creator of my dynamic components
// It currently sets this.props.name as parameter for the parent function
class CreateComponent extends React.Component {
render(){
return(
<div className="childBox">
// this.props.component is a react component of type ImageBox (see next code block)
{React.cloneElement(this.props.component, {
open: this.props.open(this.props.name),
close: this.props.close,
})}
</div>
)
}
}
// This is the parent component, using the creator and some state to open/close different components
export class DynamicContentGrid extends React.Component {
constructor() {
super();
this.state = { activeComponent: '' };
}
close() {
this.setState({ activeComponent: '' });
}
open(component) {
this.setState({ activeComponent: component })
}
render() {
console.log(this.props.children);
return(
<div className={css(styles.grid)}>
<div className={css(styles.boxUpperLeft, styles.box)}>
<CreateComponent
component={this.props.children['upperLeft']}
name='upperLeft'
open={() => (name) => this.open(name)}
close={() => this.close()}
/>
</div>
</div>
)
}
}
export default DynamicContentGrid;
And here comes the very basic child component using this.props.close without parameters (they should be set in the creator):
import React from 'react';
export class ImageBox extends React.Component {
render() {
const {title, link, img} = this.props.content.front;
return(
<div>
<h1>{title}</h1>
<h2 onClick={this.props.open}>{link}</h2>
<img src={img} />
</div>
)
}
}
export default ImageBox;
What works
The dynamic rendering of child components works fine.
Where it breaks
As you can see, the magic happens in open={() => (name) => this.open(name)}. What I want is: pass this.open to the creator, set open(name) as parameter and pass on the open function to the child.
Everything works fine, if I said the "name" parameter directly in the parent, but for several reasons I do not want to do this. So I need some kind of currying but I can't figure out, what is wrong. The parameter "name" is not properly set in the creator at the moment.
In CreateComponent set open: () => this.props.open(this.props.name).
Also, remove () => (name) => this.open(name) and replace with this.open and put this.open = this.open.bind(this); into the constructor.

how to render jsx of function from child component in parent component

I am having a child component a parent component. I am having a function in child component which returns some jsx what i want to do is use that function to return the same jsx in parent component but iam unable to figure out a way to do that. I am giving my minimal code:
parent component:
class App extends Component {
render() {
return (
<div className="App">
<Player ref={instance=>{this.player = instance}} />
{this.player.func('aaa.com','bbb')}
</div>
);
}
}
export default App;
Child component:
import React, { Component } from "react";
class Player extends Component {
func = (url, label) => {
return (
<button onClick={() => this.func(url)}>
{label}
</button>
)
}
render() {
return <div>1</div>;
}
}
export default Player;
Error: Cannot read property 'func' of undefined
//
Note: i know i can use the jsx in parent component by copy-pasting but iam trying to figure out a way of doing like this. I am having doubt that is it even possible
You can create a Player object and access the function using that object.
new Player().func('aaa.com','bbb')
I don't quite understand what you need exactly but I think that you're looking to pass some jsx element from the Child component to the parent component. What we can do is declare a propType callback on the child component and then implement it on the parent component like so.
import React from 'react';
class Hello extends React.Component {
constructor() {
super();
this.state = {
// this state will keep the element returned by the parent
returnElements: null
}
this.onReturn = this.onReturn.bind(this);
}
// this method will be fired when the Child component returns callback for onSomethingReturned
onReturn(element) {
this.setState({
returnElements: element
})
}
render () {
return (
<div>
<h1>Hello, React!</h1>
<Child onSomethingReturned={this.onReturn} />
{/* I am going to display the state here */}
{this.state.returnElements}
</div>
)
}
}
class Child extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
const element = <h3>this is child element</h3>;
// will call the propType callback function with a element I want to return
this.props.onSomethingReturned(element);
}
render() {
return (null);
}
}
export default Hello;

Reactjs pass html element on onclick

I'm new to React and I'm trying to pass the HTML element from an onClick event, but I'm not getting the expected result.
Here is the code:
import React, { Component } from 'react';
export class Header extends Component{
isScrolledIntoView (e){
console.log('html element is ',e)
}
render(){
return(
<div>
<button onClick={this.isScrolledIntoView.()}>Click me</button>
</div>
);
}
}
The desired output would be to get the button's HTML element in the console.
You need to capture the target of the e (event) instead of the event itself, like this:
import React, { Component } from 'react';
export class Header extends Component {
isScrolledIntoView (e) {
console.log('html element is ', e.target)
}
render() {
return (
<div>
<button onClick={this.isScrolledIntoView.bind(this)}>Click me</button>
</div>
);
}
}
Here is a demo link: https://codesandbox.io/s/y8xXqopM7
Hope it helps!
The method isScrolledIntoView() is bound to the class, not the component instance, so when you refer to this.isScrolledIntoView() in your render method it will return undefined. Regular React lifecycle methods are bound to the component instance, but for your own custom methods you need to do a little work, you can put it in the constructor:
constructor(props) {
this.isScrolledIntoView = this.isScrolledIntoView.bind(this);
}
Or you can use class properties to auto-bind the method:
isScrolledIntoView = (e) => {
// do stuff
}
2 things you need to change in your code.
1- You have to bind your isScrolledIntoView, and it could be inside your constructor, or doin' this => <button onClick={this.isScrolledIntoView.bind(this)}>Click me</button>
2- You should target your e event instead of only log e you should
=> console.log('html element is ', e.target)
Nice reading for novices in react
Passing current element using ref
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}
render() {
return (
<button className="square"
onClick={function(ref) { console.info(" click : " + ref.target.innerHTML); }}>
{this.props.value}
</button>
);
}
}
Credits : https://stackoverflow.com/ about using "ref"

How can I append external DOM to React component?

I have a page with a form rendered in the server, it handles validation, and the correct value for the selects.
I want to hide the DOM of that form, and append it into a react component so I can use it in react-router.
const NewItem = React.createClass({
render() {
return (
<div>
<h1>New item</h1>
{/* I WANT THE FORM FROM THE PAGE HERE*/}
</div>
)
}
})
What is the best way to do it?
You have full access to the DOM in componentDidMount. You can use refs to access the specific DOM element you want.
var NewItem = React.createClass({
componentDidMount: function () {
this.refs.formTarget.appendChild(myFormDomElement);
},
render: function () {
return React.DOM.div(null,
React.DOM.h1(null, "New item"),
React.DOM.div({ref: "formTarget"}));
}
});
Note that in 0.14, a ref is a raw DOM element. Prior to that a ref was a react component and you had to call React.findDOMNode(it) to get the actual DOM element.
React > 16.3
Try using portals like in this component:
import {Component} from 'react';
import {createPortal} from 'react-dom';
import PropTypes from 'prop-types';
class DOMPortal extends Component {
constructor(props) {
super(props);
this.el = document.createElement(props.component);
}
componentDidMount() {
this.props.parentEl.appendChild(this.el);
}
componentWillUnmount() {
this.props.parentEl.removeChild(this.el);
}
render() {
return createPortal(
this.props.children,
this.el,
);
}
}
DOMPortal.propTypes = {
parentEl: PropTypes.object.isRequired,
component: PropTypes.string,
};
DOMPortal.defaultProps = {
component: 'div',
};
Now you can pass your external DOM reference as the parentEl props to it:
<DOMPortal parentEl={decorator.contentWidget.domNode}>...children</DOMPortal>
React < 16.3
Using this.refs is "deprecated", try this instead :
render() {
return <div ref={(DOMNodeRef) => {
this.componentRef=DOMNodeRef;
}}>
...
</div>;
}
Then this.componentRef will be accesible in componentDidMount() so you can append your external DOM element:
componentDidMount(){
this.componentRef.appendChild(externalDOMelement);
}
Notes:
Remember that this.componentRef changes over time (renders()), so you must update it wherever you are passing it to.
Check for a defined reference before using it: if(this.componentRef){// ... your code}
Functional Components' refs are handled differently.
Source:
React Doc
React gives us the functionality dangerouslySetInnerHTML. it gives us the support of adding HTML element. for example
function createMarkup() {
return {__html: 'First · Second'};
}
function MyComponent() {
return <div dangerouslySetInnerHTML={createMarkup()} />;
}
You can also use portals introduced in react-16 for appending React component anywhere in the tree by using following code.
ReactDOM.createPortal(child, container)
follow following link Portals for refference

Categories