Getting undefined when trying to pass data between component - javascript

First of all I am new in React. I have two components TagUtils and Urls. I am trying to pass router paramter from Urls to TagUtils. Here is my codes:
Urls.jsx
// some codes....
export default class Urls extends React.Component {
render() {
return (
<div>
<TagUtils tag={this.props.params.tag_id}/>
</div>
)
}
}
TagUtils.jsx
export default class TagUtils extends React.Component {
deleteTag(props) {
console.log(props.tag);
}
render() {
return (
<div className="col-xs-6 col-md-4">
<button type="button" className="btn btn-danger" onClick={this.deleteTag}><i className="fa fa-trash"> Delete</i></button>
</div>
)
}
}
When I clicked Delete button it just showing undefined .Maybe I am missing something.

In your example props is event Object where there is no tag property - that's why you are getting undefined., you need set this for deleteTag and then you can get component props through this.props inside deleteTag method
export default class TagUtils extends React.Component {
constructor() {
this.deleteTag = this.deleteTag.bind(this);
}
deleteTag() {
console.log(this.props.tag);
}
render() {
return (
<div className="col-xs-6 col-md-4">
<button type="button" className="btn btn-danger" onClick={this.deleteTag}>
<i className="fa fa-trash"> Delete</i>
</button>
</div>
)
}
}

With the shift of React from createClass to ES6 classes we need to handle the correct value of this to our methods on our own, as mentioned here: http://www.newmediacampaigns.com/blog/refactoring-react-components-to-es6-classes
Change your code to have the method bounded to correct value of this in constructor:
export default class TagUtils extends React.Component {
constructor(props) {
super(props);
this.deleteTag = this.deleteTag.bind(this);
}
deleteTag(props) {
console.log(props.tag);
}
render() {
return (
<div className="col-xs-6 col-md-4">
<button type="button" className="btn btn-danger" onClick={this.deleteTag}><i className="fa fa-trash"> Delete</i></button>
</div>
)
}
}
The no autobinding was a deliberate step from React guys for ES6 classes. Autobinding to correct context was provided with React.createClass. Details of this can be found here: https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding
So based on this you could also change your code as:
export default class TagUtils extends React.Component {
deleteTag = (props) => {
console.log(props.tag);
}
render() {
return (
<div className="col-xs-6 col-md-4">
<button type="button" className="btn btn-danger" onClick={this.deleteTag}><i className="fa fa-trash"> Delete</i></button>
</div>
)
}
}

Related

JSColor onChange Event saying function is not defined

I'm trying to use the onChange event for JSColor to call a function but every time it fires, I get an error stating that the function is not defined. My code is below.
export class NavBar extends React.Component {
constructor(props) {
super(props);
}
setLinkTextColor(color) {
console.log("hello")
}
render() {
return (
<div className="sideOptionContainer">
<button className="jscolor" id="jscolor1" data-jscolor="{valueElement:'#val3', onChange: 'setLinkTextColor(this)'}">,</button>
<input id="val3" value="rgba(255,160,0)" name="color3" type="hidden"/>
</div>
)
}
}
I've tried moving the function inside of render() as function setLinkTextColor(color), thinking that maybe it had something to do with the scope, but I get the same exact error.
Edit: I've tried the following fix, removing the string from onChange and creating a global function -
export class NavBar extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="sideOptionContainer">
<button className="jscolor" id="jscolor1" data-jscolor="{valueElement:'#val3', onChange: setLinkTextColor(this)}">,</button>
<input id="val3" value="rgba(255,160,0)" name="color3" type="hidden"/>
</div>
)
}
}
function setLinkTextColor(color) {
console.log("hello")
}
Although I'm not getting any errors anymore, the onChange event is no longer firing when I change the color input.
Since this is React, you need to bind your setLinkTextColor function in the constructor:
constructor(props) {
super(props);
this.setLinkTextColor = this.setLinkTextColor.bind(this);
}
Then, in your JSColor config, you can't use a string, because JSColor can't access your function inside of your class. Instead, do this:
render() {
const jsColorConfig = {
valueElement: '#val3',
onChange: this.setLinkTextColor
};
return (
<div className="sideOptionContainer">
<button className="jscolor" id="jscolor1" data-jscolor={jsColorConfig}>,</button>
<input id="val3" value="rgba(255,160,0)" name="color3" type="hidden"/>
</div>
)
}

