this.props.contextValue.store.getState is not a function when adding a custom input - algolia

I'm running into an issue with adding my own custon input after following the documentation for Autocomplete.
The error I get is "this.props.contextValue.store.getState is not a function" when adding my CustomSearchBox component. Can anyone advise what I'm doing wrong?
Usage:
<InstantSearch
searchClient={algoliaClient}
indexName="plp"
>
<CustomSearchBox /> // Errors when I add this
<Autocomplete
searchClient={algoliaClient}
placeholder="Search products"
detachedMediaQuery="none"
openOnFocus
/>
<RefinementList attribute="DIAMETER" />
<HitWrapper>
<Hits hitComponent={Hit} />
</HitWrapper>
</InstantSearch>
Custom search box component
import React from 'react';
import { connectSearchBox } from 'react-instantsearch-dom';
const SearchBox = ({ currentRefinement, isSearchStalled, refine }) => (
<form noValidate action="" role="search">
<input
type="search"
value={currentRefinement}
onChange={event => refine(event.currentTarget.value)}
/>
{isSearchStalled ? 'My search is stalled' : ''}
</form>
);
const CustomSearchBox = connectSearchBox(SearchBox);
export default CustomSearchBox;

Related

TypeError on submit handler (Nextjs)

For a new project (next.js) I'd like to add an on submit handler to a form component and map the input of the form at the bottom of the page. However, I get the typeError message claiming that the "addSpending" is not a function.
Here the code for the form component:
import styled from "styled-components";
export default function NewSpendingForm({ addSpending }) {
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const data = Object.fromEntries(formData);
addSpending(data);
}
return (
<StyledBody>
<StyledIntro>Please fill the form to add your spendings:</StyledIntro>
<StyledAddSpendingForm onSubmit={handleSubmit}>
<StyledFormLabel>Title</StyledFormLabel>
<StyledFormInput type="text" id="title" name="title" required />
<StyledFormLabel>Amount</StyledFormLabel>
<StyledFormInput type="number" id="amount" name="amount" step="0.01" min="0" required />
<StyledFormLabel>Date</StyledFormLabel>
<StyledFormInput type="date" id="date" name="date" required />
<StyledFormLabel>Category</StyledFormLabel>
<StyledFormSelect type="select" id="category" name="category" required >
<option>Food and Drinks</option>
<option>Clothes</option>
<option>Household</option>
<option>Entertainment</option>
<option>Gasoline</option>
<option>Restaurants</option>
<option>Others</option>
</StyledFormSelect>
<StyledFormButton type="submit">Submit</StyledFormButton>
</StyledAddSpendingForm>
</StyledBody>
);
}
And this one for the page:
import styled from "styled-components";
import NewSpendingForm from "../../components/AddSpendingForm";
export default function AddSpendingPage({ spendingInput, addSpendingInput }) {
return (
<>
<StyledHeader>
<StyledTitle>Add Spendings</StyledTitle>
</StyledHeader>
<StyledBody>
<NewSpendingForm addSpending={addSpendingInput} />
<StyledLogTitle> Your Spendings Log</StyledLogTitle>
<StyledLog>
{spendingInput.map((spendingInput) => (
<StyledLogEntry>
{spendingInput.title}
{spendingInput.amount}€
{spendingInput.date}
{spendingInput.category}
</StyledLogEntry>
))}
</StyledLog>
</StyledBody>
</>
);
}
Thanks a lot in advance!
I expected the form input to be mapped and displayed at the bottom of the page. However, after clicking on the "Submit" button I get the mentioned TypeError message.

How to wait for a checkbox to be selected in Testing Library

