SQL search and JavaScript .map is not a function - javascript

I have been googling around to try to solve my issue without success.
First I understand that ".map" is a method for an array, but the variable "restaurants" is in my useState. So I didn't understand why I receive the error "TypeError: restaurants.map is not a function".
I'm trying to implement a search function in a PERN app that I've been studying. This is my Search component.
Please help me understand what might be wrong. This is the full repo in case this piece of code is not enough.
Search component:
import React, { useState } from "react";
function Search() {
const [name, setName] = useState("");
const [restaurants, setRestaurants] = useState([]);
const onSubmitForm = async (e) => {
e.preventDefault();
try {
const response = await fetch(
`http://localhost:3001/api/v1/restaurants/?name=${name}`
);
const parseResponse = await response.json();
setRestaurants(parseResponse);
} catch (err) {
console.error(err.message);
}
};
return (
<>
<div className="mb-4">
<form className="form-row" onSubmit={onSubmitForm}>
<input
type="text"
name="name"
placeholder="Search"
className="form-control"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button className="btn btn-success">Submit</button>
</form>
<table className="table my-5">
<thead>
<tr>
<th>Restaurant</th>
</tr>
</thead>
<tbody>
{restaurants.map((restaurants) => (
<tr key={restaurants.restaurants_id}>
<td>{restaurants.name}</td>
<td>{restaurants.location}</td>
</tr>
))}
</tbody>
</table>
{restaurants.length === 0 && <p>No Results Found</p>}
</div>
</>
);
}
export default Search;
File in server.js:
app.get("/api/v1/restaurants", async (req, res) => {
try {
const { name } = req.query;
const restaurants = await pool.query(
"SELECT * FROM restaurants WHERE name || ' ' ||",
[`%${name}%`]
);
res.json(restaurants.rows);
} catch (err) {
console.error(err.message);
}
});

To get rid of the javascript.mapis not a function error in your react code you have to replace tbody in your react code in the following way to handle your empty restaurants array until its state gets updated from the HTTP response.
<tbody>
{
restaurants.length > 0 && restaurants.map((restaurants) => (
<tr key={restaurants.restaurants_id}>
<td>{restaurants.name}</td>
<td>{restaurants.location}</td>
</tr>
))
}
</tbody>
Your another question related to not getting response from the backend for your postgre SQL query, you must console.log() your query and try running it on SQL interface to find the syntactical errors.

Related

Delete Table Row not working properly with search bar

i'm new to reactjs and i'm trying to make a table that shows the information from a array of objects and have a button of delete and an input to search among the users. The delete button is working correctly when i'm not searching anything, but when i'm searching it doesn't delete the corretly row, and deletes only the first one. I see that it is because the arrays that show the table are different with and without the search being used but I don't know how to make it work.
this is the component of the table:
import { formatDate } from "../../utils/formatDate";
import "./table.css";
import { useState } from "react";
function Table(props) {
const { headerData, bodyData, type, removeItem} = props;
const isUser = type === "user";
const buildTableItems = () => {
return bodyData.map((item, index) => (
<tr className="data-tr">
<td>{item.name}</td>
<td>{item.email}</td>
<td>{item.occupation}</td>
<td>{formatDate(item.birthday)}</td>
<td>
<button className="delete-button" onClick={() => removeItem(index)}>
Delete
</button>
</td>
</tr>
));
};
return (
<div className="user-data">
<table className="user-table">
<thead>
<tr className="data-th">
{headerData.map((headerTable) => (
<th >{headerTable}</th>
))}
</tr>
</thead>
<tbody>{buildTableItems()}</tbody>
</table>
</div>
);
}
export default Table;
Here the component of the search bar:
import "./searchBar.css"
function SearchBar({ searchedData, onSearch }) {
return (
<div className="search-bar">
<label>Search</label>
<input type="text" placeholder="Search User" value={searchedData} onChange={e => onSearch(e.target.value)} />
</div>
);
}
export default SearchBar;
and here is the home:
import "./Home.css";
import React, { useEffect, useState } from "react";
import Header from "../components/Header/Header";
import Table from "../components/Table/Table";
import AddData from "../components/AddData/AddData";
import SearchBar from "../components/SearchBar/SearchBar";
import { userArr } from "../mock/users";
const Home = () => {
const headerUser = ["Name", "Email", "Occupation", "Birthday"];
const [newUserArr, setNewUserArr] = useState(userArr);
const [searchedItem, setSearchedItem] = useState("");
const searchedArray = newUserArr.filter((item) => {
if (item.name.toLowerCase().includes(searchedItem.toLowerCase())) {
return true;
}
});
function onSearch(e) {
setSearchedItem(e);
}
const addDataToArr = (form) => {
setNewUserArr([...newUserArr, form]);
};
const deleteData = (indexUserArr) => {
let restOfDataArray = newUserArr.filter(
(element, ind) => ind !== indexUserArr
);
setNewUserArr(restOfDataArray);
};
return (
<>
<Header />
<SearchBar searchedData={searchedItem} onSearch={onSearch} />
<Table
type="user"
headerData={headerUser}
bodyData={newUserArr}
removeItem={(index) => deleteData(index)}
/>
<AddData saveData={(val) => addDataToArr(val)} />
</>
);
};
export default Home;
thank you
If you have ID in your user data then use that instead of index or create id keywords using concatenate with your values here is examples.
import { formatDate } from "../../utils/formatDate";
import "./table.css";
import { useState } from "react";
function Table(props) {
const { headerData, bodyData, type, removeItem} = props;
const isUser = type === "user";
const buildTableItems = () => {
return bodyData.map((item, index) => (
<tr className="data-tr">
<td>{item.name}</td>
<td>{item.email}</td>
<td>{item.occupation}</td>
<td>{formatDate(item.birthday)}</td>
<td>
<button className="delete-button" onClick={() => removeItem(`${item.name}${item.email}${item.occupation}`)}>
Delete
</button>
</td>
</tr>
));
};
return (
<div className="user-data">
<table className="user-table">
<thead>
<tr className="data-th">
{headerData.map((headerTable) => (
<th >{headerTable}</th>
))}
</tr>
</thead>
<tbody>{buildTableItems()}</tbody>
</table>
</div>
);
}
export default Table;
And here is your delete method ${item.name}${item.email}${index}
const deleteData = (data) => {
let restOfDataArray = newUserArr.filter(
(element, ind) => `${element.name}${element.email}${element.occupation}` !== data
);
setNewUserArr(restOfDataArray);
};
This will fixed your problem. If this doesn't work then you need to use ID to resolve this problem. There is a possibility that ${item.name}${item.email}${item.occupation} can be duplicates.
Never use index ever for deleting or any other operations. Use always ID.

