Ready usePlacesAutocomplete bug with react - google-maps

I'm struggling with usePlacesAutocomplete in a project. In the code, when I first display the component, 'ready' becomes true and I can get my autosuggestions. However, when I validate the first autosuggestion, change pages, and then return to the page to type a second address, 'ready' does not become true. Even if I remove "disabled={!ready}", I can use the input, but the autosuggestion does not work. It only works if I completely reload the page, which is not what I want. Do you have any idea what the problem might be? Thanks in advance.I am using next js.
import React, { useEffect, useState } from "react";
import { useLoadScript } from "#react-google-maps/api";
import { useRouter } from "next/router";
import { useDispatch, useSelector } from "react-redux";
import {
updateAddress,
updateAddressCoordinate,
updateFormAddressStatus,
updateIsReady,
} from "../../../redux/action";
import usePlacesAutocomplete, {
getGeocode,
getLatLng,
} from "use-places-autocomplete";
// Component de form pour entrer une adresse
export default function TestFormAddress(props) {
const router = useRouter();
// Props qui sont passées depuis le parent
const placeholder = props.placeholder;
const color = props.color;
const key = props.key;
// Chargement de la bibliothèque Google Places API
const { isLoaded } = useLoadScript({
googleMapsApiKey: process.env.GOOGLE_API_KEY,
libraries: ["places"],
});
// Si la bibliothèque n'est pas chargée, retourner un message de chargement
if (!isLoaded)
return (
<div
className={
color !== undefined
? "border flex items-center text-purple rounded-lg placeholder:text-slate-400 px-3 w-full h-12 border-" +
color
: "border flex items-center text-purple rounded-lg placeholder:text-slate-400 px-3 w-full h-12 border-purple"
}
>
Loading...
</div>
);
// Sinon retourner le composant Map
return <Map placeholder={placeholder} color={color} />;
}
const Map = (props) => {
// Props qui sont passées depuis le parentx
const placeholder = props.placeholder;
const color = props.color;
// Utilisation du hook useRouter pour récupérer l'URL courante
const router = useRouter();
const currentUrl = router.asPath;
// Utilisation du hook useDispatch pour dispatch une action
const dispatch = useDispatch();
// État pour stocker la localisation sélectionnée
const [selected, setSelected] = useState(null);
// Récupération du state global via le hook useSelector
const state = useSelector((state) => state);
useEffect(() => {
currentUrl === "/estimation-immobiliere"
? dispatch(updateFormAddressStatus(true))
: null;
}, [router.pathname]);
// Hook pour utiliser l'autocompletion de Google Places
const {
ready,
value,
setValue,
suggestions: { status, data },
clearSuggestions,
} = usePlacesAutocomplete();
useEffect(() => {
let timeoutId = null;
if (!ready) {
timeoutId = setTimeout(() => {
dispatch(updateIsReady(true));
// window.location.reload();
}, 2000);
}
return () => {
if (timeoutId) {
clearTimeout(timeoutId);
}
};
}, [ready]);
// Fonction pour sélectionner une adresse et obtenir ses coordonnées
const handleSelect = async (description) => {
setValue(description, false);
dispatch(updateAddress(description));
const results = await getGeocode({ address: description });
const { lat, lng } = await getLatLng(results[0]);
setSelected({ lat, lng });
clearSuggestions();
};
const handleSelected = () => {
if (value !== "") {
window.location.reload();
} else null;
};
useEffect(() => {
selected !== null ? dispatch(updateAddressCoordinate(selected)) : null;
}, [selected]);
return (
<div>
<input
value={value}
onChange={(e) => setValue(e.target.value)}
disabled={!ready}
onClick={handleSelected}
className={
color !== undefined
? "border text-purple rounded-lg placeholder:text-slate-400 px-3 w-full h-12 border-" +
color
: "border text-purple rounded-lg placeholder:text-slate-400 px-3 w-full h-12 border-purple"
}
placeholder={placeholder !== undefined ? placeholder : null}
/>
<div>
<ul className={"bg-white"}>
{data &&
data.length > 0 &&
status === "OK" &&
data.map(({ place_id, description }) => (
<li
key={place_id}
onClick={() => handleSelect(description)}
className="text-purple cursor-pointer mx-3 my-3 hover:font-bold z-50"
>
{description}
</li>
))}
</ul>
</div>
</div>
);
};
I really tried everything according to me and I would like to understand where is the error

