Cannot read properties of undefined (reading 'label') - material-ui

I am trying to implement Autocomplete using materialUI and nextJs. I encountered this error whenever I start the search.
My code is like this
client:
import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'
import React, {useState} from 'react'
import TextField from "#mui/material/TextField"
import Autocomplete from "#mui/material/Autocomplete"
import axios from "axios"
const getString = async (str) =>{
try{
// let searchableString = str.replace(/,/g, "")
let url = "http://localhost:4000/searchpop?search=" + str;
let { data } = await axios.get(url)
return data
} catch (error){
console.log(error);
}
}
export default function Home() {
const [searchOption, setOption] = useState([]);
searchOption.map((obj)=>{
console.log(obj.population_mesh.cui_str);
})
const onChangeOne = async (e) =>{
if(e.target.value) {
let data = await getString(e.target.value)
setOption(data);
}
}
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div style={{marginTop: 50}}>
<Autocomplete
freeSolo
filterOptions={(x)=> x}
onChange={(e)=> console.log(e)}
options= {searchOption ? searchOption.map((obj)=> obj.population_mesh.cui_str): []}
// options = {hello}
renderInput={(params)=>(
<TextField
{...params}
label="Search String"
onChange={(e) => onChangeOne(e)}
/>
)}
/>
</div>
</div>
)
}
I am very new to these technologies. So please help me in resolving this issue.
I also dont understand below. here is population_mesh is the field and cui_str is is subfield in the data base which i want to print for autocomplete
options= {searchOption ? searchOption.map((obj)=> obj.population_mesh.cui_str): []}

Related

Next JS 13 data send from client component to server side component but show Not found

JS 13 and inside my ReadMoreButton client component i push my article data using useRouter hook of NEXT.
Not i can not use useRouter hook inside NEXT.JS server component so here i fetch searchParams and fetch that data.
here problem is before rendering i am checking if searchParams are defined or not not if i check in development everything work fine it render data but in production mode it show page not found error even if data is correctly send.
when i run next build it give me following output Output
and i am running side in production mode using next start and it show page not found when i do /article?serchParamsData.
You can check my whole code here : https://github.com/ssiwach8888/Next.JS-News-App
i also deploy production build on Vercel but it also show same error.
I am using NEXT.JS 13 with typescript
# ReadMoreButton.tsx "First Control goes here."
"use client";
type Props = {
article: NewsData;
};
import { useRouter } from "next/navigation";
//For navigate to SSC
const ReadMoreButton = ({ article }: Props) => {
const router = useRouter();
const handleClick = () => {
const queryString = Object.entries(article)
.map(([key, value]) => `${key}=${value}`)
.join("&");
const url = `/article?${queryString}`;
router.push(url);
};
return (
<button
className="bg-orange-400 h-10 rounded-b-lg dark:text-gray-900 hover:bg-orange-500"
onClick={handleClick}
>
Read More
</button>
);
};
export default ReadMoreButton;
# Article.tsx "Then we navigate to this page."
type Props = {
searchParams?: NewsData;
};
import { notFound } from "next/navigation";
import LiveTimestamp from "../Components/LiveTimestamp";
import Link from "next/link";
const ArticlePage = ({ searchParams }: Props) => {
if (
(searchParams && Object.entries(searchParams).length === 0) ||
!searchParams
) {
return notFound();
}
const article: NewsData = searchParams;
return (
<article className="mt-6">
<section className="flex flex-col lg:flex-row pb-24 px-0 lg:px-10">
<img
src={article.image === "null" ? "/no-image.jpeg" : article.image}
alt={article.title}
className="h-50 max-w-md mx-auto md:max-w-lg lg:max-w-xl object-contain rounded-lg shadow-md"
/>
<div className="px-8">
<Link legacyBehavior href={article.url || ""}>
<a target="_blank">
<h1 className="headerTitle hover:underline cursor-pointer px-0 pb-2">
{article.title}
</h1>
</a>
</Link>
<div className="flex divide-x-2 space-x-4">
<h2 className="font-bold">
By: {article.author !== "null" ? article.author : "Unknown"}
</h2>
<h2 className="font-bold pl-4">Source: {article.source}</h2>
<p className="pl-4">
<LiveTimestamp
time={
article.published_at === "null" ? "" : article.published_at
}
/>
</p>
</div>
<p className="pt-4 text-lg">{article.description}</p>
</div>
</section>
</article>
);
};
export default ArticlePage;
You just need to put the article page in [bracket] to make it dynamic so next js can fetch all pages otherwise it would display blank----
change article folder to [article]
more reference https://nextjs.org/docs/routing/dynamic-routes

