I'm trying to add a Leader to my DB via a post.
I want to select a branch so the leader is linked to that branch.
but When I select the branch from the select box the Id does not get filled and I get the following error:
.branchId: [,…]
0: "The JSON value could not be converted to System.Guid. Path: $.branchId | LineNumber: 0 | BytePositionInLine: 30."
been stuck for a day now, help is muich appreciated
import React, {useState, useEffect} from 'react'
import axios from 'axios'
const LeadersPost = () => {
const [totem, setTotem] = useState('');
const [branchId, setBranchId] = useState('')
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async() => {
try{
const {data: response} = await axios.get('https://localhost:7070/api/Branches');
setData(response);
} catch (error) {
console.error(error.message);
}
}
fetchData();
}, []);
const onSubmit = async (e) => {
e.preventDefault();
const data = {
totem : totem,
branchId : branchId
}
try{
await axios.post('https://localhost:7070/api/Leaders', data)
.then(res => {
setData(res.data);
setTotem('');
setBranchId('');
})
} catch (error){
console.error(error.message);
}
}
return(
<div className='container mt-2'>
<h2>Leaders Post Request</h2>
<form onSubmit={onSubmit}>
<div className='mb-2 mt-3'>
<input
type={'text'}
placeholder='Leader Totem'
className='form-control'
value={totem}
onChange={e => {
setTotem(e.target.value)
}} />
<select className="form-control" aria-label="Default select example">
<option>Choose a branch</option>
{
data.map(branch =>
<option
onChange={ e => {
setBranchId(e.target.value)
}}>
{branch.id}
</option>)
}
</select>
<button type='submit' className='btn btn-primary'>Create</button>
</div>
</form>
</div>
)
}
export default LeadersPost
I don't believe the option fires an onchange event, I could be wrong but if my memory serves me correctly it doesn't. Also just checked MDN web docs and I may be correct in that.
However, I also believe the value of the option not being set would also cause this to happen. You're just setting a textConext on the event, so you could make it work potentially by that too but you may want to take a look at this answer here for select boxes in react.
Related
I want to submit a form into mongoDB using nodejs API & reactJs. With the exception of the multiple select option, everything is operating as it should be.
Being new to react, I have no idea how to handle the multi select option's onChange method.
Here is what I've tried:
import React, { useState, useRef } from "react";
import { useForm } from "react-hook-form";
import { v4 as uuidv4 } from 'uuid';
import axios from "axios";
import Select from 'react-select';
export default function EventForm(props) {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm();
const form = useRef();
const [loading, setLoading] = useState(false);
const [info, setInfo] = useState("");
const [analysis, setAnalysis] = useState("Undefined");
const [relatedEvent, setRelatedEvent] = useState([]);
const handleInfoChange = (e) => {
setInfo(e.target.value)
}
const handleAnalysisChange = (e) => {
setAnalysis(e.target.value)
}
const handleRelatedEvents = (e) => {
setRelatedEvent(e.target.value)
}
const relatedEventsData = props.data.map(opt => ({ label: opt.info, value: opt._id }));
const onSubmit = async () => {
setLoading(true);
const MySwal = withReactContent(Swal);
const eventData = {
UUID: uuidv4(),
info: info,
analysis: analysis,
relatedEvent: relatedEvent,
}
axios
.post(`${process.env.REACT_APP_PROXY}/api/events`, eventData)
.then((res) => {
console.log(res);
setLoading(false);
MySwal.fire(
"Success!",
"A new event has been saved successfully",
"success"
);
})
.catch((error) => {
console.log(error);
});
};
return (
<div className="panel-body">
<Form
ref={form}
onSubmit={handleSubmit(onSubmit)}
className="form-horizontal"
>
<div className="row">
<div className="col-lg-6">
<div className="mb-3">
<Form.Label>Info</Form.Label>
<Form.Control
type="text"
placeholder="Enter info..."
{...register("info", { required: true })}
value={info}
onChange={handleInfoChange}
/>
{errors.info && (
<ul className="parsley-errors-list filled" id="parsley-id-7" aria-hidden="false">
<li className="parsley-required">This value is required.</li>
</ul>
)}
</div>
</div>
<div className="col-lg-6">
<div className="mb-3">
<Form.Label>Related events</Form.Label>
<Select
options={relatedEventsData}
value={relatedEvent}
isMulti
onChange={handleRelatedEvents}
/>
</div>
</div>
<div className="col-lg-12">
<Button variant="primary" type="submit">
{loading ? "Saving..." : "Save"}
</Button>
</div>
</div>
</Form>
</div>
);
}
Could you please guide me how to make it work!
Thank you
you can make use of Select onChange event handler which passes the selected options as an array as argument ..
from that you can map over it to get the values as required
something as below:
const handleChange = (opts) => {
const selectedValues = opts.map((opt) => opt.value);
setSelectedValues(selectedValues);
};
Please check the working sample for better clarity 😉 -
The state restaurants changes from an input form in the front and updates a database in the back. Then the idea is to show the RestaurantList component with the new added restaurant from the input. The idea is not to use the useContext hook. I´ve tried using the useEffect hook to render the list everytime the restaurant state changes, but this makes infinit GET requests in my backend.
const RestaurantsList = (props) => {
const [restaurants, setRestaurants] = useState("");
useEffect(async () => {
try {
const response = await fetch("http://localhost:3001/api/v1/restaurants");
const data = await response.json();
setRestaurants(data);
console.log(data);
} catch (err) {
console.log(err);
}
}, [restaurants]);
...
With this code, the front updates OK and shows the new restaurant, but the back keep making get requests. Why is this happening if the restaurants state isnt changing? Any recommendation? How can I avoid this loop?
I've tried one thing that works and is to remove the preventDefault event when I click the add button. In this way, the page reloads and do what I want but i dont know if it is the best practice:
const AddRestaurant = () => {
const [name, setName] = useState("");
const [location, setLocation] = useState("");
const [priceRange, setPriceRange] = useState("");
const handleSubmit = async function (e) {
//e.preventDefault();
try {
await fetch("http://localhost:3001/api/v1/restaurants", {
method: "POST",
made: "cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name,
location,
price_range: priceRange,
}),
});
} catch (err) {
console.log(err);
}
setName("");
setLocation("");
setPriceRange("");
};
return (
<div className="mb-4">
<form action="" on>
<div className="form-row">
<div className="col">
<input
type="text"
value={name}
className="form-control"
placeholder="Name"
onChange={nameUpdate}
/>
</div>
<div className="col">
<input
className="form-control"
value={location}
type="text"
placeholder="Location"
onChange={locationUpdate}
/>
</div>
<div className="col">
<select
className="custom-select my-1 mr-sm-2"
value={priceRange}
onChange={(e) => setPriceRange(e.target.value)}
>
<option disabled>Price Range</option>
<option value="1">$</option>
<option value="2">$$</option>
<option value="3">$$$</option>
<option value="4">$$$$</option>
<option value="5">$$$$$</option>
</select>
</div>
<button className="btn btn-primary" onClick={handleSubmit}>
Add
</button>
</div>
</form>
</div>
);
};
export default AddRestaurant;
are you saying that RestaurantsList() is throwing the infinite loop? Everything I see here is frontend code. The reason you are getting an infinite loop is because you have a set dependency of [restaurants] in your useEffect hook. Every time it grabs that data it gets updated, causing it call the function again. If you just want it to fetch the data once then leave the dependency array blank.
Try this:
const [restaurants, setRestaurants] = useState("");
useEffect(() => {
const fetchData = async () => {
const response = await fetch('http://localhost:3001/api/v1/restaurants')
const data = await response.json();
console.log(data);
setRestaurants(data);
}
fetchData();
}, []);```
i am trying to make a CRUD app in DRF-Reactjs by following Tania rascia's example
i have successfully implemented add, delete, list view. but i am trying to edit a specific row which is not updating in DRF backend. but the edited row is shown in the frontend list. why it is not updating in django admin list?
in DRF side views.py:
#api_view(['POST'])
def TodoUpdate(request, pk):
todo = Todo.objects.get(id=pk)
serializer = TodoSerializer(instance=todo, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
i am using cors header to interface between frontend to backend. here is the frontend code for edit:
App.js:
import React,{Fragment, useState,useEffect} from 'react'
import EditList from './components/EditList';
import axios from 'axios'
export default function App() {
const initialTodoSate = { id: null, title: "", body: "" };
const [todos, setTodos] = useState([]);
const [todoList, setTodolist] = useState(initialTodoSate);
const [editing, setEditing] = useState(false);
useEffect(()=>{
axios.get("http://localhost:8000/api/todo-list",{})
.then(res=>{
setTodos(res.data)
}).catch(err=>{
console.log(err)
})
},[])
const addTodoList = (todo) => {
axios
.post("http://localhost:8000/api/todo-create/",todo)
.then((res) => {
console.log(res.data);
todo.id = todos.length + 1;
setTodos([todo, ...todos]);
})
.catch((err) => {
console.log(err);
});
};
const deleteTodo = (id) => {
setEditing(false);
axios.delete(`http://localhost:8000/api/todo-delete/${id}/`)
.then(res=>{
setTodos(todos.filter((todo) => todo.id !== id));
}).catch(err=>{
console.log(err)
})
};
const updateTodo = ( id,updatedTodo) => {
axios
.post(`http://localhost:8000/api/todo-update/${id}/`, id)
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
setEditing(false);
setTodos(todos.map((todo) => (todo.id === id ? updatedTodo : todo)));
};
const editRow = (todo) => {
setEditing(true);
setTodolist({
id: todo.id,
title: todo.title,
description: todo.description,
});
};
return (
<div className="container">
<h1>Django-based Todo with React Hooks</h1>
{editing ? (
<Fragment>
<h3>Edit Task</h3>
<EditList
editing={editing}
setEditing={setEditing}
todoList={todoList}
updateTodo={updateTodo}
/>
</Fragment>
) : (
<Fragment>
<CreateTodo addTodoList={addTodoList} />
<hr />
</Fragment>
)}
<div className="flex-row">
<div className="flex-large">
<TodoList todos={todos} editRow={editRow} deleteTodo={deleteTodo} />
</div>
</div>
</div>
);
}
and EditList.js:
import React, { useState,useEffect } from "react";
export default function EditList({ todoList, setEditing, updateTodo }) {
const [todo, setTodo] = useState([todoList]);
useEffect(() => {
setTodo(todoList);
}, [todoList]);
const handleChange = (e) => {
const { name, value } = e.target;
setTodo({ ...todo, [name]: value });
};
return (
<form
onSubmit={(e) => {
e.preventDefault();
updateTodo(todo.id, todo);
}}
>
<label>Title:</label>
<br />
<input
type="text"
name="title"
value={todo.title}
onChange={handleChange}
/>
<br />
<label>Description:</label>
<br />
<input
type="text"
name="body"
value={todo.body}
onChange={handleChange}
/>
<br />
<button>Update Task</button>
<button onClick={() => setEditing(false)} className="button muted-button">
Cancel
</button>
</form>
);
}
when i try to edit one row with title and body, it is edited and after pressing the update button, the updated row included in the list. but the problem is when i look into the django admin it has not been updated and when i check the development tools, i found an error:
Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
at input
at form
at EditList (http://localhost:3000/static/js/main.chunk.js:511:3)
at div
at App (http://localhost:3000/static/js/main.chunk.js:70:83)
console. # vendors~main.chunk.js:31671
where am i having the mistake?
can anyone help me please? please let me know if you need any additional codes or information.
Trying to update something should be done in a put request, not a post request. This is a REST API convention, but a discrepancy may have some consequence down the line.
In this case, the error in your development tools is telling you that one of your components has an onChange/onSubmit etc property that is changing over the course of one mount from null to a function. This is not what's causing your issue, but I suspect it can be fixed by declaring the code in a handleSubmit function and then putting that into your onSubmit.
I think the error that's actually causing your problem is that the updatedTodo is not being sent to the backend. All that is being sent is the id (second parameter of axios.post). So if you pause the backend during execution, you would see that request.data = the id only, when it should be TodoSerializer's readable fields.
PS:
You can add a "debugger;" statement in the code after the updateToDo async request error to see what the error actually is (read more on the development tools debugging - browser dependent).
Don't abuse fragments - in this case, it would make for a more accessibility-friendly experience if you use divs in most of these components. Wouldn't it make more sense if the heading of some content was grouped with the content? https://developers.google.com/web/fundamentals/accessibility/focus/dom-order-matters
I can't update the state when I am calling a second API inside a react functional component. The first API call is inside useEffect, and the second API call is done when the user clicks the button. When the second API call is done react throws this error "Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function."
And the state is not updating, I want to set the state after the second API call. How to fix this?
My code:
const AddNewProduct = () => {
const [productName, setProductName] = useState("");
const [originalPrice, setOriginalPrice] = useState("");
const [newPrice, setNewPrice] = useState("");
const [category, setCategory] = useState("");
const [description, setDescription] = useState("");
const [categoriesArray, setCategoriesArray] = useState([]);
const [isLogin, setIsLogin] = useState([]);
const [id, setId] = useState("");
useEffect(() => {
const getCategoriesData = async () => {
const Data = await fetchCategoriesApi();
setIsLogin(Data.data.login);
setCategoriesArray(Data.data.data);
console.log(Data);
};
getCategoriesData();
}, []);
const handleCategoryClick = (id) => {
setCategory(id);
console.log(id);
};
const handleNextClick = async () => {
const postApi = "https://fliqapp.xyz/api/seller/products";
try {
const post = await axios
.post(
postApi,
{
product_name: productName,
product_desc: description,
product_price: originalPrice,
product_cat: category,
},
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
)
.then((response) => {
setId(response.data.data.product_id);
console.log(id);
console.log(response);
});
} catch (error) {
return error;
}
console.log("clicked");
};
return (
<>
<div className={styles.container}>
<div className={styles.blank}></div>
<input
type="text"
className={styles.input_field}
placeholder="Product name*"
onChange={(e) => setProductName(e.target.value)}
/>
<input
type="text"
className={styles.input_field}
placeholder="original price*"
onChange={(e) => setOriginalPrice(e.target.value)}
/>
<input
type="text"
className={styles.input_field}
placeholder="new price"
onChange={(e) => setNewPrice(e.target.value)}
/>
<select
name="parent category"
id="parentcategory"
className={styles.dropdown}
defaultValue={"DEFAULT"}
onChange={(e) => handleCategoryClick(e.target.value)}
>
<option value="DEFAULT" disabled>
select category
</option>
{isLogin &&
categoriesArray.map((item, index) => (
<option value={item.id} key={index}>
{item.cat_name}
</option>
))}
</select>
<textarea
type="textarea"
className={styles.input_field}
placeholder="Description"
rows="4"
onChange={(e) => setDescription(e.target.value)}
/>
<Link
to={{
pathname: `/add_image/${id}`,
}}
className={styles.btn}
onClick={handleNextClick}
disabled
>
Next
</Link>
<div className={styles.header}>
<h1 className={styles.heading_normal}>Add new product</h1>
</div>
</div>
</>
);
};
You need to change your Link to Button and manually navigate to other route because id used in route /add_image/${id} is coming from second Api call.
Reason : because when you click on Link it will fire axios request and change route of your app, thus current component is unmounted and new route component is mounted, after this happens your axios response comeback and try to setState on unmounted component.
// import
import { useHistory } from 'react-router-dom';
// inside component
const history = useHistory();
// click handler
const handleNextClick = async () => {
// ...axiosrequest
.then((response) => {
setId(response.data.data.product_id); // may be not needed now
const id = response.data.data.product_id;
history.push(`/add_image/${id}`);
}
}
// button
<button
className={styles.btn}
onClick={handleNextClick}
>
Next
</button>
In this way you change route only once after you get proper response from server and based on response ID you update your route.
For better user experience you can show loading meanwhile you perform axios ajax request.
if any doubt please comment.
I'm making a basic weather app with React, and having an issue getting my setWeather to update weather. I had read that setState doesn't update state the first time it's called, and that seems consistent with the empty object that console.log(weather) returns. cityData returns the full response, as expected, but weather.name and non-nested data (i.e. only strings, not arrays or objects) functions properly, which is unexpected.
I would like to know how to get setWeather to perform as advertised, and why the arrays and objects that the API return are showing as undefined.
import React, { useState } from 'react';
import axios from 'axios';
const Search = () => {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
const findCity = (e) => {
e.preventDefault()
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}`)
.then(res => {
const cityData = res.data;
console.log(cityData);
setWeather(res.data);
setQuery('');
console.log(weather)
}).catch(err => console.log(err))
}
return(
<React.Fragment>
<h1>App</h1>
<p>Get the weather in your city!</p>
<form onSubmit={findCity}>
<input
type='text'
className='city-search'
placeholder='What city are you looking for?'
name='city-name'
onChange={e => setQuery(e.target.value)}
value={query}
/>
<button
type='submit'>
Get City
</button>
</form>
<h1>{weather.name}</h1>
</React.Fragment>
)
}
You won't be able to do console.log(weather) in the submit handler because the submit handler is still using the old weather (i.e. from current render). Do this instead:
const Search = () => {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
const findCity = (e) => {
e.preventDefault()
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}`)
.then(res => {
const cityData = res.data;
console.log(cityData);
setWeather(res.data);
setQuery('');
}).catch(err => console.log(err))
}
console.log(weather) //<-- THIS IS THE ONLY THING I'VE CHANGED
return(
<React.Fragment>
<h1>App</h1>
<p>Get the weather in your city!</p>
<form onSubmit={findCity}>
<input
type='text'
className='city-search'
placeholder='What city are you looking for?'
name='city-name'
onChange={e => setQuery(e.target.value)}
value={query}
/>
<button
type='submit'>
Get City
</button>
</form>
<h1>{weather.name}</h1>
</React.Fragment>
)
}
https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}
Are you passing the query and APIKEY here. If not please add them as well to your axios call. Am assuming that your getting an invalid response. APIKEY has to be provided to get a successful response from the Weather API.