How can I fetch the username and image from diff schema to UI?

I want to fetch the username of those people who order under the user ID. Is it possible to grab the owner of the id and render it to the UI using userId? instead of rendering the actual userId.
It came from different schema in database,
import React, { useEffect, useState } from 'react'
import { format } from 'timeago.js'
import { userRequest } from '../../requestMethod'
import './Widgetlg.css'
const WidgetLg = () => {
const Button = ({ type }) => {
return <button className={'widgetLgButton ' + type}>{type}</button>
}
const [orders, setOrders] = useState([])
useEffect(() => {
const getOrders = async () => {
//this is just a shorcut api
try {
const res = await userRequest.get('orders')
setOrders(res.data)
console.log(res.data)
} catch (error) {
console.log(error)
}
}
getOrders()
}, [])
return (
<div className="widgetLg">
<h3 className="widgetLgTitle">Latest Transactions</h3>
<table className="widgetTable">
<tr className="widgetLgTr">
<th className="widgetLgTh">Customer</th>
<th className="widgetLgTh">Date</th>
<th className="widgetLgTh">Amount</th>
<th className="widgetLgTh">Status</th>
</tr>
{orders.map((order) => (
<tr className="widgetLgTr">
<td className="widgetLgUser">
<span className="WidgetLgName"> {order.userId} </span>
</td>
<td className="widgetLgDate"> {format(order.createdAt)} </td>
<td className="widgetLgAmmount">P {order.amount} </td>
<td className="widgetLgStatus">
<Button type={order.status} />
</td>
</tr>
))}
</table>
</div>
)
}
export default WidgetLg
How can I fetch and render the owner of the given userId?
UI
As Best as can tell you need to get a joint document or join query and create a simple endpoint that you can call at once at the ui side using axios.

How to print/render in a table Firebase information REACT JS