I have a simple component that looks like this :
function Checkboxes(props) {
return (
<div>
<input className="item-box-checkbox-1" type="checkbox" checked={getIsChecked(1, props)} />
<input className="item-box-checkbox-2" type="checkbox" checked={getIsChecked(2, props)} />
<input className="item-box-checkbox-3" type="checkbox" checked={getIsChecked(3, props)} />
<input className="item-box-checkbox-4" type="checkbox" checked={getIsChecked(4, props)} />
...
</div>
)
}
I would like to use Testing Library to "listen" on a checkbox click. As soon as the checkbox is checked I would like to proceed with my test.
Behind the scenes after checking on the checkbox some things are happening. After these things have happened then the checkbox should display as checked.
I have tried the following :
fireEvent.click(checkboxes[1]);
await screen.findAllByRole('checkbox', {checked: true})
But this does not seem to work.
There also seems to be a screen.getByRole("checkbox")).toBeChecked() . But I need to wait for the checkbox to be checked. screen.get* functions as I understand to not provide for this.
it is hard to tell what some things are happening but assuming we have sth like this:
import React from "react";
function Checkboxes(props) {
const [checked1, setCheck1] = React.useState(false);
const [checked2, setCheck2] = React.useState(false);
const [checked3, setCheck3] = React.useState(false);
const [checked4, setCheck4] = React.useState(false);
return (
<div>
<input className="item-box-checkbox-1" type="checkbox" onChange={setCheck1} checked={checked1} />
<input className="item-box-checkbox-2" type="checkbox" onChange={setCheck2} checked={checked2} />
<input className="item-box-checkbox-3" type="checkbox" onChange={setCheck3} checked={checked3} />
<input className="item-box-checkbox-4" type="checkbox" onChange={setCheck4} checked={checked4} />
</div>
)
}
export default Checkboxes;
Then your code work for me. You may also try to waitFor:
import { fireEvent, render, screen, waitFor } from '#testing-library/react';
import Checkboxes from "../Checkboxes";
it('should work', async () => {
render(<Checkboxes />);
const checkboxes = screen.getAllByRole('checkbox');
expect(checkboxes[1]).not.toBeChecked();
fireEvent.click(checkboxes[1]);
const checked = await screen.findAllByRole('checkbox', {checked: true})
expect(checked).toHaveLength(1);
await waitFor(() => expect(checkboxes[1]).toBeChecked())
})

How to disable autocomplete with v-form

I want to disable chrome autocomplete in my v-form. How do I do that? I don't see a autocomplete property on the v-form.
https://next.vuetifyjs.com/en/api/v-form/
While it is a property on a normal html form
https://www.w3schools.com/tags/att_form_autocomplete.asp
By setting autocomplete="username" and autocomplete="new-password" on v-text-field you can actually turn off the autocomplete in chrome.
here is a code that worked for me:
<v-form lazy-validation ref="login" v-model="validForm" #submit.prevent="submit()">
<v-text-field
v-model="user.email"
label="Email"
autocomplete="username"
/>
<v-text-field
v-model="user.password"
label="Password"
type="password"
autocomplete="new-password"
/>
<v-btn type="submit" />
</v-form>
Edit: autocomplete isn't set as a prop in vuetify docs but if you pass something to a component which isn't defined as prop in that component, it will accept it as an attribute and you can access it through $attrs.
here is the result of the above code in vue dev tools:
and here is the rendered html:
I wasn't able to get autofill disabled with the above methods, but changing the name to a random string/number worked.
name:"Math.random()"
https://github.com/vuetifyjs/vuetify/issues/2792
use autocomplete="off" in <v-text-field
<v-text-field
autocomplete="off"
/>
Just add:
autocomplete="false"
to your <v-text-field> or any input
autocomplete="null"
This one prevents Chrome autofill feature
I have not been able to get any of the previous proposals to work for me, what I finally did is change the text-flied for a text-area of a single line and thus it no longer autocompletes
Try passing the type='search' and autocomplete="off" props.
I also ran into a similar problem. Nothing worked until I found this wonderful Blog "How to prevent Chrome from auto-filling on Vue?" by İbrahim Turan
The main catch is that we will change the type of v-text-field on runtime. From the below code you can see that the type of password field is assigned from the value fieldTypes.password. Based on focus and blur events we assign the type of the field. Also, the name attribute is important as we decide based on that in the handleType() function.
I'm also pasting the solution here:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<div id="app">
<div v-if="isloggedin" class="welcome">
Welcome {{username}}
</div>
<div v-else id="form-wrapper">
<label for="username">Username: </label>
<input
v-model="username"
class="form-input"
type="text"
name="username"
value=""
autocomplete="off"
/>
<label for="password">Password: </label>
<input
v-model="password"
class="form-input"
:type="fieldTypes.password"
name="password"
value=""
#focus="handleType"
#blur="handleType"
autocomplete="off"
/>
<button class="block" type="button" #click="saveCredentials">
Submit Form
</button>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
username: '',
password: '',
isloggedin: false,
fieldTypes: {
password: 'text',
}
}
},
methods: {
saveCredentials() {
this.isloggedin = true;
},
handleType(event) {
const { srcElement, type } = event;
const { name, value } = srcElement;
if(type === 'blur' && !value) {
this.fieldTypes[name] = 'text'
} else {
this.fieldTypes[name] = 'password'
}
}
}
}
</script>

How to correctly pass props to a custom component with Redux-form v6

