Controlling Modals with States and Props - javascript

I am trying to use Reactstrap to create modals that pop up when navigated through the nav bar.
My strategy is to change the state in the parent component and pass them as props to the isOpen attribute to control opening the modals.
The problem is changing the props in the child component doesn't re-render components so I am not able to close the modals!
Parent Controller:
class App extends Component {
constructor(props){
super(props);
this.state = {
zipcode : '',
zipEntered: false
};
this.onZipCodeChange = this.onZipCodeChange.bind(this);
this.isAuth = this.isAuth.bind(this);
}
componentDidMount() {
this.setState({signup:false});
if(this.state.zipcode !== '' || this.state.zipcode !== undefined){
this.setState({zipEntered:true});
this.setState({zipcode:this.state.zipcode});
} else {
this.setState({zipcode: '' });
this.setState({zipEntered:false});
}
}
onZipCodeChange(zip){
//console.log('App has detected ZipCode Change: '+zip);
this.setState({zipcode: zip});
this.setState({zipEntered:false});
}
isAuth(token){
console.log("App has token: "+ token);
//pull data from token
}
render() {
return (
<div className="App">
<header>
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<a className="navbar-brand" href="#">InkSpace</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item">
<a className="nav-link" onClick={() => {this.setState({zipEntered:true})}}>Change Zipcode</a>
</li>
<li className="nav-item">
<a className="nav-link" onClick={() => {this.setState({signup:true})}}>Tattooist</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#">FAQ</a>
</li>
<li className="nav-item">
<a className="nav-link disabled" href="#">Shop</a>
</li>
</ul>
</div>
</nav>
</header>
<ZipCode onSubmit={this.onZipCodeChange} isOpen={this.state.zipEntered} />
<GMap zipcode={this.state.zipcode} />
</div>
);
}
}
export default App;
Child Controller:
class ZipCode extends React.Component {
constructor(props) {
super(props);
this.state = {
zipcode:'' };
this.submitZipCode = this.submitZipCode.bind(this);
this.zipcodeChange = this.zipcodeChange.bind(this);
}
submitZipCode(e){
// console.log('submitting zipcode');
e.preventDefault();
const { onSubmit } = this.props; //pull out to call method it is linked to
onSubmit(this.state.zipcode);
this.setState({isOpen:false});
}
zipcodeChange(e){
this.setState({zipcode: e.target.value});
}
render(){
return(
<div>
<Modal isOpen={this.props.isOpen} toggle={this.toggle} className={this.props.className}>
<ModalHeader toggle={this.toggle}>ZipCode</ModalHeader>
<ModalBody>
<form onSubmit={this.submitZipCode}>
<label>Zip Code</label>
<input
type="input"
name="zipcode"
value={this.state.zipcode}
onChange={this.zipcodeChange}
/>
<Button color="primary" type="submit" className='btn btn-success'>Submit</Button>
</form>
</ModalBody>
</Modal>
</div>
);
}
}
export default ZipCode;

Related

Not Able to Change the Color of the alert Message in javascript react