Before posting I always google, youtube, forums or try to figure it by myself or even check other people questions that are similar but I'm stuck sadly.
So I'm using firestore database, the user can create a "student" and the data is the firestore is saved like this:
It saves the course, Name, school, and the UID of the person that create it. So far I have no problems importing that information to the firestore now the issue is to bring it back in a table, I do not understand why is not being printed.
The console Log is printing all the students 1 by 1 + all the students in the array (is cause is going through all the info)
Now as you can see the table is empty! and I do not understand WHY!!! Very frustrated
This are snips of the code that are relevant:
DB part:
useEffect(() => {
db.collection('usuarios').doc(user.uid).collection('estudiantes')
.get().then((snapshot) => {
(snapshot.forEach(doc => {
const data = doc.data();
estudiantes.push(data)
console.log(doc.data());
console.log(estudiantes)
}))
})
}, []);
Map/Rendering
<tbody>
{estudiantes.map((e) => (
<tr >
<td>
<input onChange = {(event) => {
let checked = event.target.checked;
}}
type="checkbox" checked = "">
</input>
</td>
<td >{e.name}</td>
<td >{e.school}</td>
<td >{e.grade}</td>
<td></td>
</tr>
))}
</tbody>
Whole Code:
import React, { useState, useEffect } from 'react'
import { auth, db } from './firebase';
import "./ListadoEstudiantes.css"
import data from "./mock-data.json"
import { useHistory } from 'react-router-dom';
import { Checkbox } from '#material-ui/core';
function ListadoEstudiantes({user}) {
const [contacts, setContacts] = useState(data);
const history = useHistory("");
const crearEstudiante = () => {
history.push("/Crear_Estudiante");
}
const realizarPedidos = () => {
history.push("/Crear_Pedidos");
}
const estudiantes = [];
useEffect(() => {
db.collection('usuarios').doc(user.uid).collection('estudiantes')
.get().then((snapshot) => {
(snapshot.forEach(doc => {
const data = doc.data();
estudiantes.push(data)
console.log(doc.data());
console.log(estudiantes)
}))
})
}, []);
return (
<div className="listadoEstudiantes">
<div className="estudiantes_container">
<h1 className = "estudiantes_container_h1">Listado de estudiantes</h1>
<button onClick={crearEstudiante} className = "crear_estudiante_boton">Crear Estudiantes</button>
<h3 className = "estudiantes_container_h3">*Para realizar su pedido seleccione a los estudiantes</h3>
<div className ="tableContainer">
<table>
<thead>
<tr className="Lista">
<th>
<input type="checkbox"></input>
</th>
<th>Nombre</th>
<th>Colegio</th>
<th>Grado</th>
<th>Accion</th>
</tr>
</thead>
<tbody>
{estudiantes.map((e) => (
<tr >
<td>
<input onChange = {(event) => {
let checked = event.target.checked;
}}
type="checkbox" checked = "">
</input>
</td>
<td >{e.name}</td>
<td >{e.school}</td>
<td >{e.grade}</td>
<td></td>
</tr>
))}
</tbody>
</table>
</div>
<div className="space" />
<button onClick={realizarPedidos} className = "crear_estudiante_boton">Realizar Pedidos</button>
<div className="space" />
</div>
</div>
)
}
export default ListadoEstudiantes
I think that's it, the user is from the Firestore database also the data that I'm importing is a fake data that I used to test the table (and renders with no issues) that can be ignored.
This is how it looks on the fake data and how it should look with the real data (THAT DOESN'T WORK! :'3)
estudiantes should be a local state of the component. Therefore, it needs to be captured as a state and use it for table data rendering as follows.
setEstudiantes is a setState function which updates the state asynchornously. Therefore, in order to check the updated state, you need to have the console.log("estudiantes: ", estudiantes) inside the render method (not after setEstudiantes(tempData)). Otherwise, you won't be able to see the updated state.
import React, { useState, useEffect } from "react";
import { auth, db } from "./firebase";
import "./ListadoEstudiantes.css";
import data from "./mock-data.json";
import { useHistory } from "react-router-dom";
import { Checkbox } from "#material-ui/core";
function ListadoEstudiantes({ user }) {
const [contacts, setContacts] = useState(data);
const [estudiantes, setEstudiantes] = useState([]);
const history = useHistory("");
const crearEstudiante = () => {
history.push("/Crear_Estudiante");
};
const realizarPedidos = () => {
history.push("/Crear_Pedidos");
};
useEffect(() => {
db.collection("usuarios")
.doc(user.uid)
.collection("estudiantes")
.get()
.then((snapshot) => {
const tempData = [];
snapshot.forEach((doc) => {
const data = doc.data();
tempData.push(data);
console.log(doc.data());
console.log("Temp Data: ", tempData);
});
setEstudiantes(tempData);
});
}, []);
console.log("estudiantes: ", estudiantes);
return (
<div className="listadoEstudiantes">
<div className="estudiantes_container">
<h1 className="estudiantes_container_h1">Listado de estudiantes</h1>
<button onClick={crearEstudiante} className="crear_estudiante_boton">
Crear Estudiantes
</button>
<h3 className="estudiantes_container_h3">
*Para realizar su pedido seleccione a los estudiantes
</h3>
<div className="tableContainer">
<table>
<thead>
<tr className="Lista">
<th>
<input type="checkbox"></input>
</th>
<th>Nombre</th>
<th>Colegio</th>
<th>Grado</th>
<th>Accion</th>
</tr>
</thead>
<tbody>
{estudiantes.map((e) => (
<tr>
<td>
<input
onChange={(event) => {
let checked = event.target.checked;
}}
type="checkbox"
checked=""
></input>
</td>
<td>{e.name}</td>
<td>{e.school}</td>
<td>{e.grade}</td>
<td></td>
</tr>
))}
</tbody>
</table>
</div>
<div className="space" />
<button onClick={realizarPedidos} className="crear_estudiante_boton">
Realizar Pedidos
</button>
<div className="space" />
</div>
</div>
);
}
export default ListadoEstudiantes;

