I am trying to write a program that takes names of 2 cities as an input, and then gets the temperature in the 2 cities using the openweathermap API. However, I am unable to call the API. I tried following some tutorials but it is a bit confusing. I would be glad if someone could help me with connecting to the API, and getting the temperature for the cities, and print them on screen.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import _ from 'lodash';
import Request from 'superagent';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {input1: '', input2: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
componentDidMount(){
var city1 = this.state.input1;
var url= 'http://api.openweathermap.org/data/2.5/weather?q={city1}&units=metric&APPID=83c6ba4dd07d83514536821a8a51d6d5';
Request.get(url).then((response) => {
this.setState({
report: response.body.Search
});
});
}
handleSubmit(event) {
var temperature = _.map(this.state.report, (city) => {
return (<p>{city.main.temp}</p>);
});
event.preventDefault();
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
<div className="container">
<h1>Where Should I go?</h1>
<form onSubmit={this.handleSubmit}>
<div className="cityboxdiv">
<input name="input1" type="text" id="tb1" className="citybox" onChange={this.handleChange} placeholder="Enter City1" autoFocus />
<input name="input2" type="text" id="tb2" className="citybox" onChange={this.handleChange} placeholder="Enter City2"/>
</div>
<div className="btn-div">
<button type="submit" className="sub-btn">Tell Me!</button>
</div>
</form>
</div>
</div>
);
}
}
export default App;
Two things I would like to know are how to pass the city names into the url so that we can get the data. And once we get the data, how can I display only the temperature values of the cities.
I see you make several mistakes.
Request to API and put data to state you should make inside handleSubmit (or better use actions).
In render method you should output your state data as state.report.map(item => (<div>{city.main.temp}</div>))
Generate url you can make using template string (https://learn.microsoft.com/en-us/scripting/javascript/advanced/template-strings-javascript)
Related
I wish to share this code just in case someone might need to solve such a problem of filtering unwanted characters when doing forms in react. For extras, my code shows how to pass props to components inside Route. For simplicity, I have focused on only these two inputs and omitted other stuff such as the submit button and css data for styling those classNames and ids.
import React, { Component } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import SignupForm from "./components/SignupForm";
class App extends Component {
constructor() {
super();
this.state = {
firstName: "",
lastName: "",
};
//Binding this to the functions used as they wouldn't just work if not bound
this.changeFirstName = this.changeFirstName.bind(this);
this.changeLastName = this.changeLastName.bind(this);
this.lettersOnly = this.lettersOnly.bind(this);
}
changeFirstName(e) {
this.setState({ firstName: e.target.value });
}
changeLastName(e) {
this.setState({ lastName: e.target.value });
}
// Error handler functions
lettersOnly(nameInput) {//Replacing all characters except a-z by nothing with this function
let regex = /[^a-z]/gi;
nameInput.target.value = nameInput.target.value.replace(regex, "");
}
render() {
return (
<Router>
<div className="App">
<Route
exact
path="/"
comp={SignupForm}
render={() => (
<SignupForm
//SignupForm submit props
changeFirstNameHandler={this.changeFirstName}
firstNameValue={this.state.firstName}
changeLastNameHandler={this.changeLastName}
lastNameValue={this.state.lastName}
// Error handlers
nameCharacterFilter={this.lettersOnly}
/>
)}
/>
)}
/>
</div>
</Router>
);
}
}
export default App;
Below is the signup form, which is the child component in this aspect, and also a function component as opposed to its parent component:
import React from "react";
export default function SignupForm(props) {
return (
<div className="container" id="signupForm">
<h1>Signup Form</h1>
<div className="form-div">
<form>
<input
type="text"
placeholder="First Name"
onChange={props.changeFirstNameHandler}
value={props.firstNameValue}
onKeyUp={props.nameCharacterFilter}
className="form-control formgroup"
/>
<input
type="text"
placeholder="Last Name"
onChange={props.changeLastNameHandler}
value={props.lastNameValue}
onKeyUp={props.nameCharacterFilter}
className="form-control formgroup"
/>
</form>
</div>
</div>
);
}
NB: Welcome to improve this code, if you feel the need!
I think you can improve you're code with this changes:
Use the regex directly in the onChange event
Use only one method to update the values
Here is an example of what I mean: https://codesandbox.io/s/react-playground-forked-vreku?fontsize=14&hidenavigation=1&theme=dark
Regards!
Okay here is an improved code and much more cleaner. However, I have just omitted the React Router part to focus on functionality of the state and functions in this case.
I also want the user to see when they type an unwanted character that it actually typed but then just deleted on key up so I have created an independent function justLettersAndHyphen(nameField) from changeValue(event) that is triggered by onKeyUp.
import React from "react";
import SignupForm from "./SignupForm";
class App extends React.Component {
constructor() {
super();
this.state = {
firstName: "",
lastName: ""
};
this.changeValue = this.changeValue.bind(this);
this.justLettersAndHyphen = this.justLettersAndHyphen.bind(this);
}
changeValue(event) {
this.setState({
[event.target.name]: event.target.value,
});
}
// Error handler functions
justLettersAndHyphen(nameField) {
let regex = /[^a-z-]/gi;
nameField.target.value = nameField.target.value.replace(regex, "");
}
render() {
return (
<SignupForm
firstNameValue={this.state.firstName}
lastNameValue={this.state.lastName}
changeValueHandler={this.changeValue}
nameCharacterFilter={this.justLettersAndHyphen}
/>
);
}
}
export default App;
Child component edited with name property added.
import React from "react";
export default function SignupForm(props) {
return (
<div className="container" id="signupForm">
<h1>Signup Form</h1>
<div className="form-div">
<form>
<input
name="firstName"
type="text"
placeholder="First Name"
onChange={props.changeValueHandler}
onKeyUp={props.nameCharacterFilter}
value={props.firstNameValue}
/>
<input
name="lastName"
type="text"
placeholder="Last Name"
onChange={props.changeValueHandler}
onKeyUp={props.nameCharacterFilter}
value={props.lastNameValue}
/>
</form>
</div>
</div>
);
}
I'm new to React and i'm trying to pass data (a date - 'dd/mm/yyyy') to a second page from an input box on the home page. I'm confused as to where i put my Link, what information i put in the redirect(if any) and also the syntax to send and receive it on page it. Here is the code i have so far. Please can anybody help?:
class Home extends React.Component {
constructor(props) {
super(props);
this.state = { inputDate: '' };
}
myChangeHandler = (event) => {
this.setState({inputDate: event.target.value});
}
render() {
let dateEntered = this.state.inputDate
return (
<form>
<h3 >Enter Date :
<input
type="text" className="input-text" placeholder={"DD/MM/YYYY"} onChange={this.myChangeHandler}
/>
</h3>
<button className="button half-page-width-button button-blue1"><Link to={{
pathname: '/Page1',
state: [{dateEntered}]
}}>Submit Date</Link>
</button>
</form>
);
}
}
Thanks again
Thank you for getting back to me. My receiving component looks like this. Where would I put the code? In the render section?
import React, {Component} from 'react';
import Home from './components/Home';
import './App.css';
class Page1 extends Component {
render() { // Table Data
return (
<form>
<h3 >Enter Date :
<input
type="text" className="input-text" value={this.state.header}
/>
</h3>
</form>
);
}
}
export default Page1;
You can make use of state to pass on to data to the Link Component and receive it from location in the component rendered at /Page1 path
class Home extends React.Component {
constructor(props) {
super(props);
this.state = { inputDate: '' };
}
myChangeHandler = (event) => {
this.setState({inputDate: event.target.value});
}
render() {
let dateEntered = this.state.inputDate
return (
<form>
<h3 >Enter Date :
<input
type="text" className="input-text" placeholder={"DD/MM/YYYY"} onChange={this.myChangeHandler}
/>
</h3>
<button className="button half-page-width-button button-blue1"><Link to={{
pathname: '/Page1',
state: {dateEntered}
}}>Submit Date</Link>
</button>
</form>
);
}
}
In the receiving component
class Page1 extends Component {
render() { // Table Data
const { dateEntered } = this.props.location.state || {};
return (
<form>
<h3 >Enter Date :
<input
type="text" className="input-text" value={this.state.header}
/>
</h3>
</form>
);
}
}
export default Page1;
I'm trying to write an XSS CTF exercise on React. To start I'm trying to get a fixed javascript alert to run using dangerouslySetInnerHTML. I believe, on submit, it adds on the script to the webpage but it doesn't run. Thank you in advance!
import React, { Component } from "react";
import {withRouter} from 'react-router';
import ReactDOM from 'react-dom';
class User extends Component {
constructor(props) {
super(props);
this.state = {value: '', final: 'asdf'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
event.preventDefault()
this.setState({final:'<script type="text/javascript">alert(1)</script>'})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="Type a message" id="messageField" onChange={this.handleChange}/> <br/>
<input type="submit" className='submitbutton' value="Submit" />
</form>
<div dangerouslySetInnerHTML={{__html: this.state.final}} />
</div>
);
}
}
export default withRouter(User)
This question already has answers here:
How to pass data from child component to its parent in ReactJS?
(18 answers)
Pass props to parent component in React.js
(7 answers)
Closed 5 years ago.
In react js I have 2 components.
In Component1.jsx :
import Info from Component2.jsx;
...
...
var dataInfo = "some info.. ";
<Info dataInfo={dataInfo} />
...
...
Here in the above code, we'r transfering the data in the form props from component1.jsx to component2.jsx
In the same fashion can we transfer back to data to component2.jsx to component1.jsx ?
Please help me out here. I'm trying to find the answer in google but couldn't get properly.
Yes you can transfer back to parent component,
i will give you an example to show clearly how you can do that
suppose you have a parent it's called component1 and it have a form imported as a child in it called component2
as the follow:
import React, { Component } from 'react';
export default class Component2 extends Component{
constructor() {
super();
this.state = {
UserName: '',
email: ''
};
this.onSubmit = this.onSubmit.bind(this)
}
onSubmit(e){
e.preventDefault();
var field = {
UserName: this.state.UserName,
email : this.state.email,
password: this.state.password,
}
**this.props.onUpdate(field);**
}
onChange(e){
this.setState({
[e.target.name]: e.target.value
});
}
render() {
var UserNameError = **this.props.UserNameError**;
var emailError = **this.props.emailError**;
return(
<div className="col-md-6 col-sm-6">
<div className="title">Create Account</div>
<Form onSubmit={this.onSubmit}>
<div className="form-group">
<label>user Name</label>
<input onChange={this.onChange.bind(this)} value={this.state.UserName} name='UserName'/>
<span className="error is-visible">{UserNameError}</span>
</div>
<div className="form-group">
<label>Email</label>
<input onChange={this.onChange.bind(this)} value={this.state.email} name='email' />
<span className="error is-visible">{emailError}</span>
</div>
<Button className='btn submit'>Register</Button>
</Form>
</div>
)
}}
import React, { Component } from 'react';
import Component2 from './Component2'
export default class Component1 extends Component{
constructor() {
super();
this.state = {
UserName: '',
email: '',
UserNameError:' UserNameError ',
emailError:' emailError '
};
}
onUpdate(val) {
this.setState({
email: val.email,
UserName: val.UserName,
});
console.log(' onSubmit ** email' + val.email + " UserName " + val.UserName )
};
render() {
return(
<div className="col-md-6 col-sm-6">
<Component2 **UserNameError={this.state.UserNameError}** **emailError={this.state.emailError}** **onUpdate={this.onUpdate.bind(this)}** />
</div>
)
}
}
I put the stars around sentence to notice how I transfer data errors from parent Component1 to component2
and how I send Form data by onUpdate function from child Component2 to Component1
I have a component called GameSetup which is basically just a form that user can fill out. Within the GameSetup component I am calling another component called PlayerList which displays a list of players in a html list (list of strings).
On the GameSetup form there is a textbox that allows a user to input a new player name and then click the button to add the user to the game. I have a button click event on the add player button and i update the state which contains an array of strings that contains all of the players (list of strings). When I add a new player I expect the player be displayed from the PlayerList component but it is not re rendering with the correct list it is still at its initails state or it isnt being rerendered.
What do I need to do get the PlayerList component update when a new player is added to the list?
Here is my GameSetup Component:
import React from 'react';
import PlayerList from 'components/playerlist/playerlist';
export default class GameSetup extends React.Component {
constructor(props) {
super(props);
this.state = {localmode: true, players: ["test"], buyIn: 0.00, playerName: ""};
this.handleAddPlayerButtonClick = this.handleAddPlayerButtonClick.bind(this);
this.handlePlayerNameChange = this.handlePlayerNameChange.bind(this);
}
handleAddPlayerButtonClick(event) {
this.setState({
players: this.state.players.push(this.state.playerName)
});
}
handlePlayerNameChange(event) {
this.setState({
playerName: event.target.value
});
}
render() {
return (
<div>
<div className="col-lg-6">
<form>
<h2>General Game Settings</h2>
<hr />
<div className="form-group">
<input type="text" placeholder="Name of Game" className="form-control" />
</div>
<div className="form-group">
<input type="text" placeholder="Buy In" className="form-control" />
</div>
<br/>
<h2>Players</h2>
<hr />
<div className="form-group">
<input type="text" value={this.state.playerName} className="form-control" placeholder="Player Name" onChange={this.handlePlayerNameChange} />
</div>
<button className="btn btn-success" onClick={this.handleAddPlayerButtonClick}>Add Player</button>
<PlayerList players={this.state.players} />
</form>
</div>
<div className="col-lg-6">
<h2>Game Details</h2>
<hr/>
</div>
</div>
);
}
}
Here is my PlayerList component:
import _ from 'lodash';
import React from 'react';
import PlayerListRow from './playerlistrow';
export default class PlayerList extends React.Component {
render() {
var rows = [];
this.props.players.forEach(function(player){
rows.push(<PlayerListRow player={player} key={player.Id} />);
});
return (
<ul>{rows}</ul>
);
}
}
Here is PlayerlistRow component:
import React from 'react';
export default class PlayerListRow extends React.Component {
render() {
return (
<li>{this.props.player}</li>
);
}
}
Here is an example of what the screen looks like:
The reason why it doesnt show you the players, bc you mutate state (Array.prototype.push). You can use Array.prototype.concat method. Instead of mutating existing array it return new array, which you need
handleAddPlayerButtonClick(event) {
this.setState({
players: this.state.players.concat([this.state.playerName])
});
}
HTH
I think you have to pass a new array to your setState call in handleAddPlayerButtonClick(), try this:
handleAddPlayerButtonClick(event) {
newPlayers = [].concat(this.state.players).push(this.state.playerName);
this.setState({
players: newPlayers
});
}