Accessing Parameters in SolidJS Router

I am trying to rewrite a project I made in React in Solid. I am trying to use the Solid Router as the documentation advises.
Here are my components so far.
index.js
import { render } from 'solid-js/web'
import { Router } from '#solidjs/router'
import './index.css'
import App from './App'
render(
() => (
<Router>
<App />
</Router>
),
document.getElementById('root')
)
App.jsx
import Header from './components/Header'
import styles from './App.module.css'
import Navbar from './components/Navbar'
import Topics from './components/Topics'
function App() {
return (
<div className={styles.container}>
<Header />
<Navbar />
<Routes>
<Route path="/" element={<Articles />} />
<Route path="/:topic" component={<Topics />} />
</Routes>
</div>
)
}
export default App
Navbar.jsx
import { NavLink } from '#solidjs/router'
import { getTopics } from '../utils/api'
const Navbar = () => {
const [topics, setTopics] = createSignal([])
onMount(() => {
getTopics().then(({ topics }) => {
setTopics(topics)
})
})
return (
<nav>
<ul>
<For each={topics()}>
{topic => (
<li>
<NavLink href={`/${topic.slug}`}>{topic.slug}</NavLink>
</li>
)}
</For>
</ul>
</nav>
)
}
export default Navbar
The problem I think seems to be in the component below
Topics.jsx
import { useParams } from '#solidjs/router'
import { createSignal, For, onMount, createResource } from 'solid-js'
import { getTopicArticles } from '../utils/api'
const Topics = () => {
const { topic } = useParams()
console.log(topic)
return (
<div>
<h1>{topic}</h1>
</div>
)
}
export default Topics
The params seem to be undefined no matter what. I understand that Solid router is not exactly the same as React-Router but for this simple example I can't see where I am going wrong.
The desired outcome is to be able to click on the NavLink in the Navbar.jsx component and that routes to the desired path, for example http://localhost:3000/cooking and render the topic I need, but the params are always undefined.
This is the result of the api call, api/articles?topic=undefined
The desired result is to attach the param at the end of the api with useParams, just like in my React version
Edit: below is the Topics.jsx component updated to a working version, not sure if it is the best way.
import { useParams } from '#solidjs/router'
import { getTopicArticles } from '../utils/api'
import Article from './Article'
const Topics = () => {
const params = useParams()
const [articles, setArticles] = createSignal([])
const [loading, setLoading] = createSignal(true)
createEffect(() => {
setLoading(true)
getTopicArticles(params.topic).then(({ articles }) => {
setArticles(articles)
setLoading(false)
})
})
return (
<>
{loading() && <div>Loading...</div>}
<h2>{params.topic}</h2>
<For each={articles()}>{article => <Article article={article} />}</For>
</>
)
}
export default Topics
Could be related to the object returned from useParams is being reactive. console.log returns an empty object but destructing outputs the values as expected. That is because of the proxy and totally normal.
Retrieves a reactive, store-like object containing the current route path parameters as defined in the Route.
https://github.com/solidjs/solid-router#useparams
Also regular query parameters like ?id=1&name=John does not work with useParams, for those use useSearchParams.
import { render } from "solid-js/web";
import {
Router,
useParams,
useSearchParams,
Route,
Routes,
Link
} from "#solidjs/router";
const Home = () => {
const [params, setParams] = useSearchParams();
console.log({ ...params });
return <div>Home</div>;
};
const Blog = () => {
const params = useParams();
console.log({ ...params });
return <div>Blog {JSON.stringify(params)}</div>;
};
const App = () => {
return (
<Router>
<ul>
<li>
<Link href="/?id=1&name=john">Home</Link>
</li>
<li>
<Link href="/blog/js/1">Blog</Link>
</li>
</ul>
<Routes>
<Route path="/" component={Home} />
<Route path="/blog/:category/:id" element={Blog} />
</Routes>
</Router>
);
};
render(App, document.getElementById("app")!);
Check https://codesandbox.io/s/solid-router-demo-forked-71ef9x?file=/index.tsx for live demo.
Also, we pass component name to the component prop like so:
<Route path="/" component={Home} />

