Following is the code that I'm using to create an HTML tag. I want to add a click event on this. How can I add this?
let elem = React.createElement(
this.props.tag,
{
style: this.props.style,
id: this.props.id
onClick: ()
},
[this.props.text]
)
If you are creating an HTML tag, you simply need to pass on the onClick as a function to the element as props. With React.createElement you can write it like
let elem = React.createElement(
this.props.tag,
{
style: this.props.style,
id: this.props.id
onClick: () => {console.log('clicked')}
},
[this.props.text]
)
You could also pass a predefined function like below
let elem = React.createElement(
this.props.tag,
{
style: this.props.style,
id: this.props.id
onClick: this.handleClick.bind(this)
},
[this.props.text]
)
Related
I have an array of objects inside custom hook. I want to return JSX inside one of these objects, but I get Cannot find name 'div'.ts(2304) error. Is there any solution for this problem?
const columns: IColumn[] = useMemo(
() => [
{
key: 'column2',
onRender: (item: IDocumentItem) => {
return <div style={{ fontWeight: 'normal' }}>{item.type}</div>;
},
data: 'string',
},
...
],
[setFieldName, setIndex, setItemSort]
);
I have a component called RightTab like this
const RightTab = ({ data }) => {
return (
<div className="RightTab flex__container " onClick={data.onClick}>
<img src={data.icon} alt="Dashboard Icon" />
<p className="p__poppins">{data.name}</p>
{data.dropDown === true ? (
<div className="dropdown__icon">
<img src={Assets.Arrow} alt="Arrow" />
</div>
) : (
<div className="nothing"></div>
)}
</div>
);
};
export default RightTab;
The tab has an active state in its CSS like this
.RightTab.active {
background-color: var(--primaryGreen);
}
as you have seen it changes the color when an active class is added. I have an array in the parent component that I pass down to the child component as props. Here is the array
const dataArray = [
{
name: "Dashboard",
icon: Assets.Dashboard,
dropDown: false,
onClick: handleDashBoardClick,
},
{
name: "Inventory",
icon: Assets.Inventory,
dropDown: true,
onClick: handleInventoryClick,
},
{
name: "Reports",
icon: Assets.Reports,
dropDown: true,
onClick: handleReportsClick,
},
];
Here is how I pass the props down.
<RightTab data={dataArray[0]} />
<RightTab data={dataArray[1]} />
<RightTab data={dataArray[2]} />
The data prop passed into the component is an object containing a function call as one of its properties like this. I have an onclick attribute on the child components' main container that is supposed to call the respective function.
The function is what adds the active class to make the background change color. However each time I click on the component it only changes the background of the first occurrence. And as you may have noticed I call the component thrice. No matter which component I click only the first ones background changes.
Here is an example of the function that is on the prop object.
const handleDashBoardClick = () => {
const element = document.querySelector(".RightTab");
element.classList.toggle("active");
};
I don't get what I'm doing wrong. What other approach can I use?
Although you use the component 3 times, it doesn't mean that a change you make in one of the components will be reflected in the other 2, unless you specifically use a state parameter that is passed to all 3 of them.
Also, the way you add the active class is not recommended since you mix react with pure js to handle the CSS class names.
I would recommend having a single click handler that toggles the active class for all n RightTab components:
const MainComponent = () => {
const [classNames, setClassNames] = useState([]);
const handleClick = (name) =>
{
const toggledActiveClass = classNames.indexOf('active') === -1
? classNames.concat(['active'])
: classNames.filter((className) => className !== 'active');
setClassNames(toggledActiveClass);
switch (name) {
case 'Dashboard';
// do something
break;
case 'Inventory':
// ....
break;
}
}
const dataArray = [
{
name: "Dashboard",
icon: Assets.Dashboard,
dropDown: false,
onClick: handleClick.bind(null, 'Dashboard'),
},
{
name: "Inventory",
icon: Assets.Inventory,
dropDown: true,
onClick: handleClick.bind(null, 'Inventory'),
},
{
name: "Reports",
icon: Assets.Reports,
dropDown: true,
onClick: handleClick.bind(null, 'Reports'),
},
];
return (
<>
{dataArray.map((data) =>
<RightTab key={data.name}
data={data}
classNames={classNames} />)}
</>
);
};
const RightTab = ({ data, classNames }) => {
return (
<div className={classNames.concat(['RightTab flex__container']).join(' ')}
onClick={data.onClick}>
<img src={data.icon} alt="Dashboard Icon" />
<p className="p__poppins">{data.name}</p>
{data.dropDown === true ? (
<div className="dropdown__icon">
<img src={Assets.Arrow} alt="Arrow" />
</div>
) : (
<div className="nothing"></div>
)}
</div>
);
};
I am trying to create this code in ReactJS without JSX
<li>
<a href="javascript:;" onClick={onClick ? this.handleClick : null}>
<div className="home-gallery" style={{background: `url(${photo})`}}/>
</a>
</li>
Reason is due to altering previous code in a component that doesn't quite fit my needs. Reading some other posts I came to this but its far from working.
_createClass(Photo, [{
key: 'handleClick',
value: function handleClick(event) {
var _props = this.props,
onClick = _props.onClick,
index = _props.index,
photo = _props.photo;
onClick(event, { photo: photo, index: index });
}
}, {
key: 'render',
value: function render() {
var _props2 = this.props,
photo = _props2.photo,
onClick = _props2.onClick,
margin = _props2.margin;
var imgStyle = { background: `url(${photo})`, margin: margin };
return
_react2.default.createElement('li', null,
_react2.default.createElement('a', _extends({
onClick: onClick ? this.handleClick : null
},
_react2.default.createElement('div', _extends({
style: onClick ? _extends({}, imgStyle, imgWithClick) : imgStyle
}))
))
)
}}]);
Could someone point me in the direction of fixing this or reference how to best learn what I am doing wrong.
UPDATE
I have no figured out the majority of my query with altering to but the background: 'url(${photo})' is still not producing, whilst the margin is.
var imgStyle = { background: `url(${photo})`, margin: margin };
return _react2.default.createElement(
"li",
null,
_react2.default.createElement(
"a",
{ href: "javascript:;", onClick: onClick ? this.handleClick : null },
_react2.default.createElement("div", { className: "home-gallery", style: onClick ? _extends({}, imgStyle) : imgStyle })
)
);
Okay, I came to the solution by using the online Babel compiler. Putting in the JSX gave an output that lead me toward the solution.
var imgStyle = { backgroundImage: 'url(' + photo.src + ')', margin: margin };
console.log(photo)
return _react2.default.createElement(
"li",
null,
_react2.default.createElement(
"a",
{ href: "javascript:;", onClick: onClick ? this.handleClick : null },
_react2.default.createElement("div", { className: "home-gallery", style: onClick ? _extends({}, imgStyle) : imgStyle })
)
);
I've got a component that gets two props, function and node(or string with label text), depends on these props I render the icon with some label. In future, I'm going to add more button and want to create the generic method that rendered this icon more flexible. So how to create such generic method for that?
const Wrapper = ({onRefresh, onExportToExcel, actionsLabel}) => {
return
{onRefresh && !!actionsLabel.refresh &&
<InlineIconButton name='refresh' label={actionsLabel.refresh} onClick={onRefresh} icon={<Autorenew/>} aria-label="Refresh"/>}
{onExportToExcel && !!actionsLabel.exportToExcel &&
<InlineIconButton name='exportToExcel' label={actionsLabel.exportToExcel} onClick={onExportToExcel} icon={<FileDownload/>} aria-label="ExportToExcel"/>}
}
<Wrapper onRefresh={()=> {}} onExportToExcel ={()=> {}} actionLabel={refresh: 'refresh', exportToExcel: 'export'}>
Maybe do something like:
const EXPORT_EXCEL = {
key: "EXPORT_EXCEL",
label: "export",
ariaLabel: "Export Excel",
icon: <Autorenew/>,
handler: params => { /* your function */ }
};
const REFRESH = {
key: "REFRESH",
label: "refresh",
ariaLabel: "Refresh",
icon: <FileDownload/>,
handler: params => { /* your function */ }
};
<Wrapper type={EXPORT_EXCEL} />;
const Wrapper = ({ type }) => {
return <InlineIconButton name={type.key} label={type.label} onClick={type.handler} icon={type.icon} aria-label={type.ariaLabel ? type.ariaLabel : type.label} />;
}
}
You even the possiblity to throw those EXPORT_EXCEL and REFRESH into array. Instead of having them loose put them in an array like so:
const BUTTONS = [
{
key: "EXPORT_EXCEL",
label: "export",
ariaLabel: "Export Excel",
icon: <Autorenew/>,
handler: params => { /* your function */ }
},
{
key: "REFRESH",
label: "refresh",
ariaLabel: "Refresh",
icon: <FileDownload/>,
handler: params => { /* your function */ }
},
];
And then loop through to create the Wrapper.
But then it's really up to you and your preferences and app's requirements
The entire idea behind React is to be able to create a unique component for every kind of usage. That is the entire philosophy behind React composability. Don't understand why would you want to wrap it.
I want to grab the current node of a function inside a React.createElement() function.
return React.createClass({
getInitialState: function() {
return ({
expand: false
});
},
expandLaunch: function() {
this.setState({
expand: true
});
// want to do something like
// $('.text').css('display','block');
},
render: function() {
var titlebar = React.createElement(
'div',
{className: 'titlebar', onClick: this.expandLaunch},
'Launcher'
);
//........
var text = React.createElement(
'div',
{className: 'text'},
textarea
);
return React.createElement(
'div',
{className: 'box-wrapper'},
titlebar,
text
);
}
});
So with the expandLaunch() function I wanted to target the element so I can manipulate the css and other possible functionality. FYI I am not using JSX, just regular jQuery.
Use ref.
return React.createClass({
getInitialState: function() {
return ({
expand: false
});
},
expandLaunch: function() {
this.setState({
expand: true
});
$(this.refs.text).css('display','block');
},
render: function() {
var titlebar = React.createElement(
'div',
{className: 'titlebar', onClick: this.expandLaunch},
'Launcher'
);
//........
var text = React.createElement(
'div',
{className: 'text', ref: 'text'},
textarea
);
return React.createElement(
'div',
{className: 'box-wrapper'},
titlebar,
text
);
}
});
I do urge you to use the tools React gives you to achieve this, via dynamic classNames or inline styles, rather than using jquery, which in many ways should be considered orthogonal to React.