REACT -- adding input toggle in react - javascript

I am creating a react app i have to add an input toggle inside my
header component. I tried to add but JavaScript is not working. if
this is the header component file. inside this component I have included my input toggle condition. i have placed JavaScript code right below the imports.
anyone knows please check thanks..
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Nav,
Navbar,
Collapse,
DropdownMenu,
DropdownItem,
NavbarToggler,
DropdownToggle,
UncontrolledDropdown,
} from 'reactstrap';
import { Link, withRouter } from 'react-router-dom';
import Config from '../../../constants/config';
import { SidebarNavItems } from '../Sidebar';
import logoImages from '../../../images/logo.png';
require('./styles.scss');
var allInputs = document.querySelectorAll('.myInput');
allInputs.forEach(function(node) {
node.addEventListener("click", function(){
var allHiddenInputs = document.querySelectorAll('.hidden');
if(allHiddenInputs.length === 0) {
allInputs.forEach(function(input) {
input.classList.add("hidden");
input.classList.add("second");
input.classList.remove("first");
});
node.classList.remove("hidden");
node.classList.remove("second");
node.classList.add("first");
} else {
allHiddenInputs.forEach(function(input) {
input.classList.remove("hidden");
});
}
});
});
class Search extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="">
<div className="input-container">
<input type="password" placeholder="Input 1" className="myInput first" />
<input type="password" placeholder="Input 2" className="myInput second hidden" />
</div>
</div>
);
}
}
export default withRouter(Search);
this is my css file which linked to this component.
.input-container {
display: flex;
flex-direction: column;
}
.myInput {
margin: 10px;
padding: 5px
}
.first {
order: 1;
}
.second {
order: 2;
}
.hidden {
display: none;
}
enter image description here