how to fix connection issue between vercel and mongodb

im having issues with deploying my site using vercel
this is the error:
[GET] /api/menu/menuItems
00:06:56:04
2022-09-06T05:06:56.382Z 315e3b25-b88f-4c8a-8d50-a323d2fd2b26 ERROR MongoParseError: Invalid scheme, expected connection string to start with "mongodb://" or "mongodb+srv://"
at new ConnectionString (/var/task/node_modules/mongodb-connection-string-url/lib/index.js:86:19)
at parseOptions (/var/task/node_modules/mongodb/lib/connection_string.js:213:17)
at new MongoClient (/var/task/node_modules/mongodb/lib/mongo_client.js:62:63)
at Object.9590 (/var/task/.next/server/pages/api/menu/menuItems.js:35:14)
at __webpack_require__ (/var/task/.next/server/webpack-api-runtime.js:25:42)
at __webpack_exec__ (/var/task/.next/server/pages/api/menu/menuItems.js:63:39)
at /var/task/.next/server/pages/api/menu/menuItems.js:64:28
at Object.<anonymous> (/var/task/.next/server/pages/api/menu/menuItems.js:67:3)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
RequestId: 315e3b25-b88f-4c8a-8d50-a323d2fd2b26 Error: Runtime exited with error: exit status 1
Runtime.ExitError
I have the env variable added to my vercel project already the same as the local one but when I deploy my app it'll load the app but none of the data comes through. it seems to not be able to make the api call for some reason I cant figure it out. I even tried adding the env variable with cli and still didn't work
mongodb.js
import { MongoClient } from 'mongodb'
const uri = process.env.MONGODB_URI
const options = {
useUnifiedTopology: true,
useNewUrlParser: true,
}
let client
let clientPromise
if (!process.env.MONGODB_URI) {
throw new Error('Please add your Mongo URI to .env.local')
}
if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options)
clientPromise = client.connect()
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise
/api/menu/menuItems.js
import clientPromise from "../../../mongodb";
export default async function handler(req, res) {
const client = await clientPromise;
const db = client.db("RESTAURANT");
const menu = await db.collection("menuItems").find({}).toArray();
res.json({ status: 200, data: menu });
}
/pages/index.js
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import { useEffect, useState } from 'react'
import mainImg from '../public/burrito.jpg'
import salsaImg from '../public/salsa.jpg'
import inteiorImg from '../public/place.jpg'
import styles from '../styles/Home.module.css'
import {motion} from 'framer-motion'
import Button from '#mui/material/Button'
import Card from '../components/specialsCard'
export default function Home({}) {
const [menuItems, setMenuItems] = useState([]);
console.log(process.env.MONGODB_URI)
useEffect(() => {
(async () => {
const res = await fetch("/api/menu/menuItems");
const menuItems = await res.json();
setMenuItems(menuItems);
})()
}, [])
return (
<div style={{ width: '100%'}}>
<Head>
<title>Mexican restaurant</title>
<meta name='keywords' content='restaurant, mexican, mexican food'/>
</Head>
<div className={styles.header}>
<Image className={styles.img} src={mainImg} layout='fill' alt='mainImage'/>
<motion.div className={styles.overlay} initial='hidden' animate='visible' variants={{
hidden: {
scale: .8,
opacity: 0
},
visible: {
scale: 1,
opacity: 1,
transition: {
delay: .6
}
}
}}>
<h3 style={{fontSize: '60px', margin:'0px',fontFamily: 'Hurricane, cursive'}}>Best Burritos In Town</h3>
<p>burritos only made with organic and fresh ingredients</p>
</motion.div>
</div>
<div className={styles.salsaContainer}>
<div className={styles.salsaContent}>
<p style={{color: '#ff8d66', fontFamily: 'Hurricane, cursive',fontWeight: 'bold'}}>FREE CHIPS AND SALSA WITH EVERY ORDER</p>
<h2 style={{marginTop: '2px'}}>TRY OUR INFAMOULSY SPICY SALSA. NO EXTRA CHARGE</h2>
<p>Made with fresh tomotaos and spicy peppers. This salsa is known to leave customers happy and THIRSTY for more</p>
<Button variant='contained' href='/menu' size='large' style={{backgroundColor: '#FFD966', marginTop: '20px'}}>Order Here</Button>
</div>
<div className={styles.salsaImg}>
<Image src={salsaImg} alt='salsa'/>
</div>
</div>
<div className={styles.subContainer}>
<Image src={inteiorImg} alt='inteior'/>
<div className={styles.interiorContent}>
<h2 style={{fontFamily: 'Hurricane, cursive'}}>19th CENTURY DECOR</h2>
<p>Come eat in and enjoy our welcoming aesthetics inspired by 19th century spanish design.</p>
</div>
</div>
<div className={styles.subSpContainer}>
<h2>popular menu items</h2>
<div className={styles.subSpItems}>
{(menuItems.data || []).map(item => {
if(item.type === 'special'){
return <Card title={item.title}
description={item.description}
imgUrl={item.imgUrl}
id={item._id}
key={item._id}/>
}
})}
<span style={{flexGrow:'2'}}><h2 style={{textAlign:'center'}}>Check these hot items and more!
<br/> <Link href='/menu'><a>See menu here</a></Link></h2></span>
</div>
</div>
</div>
)
}