Related

Call All User API with angular

I have problem calling API to HTML. The log is show up but the data is not show up on the html. How to call this type API properly? I'm using fuse Angular for the layout and data stuff
This is the HTML and Component
export class UserGroupTeamComponent implements OnInit
{
members: any;
constructor(private _CloudUserServer:CloudUserService)
{
}
ngOnInit(): void
{
this.getMembers();
}
async getMembers(): Promise<any> {
this.members = await this._CloudUserServer.getUsers();
console.log('abc',this.members)
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.10/angular.min.js"></script>
<div class="flex flex-col mt-8 divide-y border-t">
<ng-container *ngFor="let member of members">
<div class="flex flex-col sm:flex-row sm:items-center py-6">
<div class="flex items-center">
<div class="ml-4">
<div class="font-medium" *ngIf="members">{{member.name}}</div>
<div class="text-secondary">{{member.email}}</div>
</div>
</div>
</div>
</ng-container>
</div>
this is CloudUserService
async getUsers(limit?: number, lastKey?: string, filter?: string): Promise<any> {
const headers = {
// eslint-disable-next-line #typescript-eslint/naming-convention
Authorization: `Bearer ${(await Auth.currentSession()).getIdToken().getJwtToken()}`
};
const body = {};
const options = {headers: headers, body: body};
const limitParam = limit ? '&limit=' + limit.toString() : '';
const idParam = lastKey ? '&id=' + lastKey : '';
const filterParam = filter ? '&filter=%25' + filter + '%25' : '';
const path = `${this._userUrl}/users?${limitParam}${idParam}${filterParam}`;
const promise = API.get(this._apiName, path, options).then(
(result) => {
console.log('getUsers result', result);
return result.message;
},
(err) => {
console.log('getUsers err', err.response);
throw(err.response);
}
);
return promise;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.10/angular.min.js"></script>
The result should be all user name and user show up.

Getting textarea value in nextjs

I try to get data from a textarea in a react functional component, I'using Reducer hook to fetch data from the form, i use reducer to get data from the dom I don't understand what I've done wrong help would be very appreciated.
import Success from "../../components/singleElements/Success"
import Error from "../../components/singleElements/Error"
import { useQueryClient, useMutation } from "react-query"
import { addOnePub, getPub } from "../../lib/helper"
import { useReducer } from "react"
export default function Insertpub(){
//I use this reducer to fetch the data
const formReducer = (state, event) => {
return {
...state,
[event.target.name]: event.target.value,
};
};
//then get the textfield changes from here
const [formData, setFormData] = useReducer(formReducer, {});
const queryClient = useQueryClient()
const addMutation = useMutation(addOnePub, {
onSuccess : () => {
queryClient.prefetchQuery('pub', getPub)
}
})
const handleSubmit = (e) => {
e.preventDefault();
if(Object.keys(formData).length == 0) return console.log("Don't have Form Data");
let {pub} = formData;
const model = {
pub
}
addMutation.mutate(model)
console.log("the data is correctly inserted")
}
if(addMutation.isLoading) return <div>Loading!</div>
if(addMutation.isError) return <Error message={addMutation.error.message}></Error>
if(addMutation.isSuccess) return <Success message={"Added Successfully"}></Success>
//When I insert a value in this text area it returns null object
return (
<form onSubmit={handleSubmit}>
<textarea
className="bg-gray-200 w-full rounded-lg shadow border p-2"
rows="5"
placeholder="Ecrivez votre publication ici"
OnChange={setFormData}
name="pub"
id="pub"
></textarea>
<div className="w-full flex flex-row flex-wrap mt-3">
<div className="w-2/3">
<button
type="submit"
className="float-right bg-indigo-400 hover:bg-indigo-300 text-white p-2 rounded-lg"
>
Publier
</button>
</div>
</div>
</form>
)
}
Normally when I submit the form it should return value populated from the reducer hook but i got anything
It could be because of the typo in the capitalization (case matters):
OnChange={setFormData}
Should be
onChange={setFormData}

Make button behave like checkbox in React

I want to make a button behave like a checkbox in React, so the button that has been selected/clicked can return its value again or can be unselected again. But I haven't found a way.
Here's my code
const handleSelectedValue = (reason: any) => {
setSelectedValues(item => [...item, reason]);
};
// if value selected then change style
const checkId = (id: number) => {
return selectedValues.map(item => item.id).includes(id);
};
// inside jsx
{reasons.map(item => {
return (
<button
key={item.id}
className={`mr-2 mb-2 text-xs border-2 rounded-full font-semibold border-card-primary px-3 sm:px-5 py-2 ${checkId(item.id) ? 'text-white bg-base-primary opacity-75 border-none' : 'text-base-secondary'}`}
onClick={() => handleSelectedValue(item)}
>
{item.reason}
</button>
);
})}
This code works, but the selected value cannot be unselect. Thank you.
You have to check the existence of reason in the array. If it exists remove it else add it to list. You always add it.
const handleSelectedValue = (values) => {
setSelectedValues((item) => {
let idx = item.findIndex((itm) => itm.id === values.id);
if (idx !== -1) {
return item.filter(itm => itm.id !== values.id)
} else {
return [...item, values];
}
});
};

I' am creating the service in Angular with Node.js. Problem with date transferring between the components

I' am creating the service in Angular with Node.js. I have created 2 components and I want to share the data between them. From droplist to cards. With two droplists I search the date in the table and after I creates many buttons with names of Scenarios of the response in the cards component. But the data does not transfer from with routing. There aren't any errors in console.
Project on stackblitz:
https://stackblitz.com/github/ShimolinNik/LawClinicFrontend
This is my Frontend in Gitlab.
[1]: https://gitlab.unige.ch/thinkdata-pour-la-clinique-de-la-loi/front-end
Droplist component :
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Router } from '#angular/router';
#Component({
selector: 'app-droplist',
templateUrl: './droplist.component.html',
styleUrls: ['./droplist.component.css']
})
export class DroplistComponent implements OnInit {
themes = ["Tous les thèmes","Procédure d'asile", "Représentation légale", "Aides financières et matérielles",
"Hébergement", "Santé", "Famille", "Formation", "Vie courante et voyage",
"Protection en cas de violences", "Droits face à la police", "Questions spécifiques au Tribunal"];
mots = ["Tous les mots","admission provisoire","aide d’urgence","aide sociale","AJ","aménagements","appréhension",
"apprentissage","assistance judiciaire gratuite","assistance juridique","assistant-e social-e","besoins éducatifs particuliers",
"besoins éducatifs particuliers","centre de la Confédération","classes d’accueil","conseiller-ère-s juridiques",
"curateur-rice","débouté-e","débouté-e de l'asile","décision d'exécution du renvoi","décision de non-entrée en matière (NEM)",
"décision de renvoi","décision de renvoi avec délai de départ","décision d’exécution du renvoi","décision NEM","décision NEM Dublin",
"défense d’office","défense obligatoire","dénonciation","détenu-e","droit d’être entendu-e","École de culture générale (ECG)","école ordinaire",
"école spécialisée","effet suspensif","enseignement secondaire II","espace Dublin","État Dublin","Haute école spécialisée (HES)",
"IGS","intérêt supérieur de l’enfant","majeur-e"," mesures de pédagogie spécialisée","mineur-e","Ministère public","moyen de preuve","OCPM","PC",
"peine pécuniaire","permis B","permis B réfugié-e","permis C","permis F","permis F admission provisoire","permis F réfugié-e","permis L",
"permis N","personne de confiance","personne lésée","plainte pénale","planning familial","prévenu-e","prime d’assurance-maladie","primes",
"principe de proportionnalité","procédure accélérée","procédure de poursuite","procédure Dublin","procédure étendue","procédure pénale","procès-verbal (PV)",
"recours","réfugié-e","regroupement familial","régularisation","représentant-e juridique","représentant-e légal-e","sans statut légal",
"secondaire I","sexe légal","subside","témoin","Tribunal des mineur-e-s","tuteur-rice","université","victime","vie familiale","vie familiale existante"];
constructor(private httpClient: HttpClient,private router:Router) { }
selectedTheme:String = "Tous les thèmes";
selectedMot:String = "Tous les mots";
onSelect(){
this.getCartes();
this.router.navigate(['./cards'], {state:{info:this.information }})
}
lasttheme:String="";
lastmot:String="";
information:any;
id = 0;
getValue(value :any) {
this.id=value;
console.log(value);
}
getDonnees() {
this.httpClient.get("http://localhost:3000/sc/"+this.id.toString()).subscribe(res => {this.information=res;})
}
getCartes() {
console.log(this.selectedTheme);
console.log(this.selectedMot);
// Recherche par tous les thèmes et par tous les mots
if(this.selectedTheme == "Tous les thèmes" && this.selectedMot == "Tous les mots"){
this.httpClient.get("http://localhost:3000/all").subscribe(res => {this.information=res;})
this.lasttheme=this.selectedTheme;
this.lastmot=this.selectedMot;
}
// Recherche par thème
else if (this.selectedTheme != this.lasttheme && (this.selectedMot=="" || this.selectedMot=="Tous les mots")) {
this.httpClient.get("http://localhost:3000//"+this.selectedTheme).subscribe(res => {this.information=res;console.log(this.information)})
this.lasttheme=this.selectedTheme;
this.lastmot=this.selectedMot;
}
else if(this.selectedMot == "Tous les mots" && this.selectedTheme == this.lasttheme){
this.httpClient.get("http://localhost:3000//"+this.selectedTheme).subscribe(res => {this.information=res;})
this.lastmot=this.selectedMot;
}
// Recherche par mot
else if (this.selectedMot != this.lastmot && (this.selectedTheme == "" || this.selectedTheme == "Tous les thèmes")) {
this.httpClient.get("http://localhost:3000/"+this.selectedMot).subscribe(res => {this.information=res;})
this.lasttheme=this.selectedTheme;
this.lastmot=this.selectedMot;
}
else if (this.selectedTheme == "Tous les thèmes" && this.selectedMot == this.lastmot){
this.httpClient.get("http://localhost:3000/"+this.selectedMot).subscribe(res => {this.information=res;})
this.lasttheme=this.selectedTheme;
}
//Recherche par mot et par thème
else if ((this.selectedTheme != this.lasttheme && this.selectedTheme != "Tous les thèmes" && this.selectedMot != "" ) || (this.selectedMot != this.lastmot && this.selectedMot!="Tous les mots" && this.selectedTheme !="" )){
this.httpClient.get("http://localhost:3000/"+this.selectedTheme+"/"+this.selectedMot).subscribe(res => {this.information=res;})
this.lasttheme=this.selectedTheme;
this.lastmot=this.selectedMot;
}
else {
console.log(5)
}
console.log(this.information)
};
ngOnInit(): void {
//this.httpClient.get("http://localhost:3000/all").subscribe(res => {this.information=res;})
}
}
<mat-form-field appearance="fill">
<mat-label>Themes</mat-label>
<mat-select [(ngModel)]="selectedTheme" (selectionChange)="onSelect()">
<mat-option *ngFor="let theme of themes" [value]="theme">
{{theme}}
</mat-option>
</mat-select>
</mat-form-field>
<p>You selected: {{selectedTheme}}</p>
<mat-form-field appearance="fill">
<mat-label>Mots-clés</mat-label>
<mat-select [(ngModel)]="selectedMot" (selectionChange)="onSelect()">
<mat-option *ngFor="let mot of mots" [value]="mot">
{{mot}}
</mat-option>
</mat-select>
</mat-form-field>
<p>Your selected mot: {{selectedMot}}</p>
<router-outlet></router-outlet>
Cards component:
import { Component, OnInit } from '#angular/core';
import { DroplistComponent } from '../droplist/droplist.component';
import { HttpClient } from '#angular/common/http';
import { Router } from '#angular/router';
#Component({
selector: 'app-cards',
templateUrl: './cards.component.html',
styleUrls: ['./cards.component.css']
})
export class CardsComponent implements OnInit {
constructor(private httpClient: HttpClient, private router:Router) {
this.info = this.router.getCurrentNavigation()?.extras.state?.info;
}
info;
ngOnInit(): void {
}
}
<button id ="element.id_Scenario" *ngFor="let element of info" >{{element.Nom_Scenario}}</button>
<router-outlet></router-outlet>
Help me please