What I would do to simulate the same thing as you are trying to do would be to use local state to update the view. You can conditionally render items as well as class names for each render cycle.
class App extends React.Component {
constructor() {
super()
this.inputNames = ['input1', 'input2']
this.state = {
hiddenInputs: {
input1: { hidden: false, first: true },
input2: { hidden: true, first: false }
},
expanded: false
}
}
handleClick(name) {
const hI = Object.assign({}, this.state.hiddenInputs)
let expanded = this.state.expanded
if (expanded && hI[name].first === true) {
// clicked on the first element, we hide the other
expanded = false
} else if (expanded) {
// clicked on non first item, change order
this.inputNames.forEach(input => {
const isSame = input === name
hI[input].first = isSame
hI[input].hidden = !isSame
})
} else {
// its not open yet, show the other
expanded = true
}
this.setState({expanded, hiddenInputs: hI})
}
render() {
const { input1, input2 } = this.state.hiddenInputs
const {expanded} = this.state
const clsName1 = `myInput${input1.hidden && !expanded ? ' hidden' : ''}${input1.first ? ' first' : ' second'}`;
const clsName2 = `myInput${input2.hidden && !expanded ? ' hidden' : ''}${input2.first ? ' first' : ' second'}`;
return (
<div className="">
<div className="input-container flex">
<input type="password" placeholder="Input 1" onClick={this.handleClick.bind(this, 'input1')} className={clsName1} />
<input type="password" placeholder="Input 2" onClick={this.handleClick.bind(this, 'input2')} className={clsName2} />
</div>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
CSS:
.flex {
display: flex;
}
.first {
order: 0;
}
.second {
order: 1;
}
.hidden {
display: none;
}
Fiddle to see it in action

Try to put your code to component lifecycle (like a componentDidMount), then it would work. But in react it is not good solution to work with DOM nodes directly.
Better way would be to make like that:
class Search extends Component {
constructor(props) {
super(props);
this.state = {allInputsHidden: true}; // You can change it later
}
render() {
return (
<div className="">
<div className="input-container">
<input type="password" placeholder="Input 1" className="myInput first" />
<input type="password" placeholder="Input 2" className={this.state.allInputsHidden ? "myInput second hidden" : "myInput second"} />
</div>
</div>
);
}
}
Also, you can use package classnames to make it look more pretty

You may use state to decide which element to be displayed ...
class Search extends Component {
constructor(props) {
super(props);
this.state = {
toggleInput1:true,
}
render() {
return (
<div className="">
<div className="input-container">
{this.state.toggleInput1?
<input type="password" placeholder="Input 1" className="myInput
first" />:
<input type="password" placeholder="Input 2" className="myInput
second hidden" />
}
</div>
</div>
);
}
}
export default withRouter(Search);
And On EventListener change the state of toogleInput
handleClick = event => {
this.setState({toggleInput1:!this.state.toggleInput1 });
};

Use conditional rendering to achieve this task. You can refer this page. Create your input group as a component and add a boolean prop to use with if condition. This is much better than adding classes.
function Inputs(props) {
const isFirst = props.isFirst;
if (isFirst) {
return <input type="password" placeholder="Input 1" className="myInput first" />;
}
return <input type="password" placeholder="Input 2" className="myInput second" />;
}
ReactDOM.render(
<Inputs isFirst={true} />,
document.getElementById('root')
);
And add a click event to toggle the value of isFirst variable.

Related

TypeError: Cannot read property 'onMouse' of undefined React Class Component

I want to do when the user clicks on Input Element and the button element in the form will change to Send icon from the microphone icon. My idea was to get the value from onClick or mouseEnter handler and pass it through the if-else statement and set the correct icon
Here is my Code
`
import React, { Component } from 'react'
import { Field, reduxForm } from 'redux-form';
import InsertEmoticonIcon from '#material-ui/icons/InsertEmoticon';
import AttachFileIcon from '#material-ui/icons/AttachFile';
import MicIcon from '#material-ui/icons/Mic';
import SendIcon from '#material-ui/icons/Send';
import styled from 'styled-components'
import './MessageSender.css'
export class MessageSender extends Component {
constructor(props){
super(props);
this.state = {
bool: 'false'
}
this.onMouse = this.onMouse.bind(this);
}
onMouse(){
this.setState({bool: "true"})
}
renderInput(formProps){
return <input
onChange={formProps.input.onChange}
value={formProps.input.value}
placeholder="Message"
onClick={this.onMouse()}
/>
}
onSubmit(formValues){
console.log(formValues);
}
check(){
// return <Send />
if(this.state.bool === 'true'){
return <Send />
}else{
return <Mic />
}
}
render() {
return (
<form autoComplete="off" onSubmit={this.props.handleSubmit(this.onSubmit)}>
<Emotion />
<Field name="Message" component={this.renderInput} placeholder="Message" />
<Attach />
<button>
{this.check()}
</button>
</form>
)
}
}
const Emotion = styled(InsertEmoticonIcon)`
width: 40px!important;
height: 40px!important;
color: rgb(170,170,170);
`
const Attach = styled(AttachFileIcon)`
width: 40px!important;
height: 40px!important;
color: rgb(170,170,170);
margin-right: 0.3rem;
`
const Mic = styled(MicIcon)`
`
const Send = styled(SendIcon)`
`
export default reduxForm({
form: 'message'
})(MessageSender);
`
Therefore, here is my Error
Help me please, thanks!
Try this out. I think using an arrow function will solve an issue with using this. And you shouldn't be calling the function when you pass it to onClick
renderInput = (formProps) => {
return <input
onChange={formProps.input.onChange}
value={formProps.input.value}
placeholder="Message"
onClick={this.onMouse}
/>
}

Reactjs pass state as props to child

I Started to learn React.
I've seen the tutorial of react website
https://reactjs.org/docs/hello-world.html
and still, sometimes all the props idea doesn't work for me.
my program is crashing and the error message is :
why its happening?
someone can help me, please?
TypeError: Cannot read property 'handleSetColor' of undefined
onSetColor
8 | class ColorDisplay extends Component {
9 |
10 | onSetColor(newColor) {
11 | this.handleSetColor(newColor);
12 | }
import React, { Component } from 'react';
import './App.css';
import _ from 'underscore';
import PropTypes from 'prop-types';
class ColorDisplay extends Component {
onSetColor(newColor) {
this.props.handleSetColor(newColor);
}
render() {
return (<p>
<input type="color" value={this.props.val} onChange={this.onSetColor} />
</p>);
}
}
ColorDisplay.propTypes = {
handleSetColor: PropTypes.func,
val: PropTypes.string,
};
function TextDisplay(props) {
return <input type="text" value={props.val} readOnly={true} />
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
showColorDisplay: true,
showTextDisplay: true,
val: '#ffff00',
}
}
randomizeColor = (e) => {
this.setState(oldState => ({
val: _.sample(['#ffff00', '#ff00ff', '#abff01', '#10f100', '#3030ff', '#ddcc10']),
}));
}
toggle(val) {
this.setState(oldState => ({ [val]: !oldState[val] }));
}
setColor(newColor) {
this.setState({ val: newColor });
}
toggleColorDisplay = (e) => {
this.toggle('showColorDisplay');
}
toggleTextDisplay = (e) => {
this.toggle('showTextDisplay');
}
render() {
return (
<div className="spaced">
<h1>HELLO</h1>
<button onClick={this.randomizeColor}>Shuffle</button><br />
<label>
<br />
<input type="checkbox" checked={this.state.showColorDisplay} onChange={this.toggle.bind(this, 'showColorDisplay')} />
Color Display
</label>
<label>
<input type="checkbox" checked={this.state.showTextDisplay} onChange={this.toggle.bind(this, 'showTextDisplay')} />
Text Display
</label>
<div className="spaced">
{this.state.showColorDisplay && <ColorDisplay val={this.state.val} handleSetColor={this.setColor} />}
</div>
<div className="spaced">
{this.state.showTextDisplay && <TextDisplay val={this.state.val} />}
</div>
</div>
);
}
}
You need to call the Component constructor and bind the scope of onSetColor:
class ColorDisplay extends Component {
constructor(props) {
// This calls the constructor for React.Component
super(props);
// you also need to explicitly bind the scope
this.onSetColor = this.onSetColor.bind(this);
}
onSetColor(newColor) {
this.props.handleSetColor(newColor);
}
render() {
return (<p>
<input type="color" value={this.props.val} onChange={this.onSetColor} />
</p>);
}
}
Let me know if you need any further explanation. Here's an example from the Reactjs site that has to do with your issue.
I can't replicate the problem right now, but i would try binding the method to Color Display, just in case...

check function is called in child component

I am trying to make a custom dropdown but with custom children component. Within the children custom component, there's an onChange event.
The problem now is whenever I trigger the onChange which is for the checkbox, the dropdown is closed.
https://codesandbox.io/s/lr677jv7l7
Partial code
render() {
const { className, onOpen, children } = this.props
const { openItems, selectedItem } = this.state
return (
<div className={classnames('customDropdown', className)}>
<div tabIndex="1"
onBlur={() => { this.setState({ openItems: false }) }}
onFocus={() => { this.setState({ openItems: true }); onOpen && onOpen() }}>
<button className="btn">
{selectedItem}
</button>
<div className={classnames('items', { 'show': openItems === true, 'hide': openItems === false })}>
{children && children}
</div>
</div>
</div>
)
}
You need to get rid of following line:
onBlur={() => { this.setState({ openItems: false }) }}
It basically says that when your div wrapping the button loses focus (eg when you click the checkbox) it should set the state.openItems variable to false and therefore it closes the dropdown.
Edit:
Check out working example here: https://codesandbox.io/s/jnq2rqwr53.
Basically use onClick instead of blur and then you add click event to your document, so anytime user clicks anywhere on the document it calls your hide method and closes the modal. This way the selected checkbox gets checked, but if you want to dropdown to stay open after the selection you'll need to somehow tell the hide function not to execute if user clicked on the checkbox. I did it using ids and simple condition guard at the beginning of the hide method.
Code looks like this:
Hello.js
import React, { Component } from 'react';
import classnames from 'classnames'
export default class CustomDropdown extends Component {
constructor() {
super()
this.state = {
openItems: false,
selectedItem: 'Please select'
}
this.show = this.show.bind(this);
this.hide = this.hide.bind(this);
}
show() {
this.setState({openItems: true});
document.addEventListener("click", this.hide);
}
hide(e) {
if (e.target.id === "1" || e.target.id === "2") {
return false;
}
this.setState({openItems: false});
document.removeEventListener("click", this.hide);
}
render() {
const { className, onOpen, children } = this.props
const { openItems, selectedItem } = this.state
return (
<div className={classnames('customDropdown', className)}>
<div tabIndex="1">
<button className="btn" onClick={this.show}>
{selectedItem}
</button>
<div className={classnames('items', { 'show': openItems === true, 'hide': openItems === false })}>
{children && children}
</div>
</div>
</div>
)
}
}
index.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './styles.css';
const styles = {
fontFamily: 'sans-serif',
textAlign: 'center'
};
class App extends Component {
constructor() {
super()
}
changeCheckbox = () => {
console.log('something')
}
render(){
return(
<div style={ styles }>
<Hello>
<div>
my checkbox 1
<input type="checkbox" onChange={this.changeCheckbox} id="1" />
</div>
<div>
my checkbox 2
<input type="checkbox" onChange={this.changeCheckbox} id="2" />
</div>
</Hello>
</div>
)
}
}
render(<App />, document.getElementById('root'));

Rendering a React component in Jest returns null

I'm having hard time writing test unit with Jest :/ Here is my code:
import { NewRec } from '../src/components/edit';
import { shallow } from 'enzyme';
import React from 'react/lib/ReactWithAddons';
jest.mock('react-dom');
jest.mock('react/lib/ReactDefaultInjection');
describe('NewRec component', () => {
const component = shallow(<NewRec />);
it('returns true if blah blah', ()=>{
const p = component.find('errortitle');
expect(p.length).toEqual(1)
});
});
P is always 0. I tried to check how the component looks like after rendering. Asked the question here: (How to see what the rendered React component looks like in the Jest unit test?)
The snapshot file says it's null:
exports[`NewRec component returns true if blah blah 1`] = `null`;
So why it's always null? What is the problem in the code? The "NewRec" component is using mixins (mixins: [React.addons.LinkedStateMixin]). Can that cause the problem?
UPDATE: Here is the component code:
export const NewRec = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState() {
return {
group_id: null,
title: "",
errors: {},
}
},
createRec(event) {
event.preventDefault();
if (!this.state.title.length) {
this.setError('title', "Please add a title");
return;
}
if (!this.state.group_id) {
this.setError('group', "Please select a group");
return;
}
serverCache.createRec(
{ group: this.state.group_id, title: this.state.title },
rec => { browser.gotoRec(rec.id); }
);
},
selectgroup(group_id) {
this.setState({group_id: group_id});
},
rendergroupList(groups) {
return (
<div > { groups.map(this.rendergroup) } </div>
);
},
onTitleChange(event) {
this.setState({title:event.target.value});
},
componentWillMount() {
const user = serverCache.getUser();
if (!user || !user.get('name')) {
notifications.warning('Please login first.');
}
},
render() {
const user = serverCache.getUser();
const groups = serverCache.getgroups();
return (
<div className="row">
<form className="form-horizontal" onSubmit={this.createRec}>
<label htmlFor="title" className="col-sm-3 control-label"> Title </label>
<div>
<input type="text" id='title' value={this.state.title} onChange={this.onTitleChange} />
</div>
<div>
<label htmlFor="group" className="col-sm-3 control-label" >group </label>
</div>
<div>
{this.state.errors.title ? <div id='errortitle' >{this.state.errors.title} </div>: false }
{this.state.errors.group ? <div id='errorgroup' >{this.state.errors.group} </div> : false }
<div >
<button type="submit" className="btn btn-primary btn-default btn-block"> Create Rec</button>
</div>
</div>
</form>
</div>
);
}
});
I think component.find('new-rec').length is 0 because there is no new-rec component, tag, or whatever you're looking for, I mean, wehen I see this code const p = component.find('new-rec'); I understand that you are trying to get a p tag with a new-rec class or something like that, But if you are looking for a class, then you have to do const p = component.find('.new-rec'); Note de dot before de word (css selector). But again it will be 0 because I don't see any p tag with a .new-rec class in the NewRec component.

Toggle active class on child components

I'm having a bit of a head ache trying to figure out the React way of implementing this.
I have a Searches component which houses SearchItems, when an item is clicked among other things I need to set it's state to active to that it gets the correct CSS, I managed to get this working fine but how would I go about removing the active state from the others?
I was thinking that I could pass down a function from the top level component that would take the ID of the search, when clicked it'd zip through SearchItems and change their state to either true/false depending on which ID it was?
Code below!
Top level component:
import React from "react";
import {Link} from "react-router";
import Search from "./Search";
export default class Searches extends React.Component {
constructor(){
super();
this.state = {
searches : [
{
id : "2178348216",
searchName: "searchName1",
matches: "5"
},
{
id : "10293840132",
searchName: "searchName2",
matches: "20"
}
]
};
}
render() {
const { searches } = this.state;
const SearchItems = searches.map((search) => {
return <Search key={search.id} {...search}/>
})
return (
<div> {SearchItems} </div>
);
}
}
Search items component
export default class Search extends React.Component {
constructor() {
super();
// Set the default panel style
this.state = {
panelStyle: { height: '90px', marginBottom: '6px', boxShadow: '' },
selected: false
}
}
isActive(){
return 'row panel panel-success ' + (this.state.selected ? 'active' : 'default');
}
viewNotifications(e){
this.setState({selected: true});
}
render() {
const { id, searchName, matches } = this.props;
const buttonStyle = {
height: '100%',
width: '93px',
backgroundColor: '#FFC600'
}
return (
<div style={this.state.panelStyle} className={this.isActive()}>
<div class="col-xs-10">
<div class="col-xs-7">
Search Name: {searchName}
</div>
<div class="col-xs-7">
Must Have: PHP, MySQL
</div>
<div class="col-xs-7">
Could Have: AngularJS
</div>
</div>
<button type="button" onClick={this.viewNotifications.bind(this)} style={buttonStyle} class="btn btn-default btn-lg"> {matches} </button>
</div>
);
}
}
I think you don't need the state in the child component at all. In fact is a good idea to avoid having state in most components so they are easy to reason and reuse.
I would leave all the state only on the parent component in this case.
TOP Component:
import React from "react";
import Search from "./search";
export default class Searches extends React.Component {
constructor(){
super();
this.state = {
searches : [
{
id : "2178348216",
searchName: "searchName1",
matches: "5"
},
{
id : "10293840132",
searchName: "searchName2",
matches: "20"
}
],
activeElement : null
};
}
_onSearchSelect(searchId) {
this.setState({'activeElement': searchId})
}
render() {
const { searches, activeSearchId } = this.state;
const SearchItems = searches.map((search) => {
return <Search key={search.id} {...search}
isActive={search.id === activeElement}
onSelect={this._onSearchSelect.bind(this)} />
})
return (
<div> {SearchItems} </div>
);
}
}
CHILD Component:
import React from "react";
export default class Search extends React.Component {
_getPanelClassNames() {
const { isActive } = this.props
return 'row panel panel-success ' + (isActive ? 'active' : 'default')
}
_onSelect() {
const { id, onSelect } = this.props;
onSelect(id)
}
render() {
const { searchName, matches } = this.props;
const panelStyle = { height: '90px', marginBottom: '6px', boxShadow: '' }
const buttonStyle = {
height: '100%',
width: '93px',
backgroundColor: '#FFC600'
}
return (
<div style={panelStyle} className={this._getPanelClassNames()}>
<div className="col-xs-4">
Search Name: {searchName}
</div>
<div className="col-xs-3">
Must Have: PHP, MySQL
</div>
<div className="col-xs-3">
Could Have: AngularJS
</div>
<div className="col-xs-2">
<button type="button" onClick={this._onSelect.bind(this)}
style={buttonStyle} className="btn btn-default btn-lg"
>
{matches}
</button>
</div>
</div>
);
}
}
You can also see it running in Plunker: https://plnkr.co/edit/sdWzFedsdFx4MpbOuPJD?p=preview
Ok it turns out this is simpler than I thought and is simply a case of understanding how react works(and not getting confused) .
When you have a top level component you pass it's state via props to children, when you update the state in the top level component it'll pass that down to the children and you can use componentWillReceiveProps to take action.
I added a function to my top level component called updateActiveSearch which simply sets the state of the TOP level component I then passed the activeElement state as a prop to the child Elements along with the function. When a child element calls this function to set itself as active all of them will fire componentWillReceiveProps, they simply just need to check their own ID against the one they've received, if it matches they're active, if it doesn't they're not!
So my top level component now looks like this:
export default class Searches extends React.Component {
constructor(){
super();
this.state = {
searches : [
{
id : "2178348216",
searchName: "searchName1",
matches: "5"
},
{
id : "10293840132",
searchName: "searchName2",
matches: "20"
}
],
activeElement : 0
};
}
// This function gets passed via a prop below
updateActiveSearch(id){
//console.log(id);
this.setState({activeElement : id});
}
render() {
const SearchItems = this.state.searches.map((search) => {
return <Search activeElement={this.state.activeElement} goFunction={this.updateActiveSearch.bind(this)} key={search.id} {...search}/>
})
return (
<div> {SearchItems} </div>
);
}
}
CHILD COMPONENTS
export default class Search extends React.Component {
constructor() {
super();
// Set the default panel style
this.state = {
panelStyle: { height: '90px', marginBottom: '6px', boxShadow: '' },
selected: false
}
}
// This happens right before the props get updated!
componentWillReceiveProps(incomingProps){
if(incomingProps.activeElement == this.props.id){
this.setState({selected: true});
} else {
this.setState({selected: false});
}
}
isActive(){
return 'row panel panel-success ' + (this.state.selected ? 'active' : 'default');
}
viewNotifications(e){
//this.state.panelStyle.boxShadow = '-2px 3px 20px 5px rgba(255,198,0,1)';
this.setState({selected: true});
this.props.goFunction(this.props.id);
}
render() {
const { id, searchName, matches } = this.props;
const buttonStyle = {
height: '100%',
width: '93px',
backgroundColor: '#FFC600'
}
return (
<div style={this.state.panelStyle} className={this.isActive()}>
<div class="col-xs-10">
<div class="col-xs-7">
Search Name: {searchName}
</div>
<div class="col-xs-7">
Must Have: PHP, MySQL
</div>
<div class="col-xs-7">
Could Have: AngularJS
</div>
</div>
<button type="button" onClick={this.viewNotifications.bind(this)} style={buttonStyle} class="btn btn-default btn-lg"> {matches} </button>
</div>
);
}
}

Categories

Resources