Getting a Render not Function Error, when I run this Code Context API and Reactjs

Thanks for taking the time to read this. I have been at this now for a few hours and nearly got it right except now, Im Getting a "TypeError: render is not a function" Error and Can not figure it out, using Context API and Reactjs Please help
I have changed around States and props and back again this is the closest I got it to work
this is my parent file where I pass the UserProvider
import React, { Component } from "react";
import Group from "./Groups";
import JsonData from "../data/export";
import { UserProvider } from "./context/UserContext";
class GroupGrid extends Component {
render() {
// console.log(JsonData);
return (
<UserProvider value={JsonData}>
<div className='cards'>
<Group />
</div>
</UserProvider>
);
}
}
export default GroupGrid;
this is the child file
import React, { Component } from "react";
import UserContext from "../components/context/UserContext";
import { UserConsumer } from "../components/context/UserContext";
class GroupDetails extends Component {
static contextType = UserContext;
componentDidMount() {
const data = this.context;
// console.log(data); // { name: 'Tania', loggedIn: true }
}
render() {
return (
<UserConsumer>
{this.context.TransportGrid.GROUPS.map((value, index) => (
<div key={value.GROUP_ID} className='GroupDetail'>
<div className='groupRow1'>
<span className='Date_label'>Date:</span>
<span className='GroupDate'>
{value.GROUP_DATE}
</span>
<span className='Group_label'>Group No:</span>
<span className='GroupID'>{value.GROUP_ID}</span>
</div>
<div className='groupRow2'>
<span className='Driver_label'>Driver:</span>
<span className='DriverName'>
{value.DRIVER_NAME}
</span>
<span className='Reg_label'>Artic:</span>
<span className='VehcileReg'>
{value.VEHICLE_REG}
</span>
</div>
</div>
))}
</UserConsumer>
);
}
}
export default GroupDetails;
and this an example of the JSON it looking at
{
"TransportGrid": {
"GROUPS": [
{
"GROUP_ID": "1234",
"GROUP_DATE": "20/08/2019",
"DRIVER_ID": "22",
"DRIVER_NAME": "JIMMY BLOGGS",
"VEHICLE_REG": "XSRFDFDDF",
"START_COUNTRY": "COUNTRY1",
"END_COUNTRY": "COUNRTY2",
"MOVEMENTS": [
{
this is repeated like 180 times ANyone got any idea's?
Thanks in Advance
Problem is that your consumer from context API needs to just have a single children element as a function whereas you are having an array of JSX elements as children.
Also since you are using the latest context API you don't need to use the Consumer component, you could simply write your code as
class GroupDetails extends Component {
static contextType = UserContext;
componentDidMount() {
const data = this.context;
// console.log(data); // { name: 'Tania', loggedIn: true }
}
render() {
return (
<React.Fragment>
{this.context.TransportGrid.GROUPS.map((value, index) => (
<div key={value.GROUP_ID} className='GroupDetail'>
<div className='groupRow1'>
<span className='Date_label'>Date:</span>
<span className='GroupDate'>
{value.GROUP_DATE}
</span>
<span className='Group_label'>Group No:</span>
<span className='GroupID'>{value.GROUP_ID}</span>
</div>
<div className='groupRow2'>
<span className='Driver_label'>Driver:</span>
<span className='DriverName'>
{value.DRIVER_NAME}
</span>
<span className='Reg_label'>Artic:</span>
<span className='VehcileReg'>
{value.VEHICLE_REG}
</span>
</div>
</div>
))}
</React.Fragment>
);
}
}
export default GroupDetails;

ReactJS - Conditional Rendering with Ternary operator - InvalidValueError

I am building a web app with ReactJS, on the home page I am using a ternary operator two render two different Fragment according to the state( if true or false).
my Code looks like:
import React, { Component, Fragment } from 'react'
import { Link } from 'react-router-dom'
class Home extends Component {
state = {
citySearch : false
}
render(){
return (
<div className="home-main">
{ !this.state.citySearch ? (
<Fragment>
<h2 className="home-heading">Search Cafés from your</h2>
<div className="home-buttons">
<button className="home-buttons">Near You</button>
<span>or</span>
<button onClick={this.ActivateCitySearch} className="home-buttons">City</button>
</div>
</Fragment>
)
: (
<Fragment>
<h2 className="home-heading">Search Cafés from your</h2>
<input className="search-café" placeholder="Enter your location"/>
<Link className="search-input"><i className="fas fa-search"></i></Link>
</Fragment>
)
}
</div>
)
}
}
export default Home
The code works but I get the following in the console
InvalidValueError: not an instance of HTMLInputElement
Does anyone know how to get rid of this error??
Thanks,
J

Proper way to build bootstrap modals and notifications in React JS?

I would like to have modals and notifications in my app and coming from using old jQuery Bootstrap, creating modals and notifications were really easy but now I am pretty confused on how to implement this in the virtual DOM using the react component system.
This is what I believe the standard react way to build modals in React within a component:
Index/Router Component >
Main Layout Component >
{...Page Components... }
{...Child Component}
{<Modal /> or <Notification />}
The issue with this is I dont want to constantly have to import and create a <Modal> or <Notification /> component within my sub components, instead maybe just call a utility function such as {app.notify({type: 'success', message: 'some message'})} or app.modal({...customconfig}) and have both defined within my Main layout component which get triggerd through any child components.
Any help on this would be great, thanks!
You do not need to keep your Modal component in a hierarchy. Your Modal component should be an independent component which would take appropriate props to decide what needs to be displayed. E.g.
<Modal message={"This is my modal"} showOkCancel={true} showYesNo={false} handleOkYes={()=>console.log("OK clicked")} handleCancelNo={()=>console.log("Cancel clicked"} />
In the above example, the Modal accepts a number of props which would help it decide the message to display, the buttons to display and the actions that need to take on said button click.
This kind of a component can reside outside your component hierarchy and can be imported into any component that needs to show a modal. The parent component would just need to pass the appropriate props to show the modal.
Hope this helps.
So here is the approach I took to resolve this.
First here is how you want to structure the modal and notification components:
{Index/Router Component}
{Main Layout Component <Modal /> or <Notification />}
{...Page Components... }
{...Child Component calls app.modal({...config}) or app.notify(...config)}
For notifications, I used a plugin called react-notification-system and for modal, I just wrote it myself.
Here is my code:
Layout.js
import React from "react";
import {Link} from 'react-router';
import NotificationSystem from 'react-notification-system';
import AppHeader from "#/ui/header/AppHeader";
import AppFooter from "#/ui/footer/AppFooter";
import Modal from "#/ui/modals/modal/Modal";
import "#/main.scss";
import './layout.scss';
export default class Layout extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
app.notify.clear = this.refs.notificationSystem.clearNotifications;
app.notify = this.refs.notificationSystem.addNotification;
app.modal = this.refs.modal.updateProps;
}
render() {
return (
<div class="app">
<div class="header">
<AppHeader page={this.props.location.pathname.replace('/', '')}/>
</div>
<div class="body">
{this.props.children}
</div>
<div class="footer">
<AppFooter />
</div>
<NotificationSystem ref="notificationSystem" style={false} />
<Modal ref="modal" />
</div>
);
};
}
Modal.js
import React from "react";
import ReactDOM from 'react-dom';
import SVGInline from "react-svg-inline";
import {closeSvg} from '#/utils/Svg';
export default class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
showHeader: true,
showFooter: false,
title: "",
size: '',
className: '',
id: '',
footerContent: null,
showSubmitBtn: true,
showCancelBtn: true,
cancelBtnText: "Cancel",
successBtnText: "Save Changes",
onModalClose: () => {},
showModal: false,
html: () => {}
}
this.updateProps = this.updateProps.bind(this);
this.hideModal = this.hideModal.bind(this);
}
componentWillMount() {
var self = this;
var $modal = $(ReactDOM.findDOMNode(this));
}
componentDidUpdate(prevProps, prevState) {
if(this.state.showModal) {
$('body').addClass('modal-open');
} else {
$('body').removeClass('modal-open');
}
}
componentWillUnmount() {
// $('body').removeClass("modal-open");
}
componentWillReceiveProps(nextProps) {
console.log(nextProps);
}
updateProps(args) {
let merged = {...this.state, ...args};
this.setState(merged);
}
hideModal() {
this.setState({
showModal: false
});
this.state.onModalClose();
}
buildFooter() {
if(this.props.footerContent) {
return (
<div class="content">
{this.props.footerContent}
</div>
)
} else if(this.props.showCancelBtn && this.props.showSubmitBtn) {
return (
<div class="buttons">
<button type="button" class="btn btn-default" data-dismiss="modal" onClick={this.props.onModalClose}>{this.props.cancelBtnText}</button>
<button type="button" class="btn btn-success">{this.props.successBtnText}</button>
</div>
);
} else if(this.props.showCancelBtn) {
return (<button type="button" class="btn btn-default" data-dismiss="modal" onClick={this.props.onModalClose}>Close</button>);
} else if(this.props.showSubmitBtn) {
return (<button type="button" class="btn btn-success">Save changes</button>);
}
}
render() {
let {
id,
className,
onModalClose,
size,
showHeader,
title,
children,
showFooter,
showModal,
html
} = this.state;
return (
<div class={`modal-wrapper`} >
{
showModal ?
<div class={`modal fade in ${className}`} role="dialog">
<div class="bg" ></div>
<div class={`modal-dialog ${size}`}>
<div class="modal-content">
{ showHeader ?
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<SVGInline svg={closeSvg} />
</button>
<h4 class="modal-title">{ title }</h4>
</div> : '' }
<div class="modal-body" >
{html()}
</div>
{ showFooter ?
<div class="modal-footer">
{ this.buildFooter() }
</div> : ''
}
</div>
</div>
</div>
: ''
}
</div>
);
}
}
then in any of your child components you can just call within your render function:
app.notify({
message: message,
level: 'error'
});
or
app.modal({
showModal: true,
className: "fullscreen-image-modal",
size: "modal-lg",
html: () => {
return (<img src={listingManager.LISTINGS_PATH + imgUrl} />);
}
})

why data is not rendering using this.props in react js?

I am breaking down my Header into components. Ex: HaderTop, HeaderBottom. Further I m breaking HeaderBottom into more components. One of the component of HeaderBottom is "HeaderTab". I am passing JSON OBJECT DATA through "HeaderTab" component, which I want to loop using "this.props.data.map()" in HeaderTab class. I am not getting any error, but I am not getting the view also. Below is piece of code. "Below I have attached the view also (My UI should look like this)."
import React from 'react';
import { Link } from 'react-router';
import HeaderBreadcrumb from './HeaderBreadcrumb';
import HeaderTab from './HeaderTab';
export default class HeaderBottom extends React.Component {
constructor(props) {
super(props);
this.state = {
tabs:
[
{"id":1,"name":"Dental","path":"dentalplan"},
{"id":2,"name":"Views","path":"dentalplan"},
{"id":3,"name":"Accident Companion","path":"dentalplan"},
{"id":4,"name":"Critical Illness","path":"dentalplan"},
{"id":5,"name":"Hospital Confinement","path":"dentalplan"}
]
}
}
render() {
return (
<div id="layout-navigation" className="layout-navigation">
<div className="content-heading">
<div className="container">
<HeaderBreadcrumb />
<div className="content-heading__title">
<h1>Dental Plans</h1>
</div>
<HeaderTab data={this.state.tabs}/>
</div>
</div>
</div>
);
}
}
import React from 'react';
import { Link } from 'react-router';
export default class HeaderTab extends React.Component {
render() {
return (
<div className="content-heading__tabs" data={this.props.data}>
<ul className="tabs tabs--horizontal tabs--overlay">
{
this.props.data.map(function(item, i) {
<li role="presentation" className="tab">
<Link to={item.path}>{item.name}</Link>
</li>
})
}
</ul>
</div>
);
}
}
I think you need to return an object in the map function :
this.props.data.map(function(item, i) {
return (
<li role="presentation" className="tab">
<Link to={item.path}>{item.name}</Link>
</li>
)
})
you are not returning a value in map function.
Try:
{
this.props.data.map(function(item, i) {
return <li role="presentation" className="tab">
<Link to={item.path}>{item.name}</Link>
</li>;
})
}
I see you are using es6 classes. You should also try https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions.

Categories