How to upload a single image file with next.js to mongodb?

When I'm uploading form data to mongodb, in the image section it shows this:
"C:\fakepath\imageName.jpg" with no actual image in it. And when I fetch the data from the database and map them, all the other data like title and body gets shown, but not the image. Because there wasn't any image to begin with. It was just a fake path.
So, how can I upload image file not the path to MongoDB.
I'm using Next.js and the mongodb npm package.
This is the pages/api/new-post.js file:
import { MongoClient } from "mongodb";
export default async function handler(req, res) {
if (req.method === 'POST') {
const data = req.body
const client = await MongoClient.connect('mongodb://localhost:27017/blog-nextjs')
const db = client.db()
const postCollections = db.collection('posts')
const result = await postCollections.insertOne(data)
console.log(result)
client.close()
res.status(201).json({message: 'Post Inserted'})
}
}
The form code I used in pages/new-post.js are:
import { useRef } from "react";
export default function NewPostForm(props) {
const titleInputRef = useRef()
const imageInputRef = useRef()
const bodyInputRef = useRef()
function submitHandler(e) {
e.preventDefault()
const enteredTitle = titleInputRef.current.value
const enteredImage = imageInputRef.current.value
const enteredBody = bodyInputRef.current.value
const postData = {
title: enteredTitle,
image: enteredImage,
body: enteredBody
}
props.onAddPost(postData)
}
return (
<div>
<form onSubmit={submitHandler}>
<div>
<label htmlFor="title">Title</label>
<input
placeholder="Post Title"
required
type="text"
ref={titleInputRef}
/>
</div>
<div>
<label htmlFor="body">Post</label>
<textarea
placeholder="Post Body "
required
ref={bodyInputRef}
></textarea>
</div>
<div>
<label htmlFor="image">Image</label>
<input
type="file"
required
placeholder="Image"
accept="image/png, image/gif, image/jpeg"
// accept="image/*"
ref={imageInputRef}
/>
</div>
<div><button>Post</button></div>
</form>
</div>
);
}
It's a bad approach to load images directly in MongoDb
You should store it to 3d party hostings and save only link(s) to your image.
Check related question