i cant do search in react JS and get data from PostgreSQL

index js
const express = require("express");
const app =express();
const cors =require("cors");
const pool = require("./db");
app.use(cors());
app.use(express.json);
app.get("/data", async (req, res) => { //async to make the process fast (await)
try {
const newData= await pool.query( "SELECT * FROM interactions");
//js2xmlparser.parse('newData',newData);
} catch (err) {
console.error(err.message);
}
});
search.js
mport React,{Fragment,useEffect,useState} from "react";
import jsontoxml from "jsontoxml";
//import * as JsonToXML from "js2xmlparser";
const ListInteract =() => {
const[interactions,setinteractions] = useState([])
const getinteractions = async () => {
try {
const response = await fetch ("http://localhost:3000/data")
const data = await response.json();
// const convert= console.log(JsonToXML.parse("data", this.data));
// jsontoxml.escape(data);
console.log(data);
setinteractions(data);
} catch (err) {
console.error(err.message)
}
}
useEffect (() => {
getinteractions();
},[]); //[] it to do one
return <Fragment>
<label>drugcode</label> <input type="text" class = "mt-5"/>
<label>diseasecode</label> <input type="text"/>
<label>type</label> <input type="text"/> <button class="btn btn-success">Search </button>
<table class="table table-hover mt-5 text-center">
<thead>
<tr>
<th>ID</th>
<th>description</th>
<th>drugcode</th>
<th>deasasecode</th>
<th>type</th>
</tr>
</thead>
<tbody>
{interactions.map(interact => (
<tr key={interact.id}>
<td>{interact.id} </td>
<td>{interact.decription} </td>
<td>{interact.drugcode} </td>
<td>{interact.diseasecode} </td>
<td>{interact.type} </td>
</tr>
)
)}
</tbody>
</table>
</Fragment>
};
export default ListInteract;
i have 3 text field i put data in it drugcode&diseasecode&type *
my goal when I put the three data in text select all and show it in the table *
ex: drug code =222, diseasecode=333, type=1 in table i want all data in it
id =1 description="good" drugcode=222,diseasecode=333 type=1
after i put the data in text i have button search when i click in it
it will show me all data in the table *
*** thank you all ***

Redux reducer: not sure if I am setting items (new or old) to state correctly