I am trying to program an alert component but I am not able to change the colour of the alert message.
It will show an alert message that dark mode is enabled when I enable it in the navbar(present at the last in the navbar component code). I am using bootstrap CSS
Alert component:
import React from "react";
export default function Alert(props) {
const capital = (word) => {
const lower = word.toLowerCase();
return lower.charAt(0).toUpperCase() + lower.slice(1);
};
return (
props.alert && (
<div
className={`alert alert-${props.alert.type} alert-dismissible fade show`}
role="alert"
>
<strong>{capital(props.alert.type)}</strong>: {props.alert.msg}
</div>
)
);
}
Navbar component:
import React from "react";
import PropTypes from "prop-types";
export default function Navbar(props) {
return (
<>
<nav
className={`navbar navbar-expand-lg navbar-${props.mode} bg-${props.mode}`}
>
<div className="container-fluid">
<a className="navbar-brand" href="/">
Navbar
</a>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav me-auto mb-2 mb-lg-0">
<li className="nav-item">
<a className="nav-link active" aria-current="page" href="/">
Home
</a>
</li>
<li className="nav-item">
<a className="nav-link" href="/">
Link
</a>
</li>
<li className="nav-item">
<a
className="nav-link "
href="/"
tabIndex="-1"
aria-current="page"
>
{props.aboutText}
</a>
</li>
</ul>
<form className="d-flex mx-2">
<input
className="form-control me-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<button className="btn btn-outline-success" type="submit">
Search
</button>
</form>
<div
className={`form-check form-switch text-${
props.mode === "light" ? "dark" : "light"
} mx-2`}
>
<input
className="form-check-input "
onClick={props.togglemode}
type="checkbox"
id="flexSwitchCheckDefault"
/>
<label
className={`form-check-label `}
htmlFor="flexSwitchCheckDefault"
>
Enable Dark Mode
</label>
</div>
</div>
</div>
</nav>
</>
);
}
App.js:
import "./App.css";
import Navbar from "./components/Navbar";
import React, { useState } from "react";
import Alert from "./components/Alert";
function App() {
const [mode, setMode] = useState("light");
const [alert, setAlert] = useState(null);
const showAlert = (message, type) => {
setAlert({
msg: message,
type: type,
});
setTimeout(() => {
setAlert(null);
}, 1500);
};
const togglemode = () => {
if (mode === "light") {
setMode("dark");
document.body.style.backgroundColor = "#042743";
showAlert("Dark mode has been enabled", "Success");
} else {
setMode("light");
document.body.style.backgroundColor = "white";
showAlert("Light mode has been enabled", "Success");
}
};
return (
<>
<Navbar aboutText="About Myself" mode={mode} togglemode={togglemode} />
<div className="container " my-3="true">
<Alert alert={alert} />
</div>
</>
);
}
export default App;
change the showAlert functions 2nd property:
from "Success" to "success". it will work.
To make it easier for you, replace:
showAlert("Dark mode has been enabled", "Success");
with:
showAlert("Dark mode has been enabled", "success");
at both places in the togglemode function.

setState not working in ReactJS GET method

I've been trying to make a navbar for my website that handles log in and logout authentication. To show a log in or logout button based on if the user is either. I have sucessfully retrieved the data I need but I am having trouble rendering and saving it in my Navbar component, it looks like this:
import React from 'react';
class Navbar extends React.Component {
constructor(props){
super(props)
this.state = { loggedin: ''}
this.isLoggedIn = this.isLoggedIn.bind(this)
}
componentDidMount(){
fetch('/user-status', {method: 'GET'}).then(res => res.json()).then(data =>{
this.setState({loggedin: data})
});
}
isLoggedIn(){
fetch('/user-status',{ method: 'GET'})
.then(function (response) {
return response.json();
}).then(function (textie) {
this.setState({loggedin: textie})
return textie;
});
}
render() {
if(this.isLoggedIn == 'true'){
return(
<a className="nav-item nav-link" href="/logout">Logout</a>
);
}
return (
<nav className="navbar navbar-expand-lg navbar-dark bg-primary">
<a className="navbar-brand" href="#">Navbar</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavAltMarkup">
<div className="navbar-nav">
<a className="nav-item nav-link active" href="#">Home <span className="sr-only">(current)</span></a>
<a className="nav-item nav-link" href="/about">About</a>
<a className="nav-item nav-link" href="/signin">Sign in/Sign Up</a>
<a className="nav-item nav-link" href="/profile">My Profile</a>
<a className="nav-item nav-link" href="/leaderboard">Top Forecasts</a>
</div>
</div>
</nav>
);
}
}
export default Navbar;
The /user-status method gets whether or not the user is logged in from Flask backend, and returns either true or false. I try to save it once it changes in isLoggedIn, but I get the error cannot 'setState' on undefined. Also, when it returns textie from isLoggedIn, it returns the statement 'bound isLoggedIn' instead of true or false, and I'm not sure why.
I try to say in the render part that if the loggedin variable is true, there will be a Navbar option to logout, but if there isnt, there will be a navbar option to log in. Any thoughts why this isn't working and this error keeps popping up? I guess what I'd like to know is how to save a fetched data into a react component.
In this line if(this.isLoggedIn == 'true') you are checking if the function isLoggedIn in the this scope is equals to true, but you actually should call to this.state.isloggedIn == 'true' I think.
Try this:
class Navbar extends React.Component {
state = { loggedin: '' };
componentDidMount() {
this.isLoggedIn();
}
isLoggedIn = () => {
fetch('/user-status')
.then((res) => res.json())
.then((data) => this.setState({ loggedin: data }));
};
render() {
if (this.state.loggedin == 'true') {
return (
<a className='nav-item nav-link' href='/logout'>
Logout
</a>
);
}
return (
<nav className='navbar navbar-expand-lg navbar-dark bg-primary'>
<a className='navbar-brand' href='#'>
Navbar
</a>
<button
className='navbar-toggler'
type='button'
data-toggle='collapse'
data-target='#navbarNavAltMarkup'
aria-controls='navbarNavAltMarkup'
aria-expanded='false'
aria-label='Toggle navigation'
>
<span className='navbar-toggler-icon'></span>
</button>
<div className='collapse navbar-collapse' id='navbarNavAltMarkup'>
<div className='navbar-nav'>
<a className='nav-item nav-link active' href='#'>
Home <span className='sr-only'>(current)</span>
</a>
<a className='nav-item nav-link' href='/about'>
About
</a>
<a className='nav-item nav-link' href='/signin'>
Sign in/Sign Up
</a>
<a className='nav-item nav-link' href='/profile'>
My Profile
</a>
<a className='nav-item nav-link' href='/leaderboard'>
Top Forecasts
</a>
</div>
</div>
</nav>
);
}
}
export default Navbar;