rest call with react + redux

I am learning how to use Redux. I would like to create a simple application with only one button. When the button is clicked I want to do a rest api call and when the response comes back the response content needs to be displayed.
What I would like to do is send a store.dispatch(CardAction.GET_CARDS) message to Redux when user clicks on the button. I do not want to call rest api directly from the button's onClick handler.
When the answer is received I intend to to the same: send an event with store.dispatch(CardAction.UPDATE_UI) and somehow at the background I want to update the Redux's status.
I hope that this concept is align with React + Redux.
I have some JavaScript code done but some part of it are missing. Could you please help me to put parts together?
index.jsp
<!DOCTYPE html>
<%#page session="false"%>
<%#page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<html>
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=UTF-8">
<base href="${pageContext.request.contextPath}/" />
<link rel="icon" type="image/x-icon" href="public/image/favicon.ico">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css">
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
App.js
let store = createStore(reducers);
ReactDom.render(
<Provider store={store}>
<Card/>
</Provider>,
document.getElementById('root')
);
Card.js
export default class Card extends React.Component {
render() {
return (
<div>
...
<Button onClick={() => store.dispatch(CardAction.GET_CARDS)}>rest call</Button>
</div>
)
}
}
ActionType.js
export const GET_CARDS = 'get-cards';
export const UPDATE_UI = 'update-ui';
CardAction.js
export function getCards(param1, param2) {
return createAction(ActionType.GET_CARDS, (param1, param2) => ({ value1, value2 }))
}
export function updateUi() {
return createAction(ActionType.UPDATE_UI)
}
RootReducer.js
export const reducers = (state = {}, action) => {
return action
};
RestClient.js
export default {
cardPost(param1, param2) {
const url = ...;
fetch(url, {
method: 'POST',
credentials: 'include'
})
.then(response => {
if (response.ok) {
console.info('rest response have arrived');
store.dispatch(CardAction.UPDATE_UI)
} else {
console.info('error appeared during calling rest api');
//store.dispatch(CardAction.SHOW_ERROR)
}
})
.catch(function(err) {
console.info(err + ' Url: ' + url)
})
}
}
You should never call store.dispatch() from a component. Instead, you should import a previously built action and let the Redux flow do the remaining stuff. The reducer shouldn't return an action, instead, it should return a new state, without mutating the previous one. I'd suggest you should first compensate some of the comprehensible lack of experience with Redux, and then you can try to follow along with a React-Redux-Rest tutorial like this one: https://medium.com/#rajaraodv/a-guide-for-building-a-react-redux-crud-app-7fe0b8943d0f#.cnat3gbcx
[EDIT]
Here's what I'd do
// component Card.js
import {getCards} from "CardAction";
export default class Card extends React.Component {
render() {
return (
<div>
...
<Button onClick={getCards(param1, param2)}>rest call</Button>
</div>
)
}
}
// action CardAction.js
const receivedCards = (cards) => ({
type: "RECEIVED_CARDS",
cards
})
export function getCards(param1, param2) {
// idk where you're gonna use these params btw
// also please note that fetch() isn't supported by older browsers. Here I'm showing you a simple example with axios, which basically performs the same operation. Feel free to adapt this example code as you want.
return function(dispatch) {
return axios({
url: server + "endpoint",
timeout: 20000,
method: 'get'
})
.then(function(response) {
let cards = response.data;
dispatch(receivedCards(cards));
})
.catch(function(response){
console.log(response.data.error);
})
}
};
// reducer reducer.js
const initialState = {};
export default (state = initialState, action) => {
switch(action.type) {
case "RECEIVED_CARDS":
return Object.assign({},
state,
{cards: action.cards});
default:
return state;
}
}