I am creating a website for my end term project at school.
So far I have two views I am trying to render. Both returning a collection from my express/api endpoint. One behaves sort of correctly and the other completely borks.
I believe my problem is the way I am creating new state in the reducer and knowing when a dumb component has access to props. But before we get to that, here are the errors.
On the not so borky page:
invariant.js:42 Uncaught (in promise) Error: setState(...): takes an
object of state variables to update or a function which returns an
object of state variables.
And,
Warning: SingleCountry.state: must be set to an object or null
On the second page:
Uncaught (in promise) Error: setState(...): takes an object of state
variables to update or a function which returns an object of state
variables.
Also I'm getting:
Error: Can't set headers after they are sent.
This happens when I try to navigate to a single page/view from my not so borky first page. That shouldn't be happening as I believe my route is pretty much locked down.
This is from routes/api, I am using Express...
router
.route('/')
.get((req, res, next) => {
return Country.findAll({ include: [Aircraft] })
.then(countries => {
countries.filter(country => {
return country.aircrafts.length > 0;
});
})
.then(countries => res.json(countries))
.catch(next);
})
.post((req, res, next) => {
if (req.body) {
Country.create(req.body)
.then(country => {
country.save();
res.json(country);
})
.catch(next);
}
});
This is the aforementioned reducer:
import { combineReducers } from 'redux';
import axios from 'axios';
const initialState = {
topFiveCountries: [],
oneCountry: {},
countries: [],
};
// ACTION TYPES
const GET_TOP_COUNTRIES_BY_GFI = 'GET_TOP_COUNTRIES_BY_GFI';
const GET_COUNTRY = 'GET_COUNTRY';
const GET_COUNTRIES = 'GET_COUNTRIES';
// ACTION CREATORS
export function getTopFiveCountriesByGFI(topFiveCountries) {
const action = {
type: GET_TOP_COUNTRIES_BY_GFI,
topFiveCountries,
};
return action;
}
export function getCountry(country) {
const action = {
type: GET_COUNTRY,
country,
};
return action;
}
export function getCountries(countries) {
const action = {
type: GET_COUNTRIES,
countries,
};
return action;
}
//THUNK CREATORS
export function fetchTopFiveCountriesByGFI() {
return function thunk(dispatch) {
return axios
.get('/api/countries/top-five-countries')
.then(res => res.data)
.then(countries => {
const action = getTopFiveCountriesByGFI(countries);
dispatch(action);
});
};
}
export function fetchCountry(countryId) {
return function thunk(dispatch) {
return axios
.get('/api/countries/' + `${countryId}`)
.then(res => res.data)
.then(country => {
const action = getCountry(country);
dispatch(action);
});
};
}
export function fetchCountries() {
return function thunk(dispatch) {
return axios
.get('/api/countries')
.then(res => res.data)
.then(countries => {
const action = getCountries(countries);
dispatch(action);
});
};
}
// REDUCER
const rootReducer = function(state = initialState, action) {
switch (action.type) {
case GET_COUNTRIES:
return action.countries;
// return { ...state, countries: action.countries };
// return (state.countries = state.countries.concat(action.countries));
case GET_TOP_COUNTRIES_BY_GFI:
// return action.topFiveCountries;
return { ...state, topFiveCountries: action.topFiveCountries };
case GET_COUNTRY:
return action.country;
// return { ...state, oneCountry: action.country };
default:
return state;
}
};
export default rootReducer;
The funny thing the way I am going about them are not too dissimilar for each other. They are both dumb components:
First the TopFiveCountriesByGFI:
import React from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
export default function TopFiveCountriesByGFI(props) {
const topFiveCountries = props.topFiveCountries;
const flagStyle = {
height: '50px',
width: '100px',
};
return (
<div className="row">
<div className="twelve columns">
<h2> - Top Five Coutries By GFI -</h2>
<table className="u-full-width">
<thead>
<tr>
<th>Name</th>
<th>GFI</th>
<th>Flag </th>
</tr>
</thead>
{topFiveCountries.map(function(country) {
return (
<tbody key={country.id}>
<tr>
<td>
<Link className="country-page-link" to={`/countries/${country.id}`}>
{country.name}
</Link>
</td>
<td>{country.GFI}</td>
<td>
<img style={flagStyle} src={country.flagUrl} />
</td>
</tr>
</tbody>
);
})}
</table>
</div>
</div>
);
}
Second is the Countries view:
import React from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
export default function Countries(props) {
console.log('props', props.countries);
const countries = props.countries;
const flagStyle = {
height: '50px',
width: '100px',
};
return (
<div className="row">
<div className="twelve columns">
<h2> - Countries -</h2>
<table className="u-full-width">
<thead>
<tr>
<th>Name</th>
<th>GFI</th>
<th>Flag </th>
</tr>
</thead>
{countries &&
countries.map(function(country) {
return (
<tbody key={country.id}>
<tr>
<td>
<Link className="country-page-link" to={`/countries/${country.id}`}>
{country.name}
</Link>
</td>
<td>{country.GFI}</td>
<td>
<img style={flagStyle} src={country.flagUrl} />
</td>
</tr>
</tbody>
);
})}
{/* {countries ? (
countries.map(country => {
return (
<tbody key={country.id}>
<tr>
<td>
<Link className="country-page-link" to={`/countries/${country.id}`}>
{country.name}
</Link>
</td>
<td>{country.GFI}</td>
<td>
<img style={flagStyle} src={country.flagUrl} />
</td>
</tr>
</tbody>
);
})
) : (
<div>Sorry no content yet!</div>
)}*/}
</table>
</div>
</div>
);
}
Any help will be appreciated!
UPDATE
As Deryck pointed out one of my endpoints wasn't returning anything but I am still getting this error:
SingleCountry.state: must be set to an object or null
You return an undefined value inside your promise's then, which tries to go into res.json(countries) which then fails/throws. It gets back to the page as undefined still, resulting in your setState() issue since there's nothing there.
So, inside of this block
return Country.findAll({ include: [Aircraft] })
.then(countries => {
countries.filter(country => { // <<-------- add `return` before countries
return country.aircrafts.length > 0;
});
})
.then(countries => res.json(countries))

Categories

Resources