React - How to change the props of a child component when an event happens?

I have a component called Nav. I want send props to another component called Body when the user use types in a search bar. The issue I'm having is that the value in the Body component does not change when I type in the search bar.
The Nav class:
constructor(props) {
super(props);
this.state = { id: "" };
this.handleChange = this.handleChange.bind(this);
}
handleChange = event => {
this.setState({ id: event.target.value });
};
render() {
return (
<div>
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarTogglerDemo03"
aria-controls="navbarTogglerDemo03"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon" />
</button>
<a className="navbar-brand" href="#">
<img src="https://icon-icons.com/icons2/1412/PNG/48/comics-spiderman-cam_97492.png" />
Home
</a>
<div className="collapse navbar-collapse" id="navbarTogglerDemo03">
<ul className="navbar-nav mr-auto mt-2 mt-lg-0">
<li className="nav-item active">
<a className="nav-link" href="#">
<span class="sr-only">(current)</span>
</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#">
Link
</a>
</li>
<li className="nav-item">
<a
className="nav-link disabled"
href="#"
tabindex="-1"
aria-disabled="true"
>
Disabled
</a>
</li>
</ul>
<form
className="form-inline my-2 my-lg-0"
onSubmit={() => {
console.log(this.state.id);
}}
>
<input
className="form-control mr-sm-2"
type="search"
placeholder="Search"
aria-label="Search"
value={this.state.id}
onChange={this.handleChange}
/>
<button className="btn btn-light" type="submit">
Search
</button>
</form>
</div>
</nav>
<Body valorId={this.state.id} />
{alert(this.state.id)}
</div>
);
}
The body class:
constructor(props) {
super(props);
this.state = { heroe: null, loading: true };
}
async componentDidMount() {
const url = "https://superheroapi.com/api/2132321/" + this.props.valorId;
console.log("aca va:" + this.props.valorId);
alert(url);
const response = await fetch(url);
const data = await response.json();
console.log(data.name);
this.setState({ heroe: data, loading: false });
}
Thank you.
componentDidMount will only run when the component is first mounted. You could instead move the logic to a separate method and call that both in componentDidMount and in componentDidUpdate when the valorId prop changes.
Example
class Body extends React.Component {
constructor(props) {
super(props);
this.state = { heroe: null, loading: true };
}
componentDidMount() {
this.loadHeroe();
}
componentDidUpdate(prevProps) {
if (this.props.valorId !== prevProps.valorId) {
this.loadHeroe();
}
}
loadHeroe = async () => {
this.setState({ loading: true });
const url = "https://superheroapi.com/api/2132321/" + this.props.valorId;
const response = await fetch(url);
const data = await response.json();
this.setState({ heroe: data, loading: false });
};
render() {
// ...
}
}
The problem is that you use componentDidMount
This function is called one time, at the mount of the component.
Try to use componentDidUpdate instead

ReactJs setState undefined when using react-autoBind

