I am trying to make a clinic locator that when you put where you are, you get as a result the nearby clinics, I can not enter data in the imput, not even let me write and I can not find the problem.
import React, { useState, useEffect } from 'react'
import { getClinic } from '../../api/drupalAPI'
import {Clinic} from '#icofcv/common';
import Spinner from '../spinner/Spinner';
interface Props {
showModalLocator: boolean,
closeModalLocator: () => void
}
export const ClinicLocator: React.FC<Props> = ({ children, showModalLocator, closeModalLocator }) => {
const [clinicList, setClinicList] = useState<Clinic[]>([]);
const [clinicListFiltered, setClinicListFiltered] = useState<Clinic[]>([]);
const [searchClinic, setSearchClinic] = useState("");
const handleChange= (e) => async () => {
getClinic().then((response)=>{
console.log(response)
setClinicList(response);
setClinicListFiltered(response)
}).catch ( (error) => {
console.error(error);
throw error;
});
setSearchClinic(e.target.value);
filter(e.target.value);
}
const filter=(termSearch)=>{
const resultSearch= clinicList.filter((element)=>{
if(element.address?.toString().toLowerCase().includes(termSearch.toLowerCase())
|| element.province?.toString().toLowerCase().includes(termSearch.toLowerCase())
|| element.town?.toString().toLowerCase().includes(termSearch.toLowerCase())
){
return element;
}
});
setClinicListFiltered(resultSearch);
}
return (
<>
<div>
{showModalLocator ? (
<>
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
<div className="relative p-2 w-full max-w-3xl h-full md:h-auto">
{/*content*/}
<div className="relative bg-white rounded-lg shadow">
{/*header*/}
<div className="flex justify-between items-start px-4 py-3 rounded-t border-b">
<h3 className="text-lg font-medium">Localizador de clinicas</h3>
<button className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center" onClick={closeModalLocator}>
<svg aria-hidden="true" className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
</svg>
</button>
</div>
{/*body*/}
<div className="relative px-3 py-3 flex-auto overflow-auto modal-body">
<h2 className="text-sm font-medium mb-2">¿Dónde te encuentras?</h2>
<input
value={searchClinic}
onChange={handleChange}
type="search"
className="w-100 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2"
placeholder="Introduce una ubicación"
/>
<div className="py-3 border-b flex flex-col md:flex-row items-start md:items-center md:justify-between justify-start gap-2">
<div className="flex items-center">
<label className="inline-flex relative items-center mr-5 cursor-pointer">
<input type="checkbox" className="sr-only peer" checked/>
<div className="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-teeal-600
peer-checked:after:translate-x-full peer-checked:after:border-white after:content-['']
after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-teal-600"></div>
<span className="ml-2 text-xs font-medium text-gray-900">Centro privado</span>
</label>
</div>
<div className="flex items-center">
<label className="inline-flex relative items-center mr-5 cursor-pointer">
<input type="checkbox" className="sr-only peer" readOnly/>
<div className="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-teeal-600
peer-checked:after:translate-x-full peer-checked:after:border-white after:content-['']
after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-teal-600"></div>
<span className="ml-2 text-xs font-medium text-gray-900">con Mútuas</span>
</label>
</div>
<div className="flex items-center">
<label className="inline-flex relative items-center mr-5 cursor-pointer">
<input type="checkbox" className="sr-only peer" readOnly/>
<div className="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-teeal-600
peer-checked:after:translate-x-full peer-checked:after:border-white after:content-['']
after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-teal-600"></div>
<span className="ml-2 text-xs font-medium text-gray-900">con Compañías de Salud</span>
</label>
</div>
</div>
<div>
<h2 className="text-sm font-medium my-3">Resultados</h2>
<div className="w-100">
<iframe className="w-100" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2664.3238269926374!2d-0.3805919350162851!3d39.46959682083709!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0xd604f4bee0957f3%3A0x6686ff7d230b3965!2zQy4gZGUgU2FudC
BWaWNlbnQgTcOgcnRpciwgNjEsIHBpc28gMsK6LCBwdGEgMsKqLCA0NjAwMiBWYWzDqG5jaWEsIEVzcGHDsWE!5e0!3m2!1ses!2sus!4v1662388390673!5m2!1ses!2sus" loading="lazy"></iframe>
</div>
<div className="md:mt-4 overflow-auto relative py-2">
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
<div className="card bg-white px-2 py-3 h-36 md:h-32">
{!clinicListFiltered ? <Spinner /> :
clinicListFiltered.map((clinic) => (
<button key={clinic.id} type="button" className="text-left">
<div className="flex items-center gap-2 md:gap-4 md:gap-4">
<img className="h-24 w-2/5 min-w-40 object-cover object-center rounded-lg" src="../carousel-1.svg" alt="#"/>
<div className="w-3/5">
<div className="text-md font-medium leading-5 clinic-title uppercase">{clinic.title}</div>
<div className="flex items-center gap-2">
<div className="text-neutral-500 text-sm">{clinic.propsPhone}</div>
<div className="text-neutral-500 text-sm">{clinic.mobile}</div>
</div>
<div className="text-teal-600 text-sm underline clinic-mail">{clinic.email}</div>
<div className="text-neutral-500 text-sm">{clinic.registry}</div>
</div>
</div>
</button>
))
}
</div>
{/* <div className="card bg-white px-2 py-3 h-36 md:h-32">
<button type="button" className="text-left">
<div className="flex items-center gap-2 md:gap-4 md:gap-4">
<img className="h-24 w-2/5 min-w-40 object-cover object-center rounded-lg" src="../carousel-1.svg" alt="#"/>
<div className="w-3/5">
<div className="text-md font-medium leading-5 clinic-title uppercase">AlamedaVLC</div>
<div className="flex items-center gap-2">
<div className="text-neutral-500 text-sm">963255652</div>
<div className="text-neutral-500 text-sm">963255652</div>
</div>
<div className="text-teal-600 text-sm underline clinic-mail">fisioalamedavlc#gmail.com</div>
<div className="text-neutral-500 text-sm">9947</div>
</div>
</div>
</button>
</div> */}
</div>
</div>
</div>
</div>
{/*footer*/}
<div className="flex items-center justify-end px-4 py-2 border-t border-solid border-slate-200 rounded-b gap-2">
<button className="btn text-black text-sm background-transparent px-8 outline-none focus:outline-none focus:ring-teal-600 focus:border-teal-600" type="button" onClick={closeModalLocator}>Cancelar</button>
<button className="btn bg-teal-600 hover:bg-teal-700 text-white text-sm active:bg-teal-700 px-8 outline-none focus:outline-none" type="button" onClick={closeModalLocator}>Buscar</button>
</div>
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</div>
</>
)
}
Try to change the line
const handleChange= (e) => async () => {
to
const handleChange = (e) => {
You're currently returning a function, which means that it doesn't get called. There is also no need for async as you don't have any await in the function.
handleChange returns a function which is never executed; remove the currying as it is not needed:
const handleChange= (e) => {
getClinic().then((response)=>{
console.log(response)
setClinicList(response);
setClinicListFiltered(response)
}).catch ( (error) => {
console.error(error);
throw error;
});
setSearchClinic(e.target.value);
filter(e.target.value);
}
The reason you cannot input anything is that React treats the input field as controlled component, which means that it itself won't take care of updating the fields value since you passed an initial value (of ""). With controlled components, you as the developer are required to handle the state outside of the input field, i.e. update the value attribute of the input component. Since that failed due to the mistake outlined above, the value of the input field remains fixed at "", thus not allowing you to type in the field.
Further reading:
Controlled components
Uncontrolled components
Related
I am developing a search bar that performs the search by calling an api, I encounter an error: Parsing error: Missing semicolon. The error comes from this part of the code:
const form = event.target as HTMLFormElement;
specifically between the event.target and the as. Could someone explain me the reason of this error and how to solve it?
import React, { FormEvent, useState, useEffect } from "react";
import Select, { SingleValue } from "react-select";
import { getCollegiate } from "../../api/drupalAPI";
import { Collegiate } from "#icofcv/common";
import Loader from "../spinner/Loader";
interface Props {
showModal: boolean;
closeModal: () => void;
}
export const ModalFilterCollegiate: React.FC<Props> = ({
children,
showModal,
closeModal,
}) => {
const [collegiateList, setCollegiateList] = useState<Collegiate[]>([]);
const [collegiateSearch, setCollegiateSearch] = useState("");
const searchForCollegiates = async (query: String): Promise<Collegiate[]> => {
const result = await fetch(`/collegiate?filter=${query}`);
return (await result.json()).results;
};
useEffect(() => {
(async () => {
const query = encodeURIComponent(collegiateSearch);
const response = await searchForCollegiates(query);
setCollegiateList(response);
})();
}, [collegiateSearch]);
const search = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const form = event.target as HTMLFormElement;
const input = form.querySelector("#searchText") as HTMLInputElement;
setCollegiateSearch(input.value);
input.value = "";
};
return (
<>
<div>
{showModal ? (
<>
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
<div className="relative p-2 w-full max-w-2xl h-full md:h-auto">
{/*content*/}
<div className="relative bg-white rounded-lg shadow">
{/*header*/}
<div className="flex justify-between items-start px-4 py-3 rounded-t border-b">
<h3 className="text-lg font-medium">Buscar Colegiado</h3>
<button
className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center"
onClick={closeModal}
>
<svg
aria-hidden="true"
className="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd"
></path>
</svg>
</button>
</div>
{/*body*/}
<div className="relative px-3 py-3 flex-auto overflow-auto modal-body">
<form
className="searchForm"
onSubmit={(event) => search(event)}
>
<div className="grid md:grid-cols-2 md:gap-4">
<div className="relative z-0 w-full group my-2">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Número colegiado
</label>
<input
name=""
type="text"
id=""
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
/>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
</div>
<div className="grid md:grid-cols-2 md:gap-4">
<div className="relative z-0 w-full group my-2">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Nombre
</label>
<input
name=""
type="text"
id="searchText"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
/>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
<div className="relative z-0 w-full group my-2">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Apellidos
</label>
<input
name=""
type="text"
id=""
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
/>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
</div>
<div className="grid md:grid-cols-2 md:gap-4">
<div className="relative z-0 w-full group">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Provincia
</label>
<select className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
<option>Cualquier Provincia</option>
</select>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
<div className="relative z-0 w-full group">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Tipo
</label>
<select className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
<option>Seleccionar tipo</option>
<option>Ejercientes</option>
<option>No ejercientes</option>
<option>Honorarios</option>
<option>Colegiados de honor</option>
</select>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-slate-200 rounded-b gap-2">
<button
className="btn text-black text-sm background-transparent px-8 outline-none focus:outline-none focus:ring-teal-600 focus:border-teal-600"
type="button"
onClick={closeModal}
>
Cancelar
</button>
<button
className="btn bg-teal-600 hover:bg-teal-700 text-white text-sm active:bg-teal-700 px-8 outline-none focus:outline-none"
type="button"
>
Buscar
</button>
</div>
</form>
</div>
{/*footer*/}
{collegiateList.map((collegiate) => (
<tr key={collegiate.id} className="bg-white border-b">
<td className="py-2 px-6">{collegiate.color}</td>
<td className="py-2 px-6">{collegiate.collegiate}</td>
<td className="py-2 px-6">{collegiate.firstname}</td>
<td className="py-2 px-6">{collegiate.lastname}</td>
<td className="py-2 px-6">{collegiate.provincia}</td>
</tr>
))}
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</div>
</>
);
};
I have mapped a list of responses from my backend mongodb to my frontend. For each response, I have also added a button. I want to add an voteResponse function for my vote button. How can I continue to have access to my {response.respondee} and {response.response} in my voteResponse function?
{responses.map((response) => (
<div
key={response._id}
className='py-8 px-12 mb-12 bg-gray-50 border-b border-gray-100 transform transition duration-300 ease-in-out hover:-translate-y-2'
>
<NextLink href={`/responses/${response.response}`} passHref>
<div>
<div className='inline-block text-gray-900 mb-4'></div>
<h3 className='text-lg leading-normal mb-2 font-semibold text-black'>
{response.response}
</h3>
<p className='text-gray-500'>
{response.respondee.slice(0, 5)}...
{response.respondee.slice(38)}
</p>
</div>
</NextLink>
<div>
<button
type='submit'
className='inline-flex justify-center mt-3 py-1 px-3 border border-transparent shadow text-base font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none'
onClick={voteResponse}
>
Vote
</button>
</div>
</div>
))}
You can do this by 2 ways. First is by making a separate component which is being rendered in map function and pass response in it through props then each component will have access to it's response.response and response.respondee.
funtion Response({response}){
const voteResponse = () =>{
console.log(response.response, response.respondee)
}
return(
<div key={response._id} className='py-8 px-12 mb-12 bg-gray-50 border-b border-gray-100 transform transition duration-300 ease-in-out hover:-translate-y-2'>
<NextLink href={`/responses/${response.response}`} passHref>
<div>
<div className='inline-block text-gray-900 mb-4'></div>
<h3 className='text-lg leading-normal mb-2 font-semibold text-black'>
{response.response}
</h3>
<p className='text-gray-500'>
{response.respondee.slice(0, 5)}... {response.respondee.slice(38)}
</p>
</div>
</NextLink>
<div>
<button type='submit' className='inline-flex justify-center mt-3 py-1 px-3 border border-transparent shadow text-base font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none' onClick={voteResponse}>
Vote
</button>
</div>
</div>
)
}
//use it like this
{responses.map((response) => (
<Response response={response} key={response._id} />
))}
Second way to pass the index in voteResponse function and then through that index you can access the those variables like responses[index].response and responses[index].respondee.
{responses.map((response, index) => (
<div key={response._id} className='py-8 px-12 mb-12 bg-gray-50 border-b border-gray-100 transform transition duration-300 ease-in-out hover:-translate-y-2'>
<NextLink href={`/responses/${response.response}`} passHref>
<div>
<div className='inline-block text-gray-900 mb-4'></div>
<h3 className='text-lg leading-normal mb-2 font-semibold text-black'>
{response.response}
</h3>
<p className='text-gray-500'>
{response.respondee.slice(0, 5)}... {response.respondee.slice(38)}
</p>
</div>
</NextLink>
<div>
<button type='submit' className='inline-flex justify-center mt-3 py-1 px-3 border border-transparent shadow text-base font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none' onClick={voteResponse}>
Vote
</button>
</div>
</div>
))}
Pass value to onClick prop: onClick={() => voteResponse(response)} and use it as parameter of voteResponse function:
const voteResponse = (res) => {
console.log("response.respondee is: ", res.respondee) //<=== response.respondee value is res.respondee value
console.log("response.response is: ", res.response)
}
{responses.map((response) => (
<div
key={response._id}
className='py-8 px-12 mb-12 bg-gray-50 border-b border-gray-100 transform transition duration-300 ease-in-out hover:-translate-y-2'
>
<NextLink href={`/responses/${response.response}`} passHref>
<div>
<div className='inline-block text-gray-900 mb-4'></div>
<h3 className='text-lg leading-normal mb-2 font-semibold text-black'>
{response.response}
</h3>
<p className='text-gray-500'>
{response.respondee.slice(0, 5)}...
{response.respondee.slice(38)}
</p>
</div>
</NextLink>
<div>
<button
type='submit'
className='inline-flex justify-center mt-3 py-1 px-3 border border-transparent shadow text-base font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none'
onClick={() => voteResponse(response)
>
Vote
</button>
</div>
</div>
))}
I found a great accordion solution on the internet and wanted to try it. The difference between the example and my code is I used max-height-fit instead of max-height-20.
Here is my code:
<div className="relative overflow-hidden">
<input
type="checkbox"
className="peer absolute top-0 inset-x-0 w-full h-12 opacity-0 z-10 cursor-pointer"
/>
<div className="bg-gray-500 h-12 w-full pl-5 flex items-center">
<h1 className="text-lg font-semibold text-white">Offline</h1>
</div>
<div className="absolute top-3 right-3 text-white transition-trasnform duration-500 rotate-0 peer-checked:rotate-180">
<FontAwesomeIcon icon={faChevronDown} />
</div>
<div className="overflow-auto transition-all duration-500 max-h-0 peer-checked:max-h-fit">
{players
.filter((p: any) => p.name.toLowerCase().includes(search))
.map((player: any) => {
return (
<div className="flex py-4 border-b-2 border-gray-700 hover:bg-gray-800/90 last:border-b-0">
<div className="ml-5 -mt-1 bg-gray-700 w-8 h-8 text-center leading-8 rounded-full">
{player.ID}
</div>
<div className="ml-5 flex grow">
<div className="w-full">
{player.name} ({player.level})
</div>
<div>
{player.isAdmin && (
<FontAwesomeIcon className="mr-5" icon={faCrown} />
)}
</div>
</div>
</div>
);
})}
</div>
</div>
I've been starring at my code, but I can't see where the key is missing. That is my error:
Warning: Each child in a list should have a unique "key" prop.
Check the render method of Card. It was passed a child from ContractInfo.
Here is Card:
export const Card = ({ selected, onChange, title, price, frequency, description, feature, cta }) => {
const mode = selected ? 'border-yellow-500 border-4' : 'border-gray-200'
return (
<div
className={["relative p-8 bg-white border-gray-200 rounded-2xl shadow-sm flex flex-col border-2", mode].join(' ')}
style={{cursor:'pointer'}}
selected={selected}
onClick={onChange}
>
<div className="flex-1 ">
<h3 className="text-xl font-semibold text-gray-900">{title}</h3>
<p className="mt-4 flex items-baseline text-gray-900">
<span className="text-5xl font-extrabold tracking-tight">€{price}</span>
<span className="ml-1 text-xl font-semibold">{frequency}</span>
</p>
<p className="mt-6 text-gray-500">{description}</p>
{/* Feature list */}
{feature}
</div>
<div className= 'bg-yellow-500 text-white hover:bg-yellow-600 mt-8 block w-full py-3 px-6 border border-transparent rounded-md text-center font-medium'>
{cta}
</div>
</div>
);
}
And here is the bit in ContractInfo:
return (
<div className={formStep === 0 ? 'block' : 'hidden'}>
<div className="bg-white py-16 px-4 overflow-hidden sm:px-6 lg:px-8">
<div className="relative max-w-xl mx-auto">
<div className="text-center">
<h2 className="text-3xl font-extrabold tracking-tight text-gray-600 sm:text-4xl">Welcher Vertrag passt zu dir?</h2>
</div>
</div>
<div className="max-w-7xl mx-auto py-4 px-4 bg-white sm:px-6 lg:px-8">
<div className="mt space-y-12 lg:space-y-0 lg:grid lg:grid-cols-3 lg:gap-x-8">
{contracts.map((contract, index) => (
<Card
key={contract.id}
title={contract.title}
price={contract.price}
frequency={contract.frequency}
description={contract.description}
feature={ contract.features.map((feature, index) =>
<ul role="list" className="mt-6 space-y-6">
<li className="flex" key={feature.id} >
{console.log(feature.id)}
<CheckIcon className="flex-shrink-0 w-6 h-6 text-yellow-500" aria-hidden="true" />
{feature.name}
</li>
</ul> )}
cta={contract.cta}
selected={isSelected === index}
onChange={() => setisSelected(index)}
/>
))}
{/* {console.log(contracts?.[isSelected])} */}
</div>
</div>
<div className="mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-center">
<div className="rounded-md shadow">
<a role="button" tabIndex={0}
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-gray-200 hover:bg-gray-200 focus:outline-none md:py-4 md:text-lg md:px-10 cursor-not-allowed"
>
Zurück
</a>
</div>
<div className="mt-3 sm:mt-0 sm:ml-3">
<a
//onClick={nextQuizStep}
onClick={() => nextFormStep(contracts?.[isSelected]) }
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-500 hover:bg-yallow-600 md:py-4 md:text-lg md:px-10"
>
Weiter
</a>
</div>
</div>
</div>
</div>
);
}
Keys are both present for features list and for cards. Where is the problem?
Key Error is caused by feature rendering in Card component
This is cause the keys are not present among sibling elements of the for loop in feature creation, so to correct this You set key for parent ul in
feature={ contract.features.map((feature, index) =>
<ul role="list" className="mt-6 space-y-6">
<li className="flex" key={feature.id} >
{console.log(feature.id)}
<CheckIcon className="flex-shrink-0 w-6 h-6 text-yellow-500" aria-hidden="true" />
{feature.name}
</li>
</ul> )}
so it becomes
feature={ contract.features.map((feature, index) =>
<ul role="list" className="mt-6 space-y-6" key={'feature-'+feature.id}>
<li className="flex" >
{console.log(feature.id)}
<CheckIcon className="flex-shrink-0 w-6 h-6 text-yellow-500" aria-hidden="true" />
{feature.name}
</li>
</ul> )}
I am trying to change the element through get element by id and it is throwing:
TypeError: Cannot set property 'innerHTML' of null.
Is this how we pass parameters or we have other approaches?
My code:
const [isOpen, setIsOpen] = useState(false);
const togglePopup = (name='shraweg') => {
setIsOpen(!isOpen);
let inner = document.getElementById(name)
inner.innerHTML=(
<>
{
isOpen &&
<div className="popup-box">
<div className="flex flex-col box gap-1">
<div>
<p className="font-meduim text-lg">Are you sure you want to kick {" "+player.username+" "} ?</p>
</div>
<div className="flex flex-row gap-14 items-center justify-center">
<button type="submit" onClick={handleKick} value={player._id} className="border font-semibold text-lg border-red-300 rounded-xl hover:bg-red-600 px-6">
Yes
</button>
<button onClick={togglePopup} className="border font-semibold text-lg border-yellow-300 rounded-xl hover:bg-yellow-500 px-6">
No
</button>
</div>
</div>
</div>
}
</>
)
}
Here I've written a function to change the elements inside my html tag:
return (
<legend className="text-xl mb-5 border-yellow-500 border-l-4 pl-2 mt-10">Team Members</legend>
<div className="flex gap-5 flex-col w-full mb-4">
{props.team.players.map((player, key) => (
<div key={key} className="">
<label htmlFor="csgoign" className="flex bg-gray-50 hover:bg-gray-200 p-3 rounded-xl w-full items-center justify-between">
<div className="flex font-medium gap-3">
<img src={"https://robohash.org/"+player.username+"?set=set5"} className="w-12 h-12 rounded-3xl bg-blue-100"/>
<div className="ml-3">
<a href={"http://localhost:3000/userprofile/"+player._id} className="text-2xl w-auto font-semibold hover:text-yellow-600">
{player.username}
</a>
<p className="text-sm font-normal text-gray-700 font-paragraph">
Member since : {player.join_date}
</p>
</div>
</div>
{props.user._id == props.team.team_cap && (
<>
{!(player.username == props.user.username) && (
<div id={player.username}>
{
!isOpen &&
<button type="button" onClick={togglePopup(player.username)} className="border font-semibold text-xl border-red-300 rounded-xl hover:bg-red-600 px-7 py-2">
Kick
</button>
}
</div>
)}
</>
)}
</label>
</div>
))}
</div>
)
onClick={togglePopup(player.username)}
change to
onClick={()=>togglePopup(player.username)}
onClick property should be a function