I am trying to update my form to redux-form v6.7 and I'm having difficulties wrapping my head about this part.
Say I want to render a select component like so :
<div className="col-md-12">
<Field name="name" component={renderSelect}/>
</div>
Here is my component that was working fine with the previous versions of react-redux, obviously with a form prop named "name" :
<VirtualizedSelect
{...domOnlyProps(name)}
filterOptions={itemsFilter}
options={this.state.items.items}
onChange={name.onChange}
value={name.value}
name="name"
placeholder="Name"
onBlur={() => name.onBlur(name.value)}
autoBlur={true}
simpleValue={true}
multi={true}
clearable={false}
onBlurResetsInput={false}
onCloseResetsInput={false}
delimiter="|"
showNewOptionAtTop={false}
selectComponent={Creatable}
promptTextCreator={(label) => {return "Search for " + label}}
/>
So now I am trying to wrap this component in a renderSelect() function. But I am unsure how to correctly pass the props I need to the custom component. What props should I pass, which props are passed by default, etc.
const renderSelect = ({/*what to pass here?*/ input }) => (
<FormGroup controlId="name" role="form" className="col-md-12">
<div className="group selectW" style={{width: '100%'}}>
<VirtualizedSelect
{...domOnlyProps(name)}
filterOptions={itemsFilter}
options={this.state.items.items}
onChange={name.onChange}
value={name.value}
name="name"
placeholder="Name"
onBlur={() => name.onBlur(name.value)}
autoBlur={true}
simpleValue={true}
multi={true}
clearable={false}
onBlurResetsInput={false}
onCloseResetsInput={false}
delimiter="|"
showNewOptionAtTop={false}
selectComponent={Creatable}
promptTextCreator={(label) => {return "Search for " + label}}
/>
</div>
</FormGroup>
);
Help appreciated.
I figured it out, posting what it looks like as it might help others at some point
const renderSelect = ({input, items, filter}) => (
<FormGroup controlId="name" role="form" className="col-md-12">
<div className="group selectW" style={{width: '100%'}}>
<VirtualizedSelect
filterOptions={filter}
options={items}
onChange={input.onChange}
value={input.value}
name={input.name}
placeholder="Name"
onBlur={() => input.onBlur(input.value)}
autoBlur={true}
simpleValue={true}
multi={true}
clearable={false}
onBlurResetsInput={false}
onCloseResetsInput={false}
delimiter="|"
showNewOptionAtTop={false}
selectComponent={Creatable}
promptTextCreator={(label) => {return "Search for " + label}}
/>
</div>
</FormGroup>
);

react rerendering form causes focus/blur issue on state change

I have a form in a react component that has two change handlers, one for my two draftjs textareas, and one for my other text inputs:
onChangeEditor = (editorStateKey) => (editorState) => {
this.setState({ [editorStateKey]: editorState });
}
handleInputChange(event) {
event.preventDefault();
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
In my render method I have two views that I switch between depending on which view mode I am in, read or edit:
render () {
const Editable = () => (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" key="text01" name="title" defaultValue={this.state.title} onBlur={this.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.state.editorState1} onChange={this.onChangeEditor('editorState1')} name="text01"/>
<h4>Citat</h4>
<input type="text" key="text02" name="quote01" defaultValue={this.state.quote01} onBlur={this.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.state.editorState2} onChange={this.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.saveForm} />
</form>
</div>
);
const Readable = () => (
<div>
<h1 className="header66">{this.state.title}</h1>
<div className="text66">{this.state.text01}</div>
<div className="quote100">{this.state.quote01}</div>
<div className="text66">{this.state.text02}</div>
</div>
);
return (
<div>
{ this.props.isInEditMode ? <Editable /> : <Readable /> }
</div>
);
}
When I switch between inputs in my browser I have to click twice in order to get the focus on the right input.
I suspect that this is because a change is triggered on the "blur" event of each input, causing the form to rerender because state is changed. And when the form rerenders, it goes through the { this.props.isInEditMode ? <Editable /> : <Readable /> } which causes the input to lose focus.
The problem is that I don't know how to get around this.
I solved it myself.
It turns out that it was not a good idea to place the Editable and Readable inside of my component as I did. Instead I moved them out to their own components, and it works properly now.
class Editable extends React.Component {
render() {
return (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" name="title" defaultValue={this.props.title} onChange={this.props.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.props.editorState1} onChange={this.props.onChangeEditor('editorState1')} name="text01" />
<h4>Citat</h4>
<input type="text" name="quote01" defaultValue={this.props.quote01} onChange={this.props.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.props.editorState2} onChange={this.props.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.props.saveForm} />
</form>
</div>
);
}
};
class Readable extends React.Component {
render() {
return (
<div>
<h1 className="header66">{this.props.title}</h1>
<div className="text66">{this.props.text01}</div>
<div className="quote100">{this.props.quote01}</div>
<div className="text66">{this.props.text02}</div>
</div>
);
}
};