Getting this Uncaught TypeError: Cannot read property 'setState' of undefined when trying to setState in a function. I'm aware that there are other similar issues already posted but none of them are using react-autobind
this works when I bind the function in the constructor Like so :
this.toggleNav = this.toggleNav.bind(this)
However I would like to accomplish this with react-autobind
import React from "react";
import ReactDOM from "react-dom";
import ScrollspyNav from "react-scrollspy-nav";
import autoBind from 'react-autobind';
export default class Navigation extends React.Component {
constructor(props) {
super(props);
autoBind(this);
this.state = {
toggleMobileNav: false
};
}
toggleNav() {
this.setState((prev, props) => {
return {
toggleMobileNav: !prev.toggleMobileNav
}
});
}
render() {
return(
<ScrollspyNav
scrollTargetIds={["page-top", "about", "projects", "signup"]}
activeNavClass="is-active"
scrollDuration="1000"
headerBackground="false"
activeNavClass="active-nav"
>
<nav className="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
<div className="container">
<a id="page-top" className="navbar-brand js-scroll-trigger" href="#page-top">Start Bootstrap</a>
<button className="navbar-toggler navbar-toggler-right" onClick={this.toggleNav} type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i className="fas fa-bars"></i>
</button>
<div className= {this.state.toggleMobileNav ? "show collapse navbar-collapse" : " " + 'collapse navbar-collapse'} id="navbarResponsive">
<ul className="navbar-nav ml-auto">
<li className="nav-item">
<a className="nav-link" href="#about">About</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#projects">Projects</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#signup">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
</ScrollspyNav>
)
}
}
If you use arrow function syntax to declare your method, you will not need to call this.toggleNav = this.toggleNav.bind(this) or use react-autobind
toggleNav = () => {
this.setState((prev, props) => {
return {
toggleMobileNav: !prev.toggleMobileNav
}
});
}
Here's a Medium post that covers all the options: https://medium.com/komenco/react-autobinding-2261a1092849

How to import dropdown with autocomplete in the navbar

Im really new in the react and may be my code is very wrong, but how can create a dropdown with autocomplete in the navbar with bootstrap in React JS.
I read too much examples but my code never run..
I try to create dropdown with create-select but I dont know exactly how..
My code:
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
import PropTypes from 'prop-types';
import createClass from 'create-react-class';
export default class Header extends Component {
var ValuesAsBooleansField = createClass({
displayName: 'ValuesAsBooleansField',
propTypes: {
label: PropTypes.string
},
getInitialState () {
return {
options: [
{ value: true, label: 'Yes' },
{ value: false, label: 'No' }
],
value: null
};
},
onChange(value) {
this.setState({ value });
console.log('Boolean Select value changed to', value);
},
render () {
return (
<div className="section">
<h3 className="section-heading">{this.props.label} (Source)</h3>
<Select
onChange={this.onChange}
options={this.state.options}
simpleValue
value={this.state.value}
/>
<div className="hint">This example uses simple boolean values</div>
</div>
);
}
});
module.exports = ValuesAsBooleansField;
render() {
return (
<nav class="navbar navbar-toggleable-md navbar-inverse bg-inverse ">
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="#">WeatherGraph</a>
<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">Начало <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Времето</a>
</li>
</ul>
</div>
</nav>
);
}
}
You have mixed up the Es5 and Es6 coding style. Just update your code and it's working fine now.
import React, { Component } from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
export default class ValuesAsBooleansField extends Component {
constructor(props){
super(props);
this.state = {
options: [
{ value: true, label: 'Yes' },
{ value: false, label: 'No' }
],
value: null
}
this.onChange = this.onChange.bind(this);
}
onChange(event) {
this.setState({value: event.value});
console.log('Boolean Select value changed to', event.value);
}
render () {
return (
<div className="section">
<h3 className="section-heading">{this.props.label} (Source)</h3>
<Select
onChange={this.onChange}
options={this.state.options}
value={this.state.value}
/>
<div className="hint">This example uses simple boolean values</div>
</div>
);
}
}
**************** Paste this code in Header.js file *************
import React, { Component } from 'react';
import ValuesAsBooleansField from './ValuesAsBooleansField';
export default class Header extends Component {
render() {
return (
<nav class="navbar navbar-toggleable-md navbar-inverse bg-inverse ">
<button class="navbar-toggler navbar-toggler-right"
type="button" data-toggle="collapse"
data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<ValuesAsBooleansField />
<a class="navbar-brand" >WeatherGraph</a>
<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link">Начало <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link">Времето</a>
</li>
</ul>
</div>
</nav>
);
}
}

Categories

Resources