I want to add addEventListener() in Reactjs by which if I click outside this model, the model get close

class Model extends Component {
render() {
return (
<ProductConsumer>
{(value) => {
const {modelOpen, closeModel} = value;
const{img, title, price} = value.modelProduct;
if (!modelOpen) {
return null;
}
else {
return (
<ModalContainer>
<div className="container">
<div className="row">
<div id="model" className=" cl-8 mx-auto xolo-md-6 collg-4 text-center text-capitalize p-5">
<h5> Item added to cart </h5>
<img src={img} className="img-fluid" alt="product" />
<h5> {title} </h5>
<h5 className="text-muted"> price : $ {price} </h5>
<Link to="/">
<ButtonContainer onClick = {() => closeModel()}>
continue shopping
</ButtonContainer>
</Link>
<Link to="/cart">
<ButtonContainer cart onClick={() => closeModel()}>
go to cart
</ButtonContainer>
</Link>
</div>
</div>
</div>
</ModalContainer>
);
}}
}
</ProductConsumer>
);
}
}
export default Model;
You can use the below component to check whether the click is outside or inside.
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class OutsideClick extends Component {
constructor (props) {
super(props)
this.getContainer = this.getContainer.bind(this)
this.isTouch = false
this.handle = this.handle.bind(this)
this.checkIfClickWithinListenBoundary = this.checkIfClickWithinListenBoundary.bind(this);
this.checkifClickWithinIgnoreBoundary = this.checkifClickWithinIgnoreBoundary.bind(this);
}
componentDidMount () {
document.addEventListener('touchend', this.handle, true)
document.addEventListener('click', this.handle, true)
}
componentWillUnmount () {
document.removeEventListener('touchend', this.handle, true)
document.removeEventListener('click', this.handle, true)
}
getContainer (ref) {
this.container = ref
}
checkIfClickWithinListenBoundary(node) {
if (!this.props.listenClickWithinClass) {
return true;
}
const el = document.querySelector(`.${this.props.listenClickWithinClass}`)
if (!el) {
return el.contains(node)
}
return false
}
checkifClickWithinIgnoreBoundary(node) {
if (!this.props.ignoreClickWithinClass) {
return true;
}
const el = document.querySelector(`.${this.props.ignoreClickWithinClass}`)
if (el) {
return !el.contains(node)
}
return false
}
handle (e) {
if (e.type === 'touchend') {
this.isTouch = true
}
if (e.type === 'click' && this.isTouch) {
return
}
const { onClickOutside } = this.props
const el = this.container
if (!el.contains(e.target) && this.checkIfClickWithinListenBoundary(e.target) && this.checkifClickWithinIgnoreBoundary(e.target)) {
onClickOutside(e)
}
}
render () {
const {
children, onClickOutside, listenClickWithinClass, ignoreClickWithinClass, ...props
} = this.props
return <div {...props} ref={this.getContainer}>{children}</div>
}
}
OutsideClick.propTypes = {
onClickOutside: PropTypes.func.isRequired,
listenClickWithinClass: PropTypes.string,
ignoreClickWithinClass: PropTypes.string,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
])
}
OutsideClick.defaultProps = {
children: null,
listenClickWithinClass: null,
ignoreClickWithinClass: null
}
You can use this way.
return (
<OutsideClick onClickOutside={() => this.closeModel()} >
<ModalContainer>
.......
</ModalContainer>
</OutsideClick>
)