How to conditionally append a url parameter to form text input - javascript

I have a form with a single input which is query for the search url -
<form className={styles.searchInputContainer} role="search" action="/search">
<label htmlFor={id} className={styles.searchLabel}>{constants.search}</label>
<input id={id} className={styles.searchInput} type="search" name="q" placeholder="Search..." autocomplete="off" />
</form>
At the moment, when I hit enter, the url will end with '/search?q=whatever_the_input_is'
I am currently doing logic elsewhere in the file to check if the search bar is on a particular page. With this boolean value (isShoppingPage), I want to optionally append a 'type=shop' to the url when the user hits enter so it automatically only searches through the shop categories. I've tried appending 'type=shop' to the input value but then the url ends up having URL encoding. I'm confused as to how to conditionally add this without changing the name="q" which the input currently has and needs.

Instead of action you can use onSubmit prop of the form.
import React, {useState} from 'react';
const Form = (props) => {
const {styles, id, constants} = props;
const [qValue, setQValue] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
// here you can make API call with q=qValue and type=shop
};
return (
<form className={styles.searchInputContainer} role="search" onSubmit={handleSubmit}>
<label htmlFor={id} className={styles.searchLabel}>{constants.search}</label>
<input id={id} className={styles.searchInput} type="search" name="q" placeholder="Search..." autocomplete="off" value={qValue} onChange={e => setQValue(e.target.value)} />
</form>
)
};
This is guide from react docs

Related

Two forms on the same level are submitted in react app

I have react app with with complex component layout with multiple forms.
I know that placing one form inside another is not allowed. But I have a component which renders a form and must be placed inside my form. To prevent forms be rendered one inside another I use react portal.
But when I try to submit form rendered with portal, first form is also submitted that is unexpected. Looks like I miss something important.
How to prevent first form submit when submitting the second?
Thank you
Simplified example is here
import { createPortal } from "react-dom";
const Portal = ({ children, elm }) => createPortal(children, elm);
export default function App() {
return (
<div className="App">
<form
onSubmit={(e) => {
e.preventDefault();
alert("submit 1");
}}
>
First form <input type="text" value="1" />
<Portal elm={document.querySelector("body")}>
Second form{" "}
<form
onSubmit={(e) => {
e.preventDefault();
alert("submit 2");
}}
>
<input type="text" value="2" />
<input type="submit" value="submit 2" />
</form>
</Portal>
</form>
</div>
);
}
I had the same problem, as #EisaRezaei said in the first comment, using e.stopPropagation() in the form inside the portal, and submit type buttons, everything worked fine

redux-form How to have initial value in the input field

I use redux-form for my form, following the example: https://redux-form.com/8.3.0/docs/api/fields.md/
So the <Fields /> is like so:
<Fields
names={['firstName', 'lastName']}
component={input}
validate={{
firstName: (value, allValues, props, name) => 'error'
}}
warn={{
lastName: (value, allValues, props) => 'warning'
}}
/>
the fields component that i render is this
const renderFields = (fields) => (
<div>
<div className="input-row">
<input {...fields.firstName.input} type="text"/>
{fields.firstName.meta.touched && fields.firstName.meta.error &&
<span className="error">{fields.firstName.meta.error}</span>}
</div>
<div className="input-row">
<input {...fields.lastName.input} type="text"/>
{fields.lastName.meta.touched && fields.lastName.meta.error &&
<span className="error">{fields.lastName.meta.error}</span>}
</div>
</div>
)
So far so good, the form displays the 2 input fields and i can add values into them.
But how do i pass default values into the input's ?
When i add the value property into the input, i cant edit the input afterwards.
For example, i add the value prop with a value like so:
const renderFields = (fields) => (
<div>
<div className="input-row">
// add value="my name"
<input {...fields.firstName.input} type="text" value="my name" />
{fields.firstName.meta.touched && fields.firstName.meta.error &&
<span className="error">{fields.firstName.meta.error}</span>}
</div>
<div className="input-row">
// add value="my last name"
<input {...fields.lastName.input} type="text" value="my last name" />
{fields.lastName.meta.touched && fields.lastName.meta.error &&
<span className="error">{fields.lastName.meta.error}</span>}
</div>
</div>
)
In that way, the inputs have always the same init value.
Any help on how to have default value and also be able to edit it, thank you.
When you provide the value prop you will need to provide onChange function as well and handle the state - https://reactjs.org/docs/forms.html#controlled-components
and from redux-form docs: https://redux-form.com/8.3.0/docs/api/field.md/#-code-onchange-event-newvalue-previousvalue-name-gt-void-code-optional-
You need a state variable to hold the input value.
const [inputValue, setInputValue] = useState('');
In the input tag, use the previously declared state variable as value & in onChange of input, set the input value to the target value.
<input type="text" value={inputValue} onChange={e => setInputValue(e.target.value)} />
You can use prop defaultValue, as mentioned in Redux Form documentation :https://redux-form.com/6.0.0-alpha.4/docs/api/field.md/#props
<Field component={your custom component} defaultValue={}/>

React component is changing an uncontrolled input to be controlled error

please , how can i get over this error of component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
this prevent the input field from showing what i am typing.
const [sellerName, setSellerName] = useState();
const [storeName, setStoreName] = useState("");
...
<form className="registerInputContainer customerEditInput">
<div className="regInput passForm ">
<span className="userEmail">Owner's Full name (Required)</span>
<div className="passwordContainer editCusInputField">
<input
placeholder="your name"
value={sellerName }
onChange={(e) => setSellerName(e.target.value)}
className="passwordInput regInputField"
/>
</div>
</div>
<div className="regInput passForm ">
<span className="userEmail">Store Name (required)</span>
<div className="passwordContainer editCusInputField">
<input
placeholder=""
required
value={storeName || ""}
onChange={(e) => setStoreName(e.target.value)}
className="passwordInput regInputField"
/>
</div>
</div>
...
</form>
i have tried some of the solution i saw on stackoverflow but they are not working . thanks you all

vee-validate#4.x - how to manually validate field

While using
vee-validate#4.4.5
vue#3.1.4
I encountered following problem:
<Form #submit="onSubmit" :validation-schema="schema">
<div class="mb-3">
<label for="edit-email" class="form-label">E-mail</label>
<Field
id="edit-email"
class="form-control"
name="email"
type="text"
:validateOnInput="true"
/>
<ErrorMessage class="invalid-feedback" name="email" />
</div>
<button #click="checkEmail" type="button">Check e-mail address</button>
<!-- non-important part of the form -->
</Form>
I'd like to manually validate <Field /> when the button is clicked (error message should appear) and then I want to use the field's value to perform another action.
I wrote following code:
import { useFieldValue } from 'vee-validate';
// setup
setup() {
const schema = object({
email: string().required().email().label("e-mail"),
});
function verifyEmail(v) {
const emailValue = useFieldValue("email");
console.log(emailValue); // empty ComputedRefImpl
}
return {
schema,
verifyEmail,
};
},
}
And this doesn't work.
emailValue is returned as ComputedRefImpl with an undefined value.
I guess I'm mixing Components & Composition API flavors of vee-validate. But still don't know how to resolve this issue.
Created sandbox with this: https://codesandbox.io/s/vue3-vee-validate-form-field-forked-xqtdg?file=/src/App.vue
Any help will be much appreciated!
According to vee-validate's author:
https://github.com/logaretm/vee-validate/issues/3371#issuecomment-872969383
the useFieldValue only works as a child of a useForm or useField.
So it doesn't work when <Field /> component is used.

Input form value remains the same even with an onChange handler

This code is a functional component that should render a user detail page(Show details view) OR a form to edit(Edit detail view) this user info depending on the state of isUpdate. This works alright, as the update and save buttons change the state of isUpdate to render the Edit View or Show View respectively.
When I select a user, the page gets the specific user by match.params.id which also works. My problem is when the isUpdate is set to true (the edit form with the original values of the user details is rendered) I expect that the input values change when I type on the input for, but instead the value remains the same as its original value(unable to type new values).
I dont know why I am facing this problem.
UserDetail Component code below:
import React, {Fragment, useEffect, useState} from 'react';
import { connect } from 'react-redux';
import { findUser } from '../../actions/user';
const UserDetails =({match, user, loading, findUser}) => {
const[isUpdate, setIsUpdate]=useState(false);
//fetching user info based on the params id
useEffect(() => {
findUser(match.params.id);
},[])
//setting the initial state of user to the values from the fetched data
const[userData, setUserData]=useState({
name: user.name,
email: user.email,
});
//on Change handler
const onChange = e =>{
setUserData({...userData, [e.target.name]:e.target.value})
}
//User detail rendered to be viewed or edited
return loading ?
(<Fragment>
<div className="loader-container" ></div>
<div className="loader"></div>
</Fragment>) :
(isUpdate ? (
<Fragment>
<div className="detail-container">
<form>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="name">Full Name:</label>
<input
type="name"
className="form-control"
id="name"
name="name"
value={user.name}
onChange={e=>onChange(e)}/>
</div>
<div className="form-group col-md-6">
<label htmlFor="email">Email:</label>
<input
type="email"
className="form-control"
id="email"
name="email"
value={user.email}
onChange={e=>onChange(e)}/>
</div>
</div>
<button type="submit" className="btn btn-primary" onClick={()=>setIsUpdate(false)}>SAVE</button>
</form>
</div>
</Fragment>):
(<Fragment>
<div className="detail-container">
<div className="d-flex justify-content-end mb-20"> <button className="btn btn-warning "
onClick={()=>setIsUpdate(true)}> UPDATE</button>
</div>
<div className="row mb-10">
<div className=" col-md-6">
<div className="detail-label">Full Name:</div>
<div className="detail">{`${user.name}`}</div>
</div>
<div className=" col-md-6">
<div className="detail-label">Email:</div>
<div className="detail">{`${user.email}`}</div>
</div>
</div>
</div>
</Fragment>))
const mapStateToProps = (state) => ({
user: state.user.a_user,
loading: state.user.loading
})
export default connect(mapStateToProps,{findUser})(UserDetails);
Please I would appreciate anyone pointing me in the right direction.
The user data remains constant during the editing session, so the input element cannot work properly. Try to change its declaration using the userData instead:
<input
type="name"
className="form-control"
id="name"
name="name"
value={userData.name}
onChange={e=>onChange(e)}/>
UPDATE: in order to update the userData state whenever the user changes, you could use this trick:
const[userData, setUserData]=useState();
useEffect(
() => {
setUserData({
name: user.name,
email: user.email,
});
},
[user]
);
Take care to handle the initial condition where userData is undefined.
Your form inputs values should be targetting userData instead of user i.e
<input
...name="name"
value={userData.name} />
You need to set your userData in the useEffect method as it seems that for each user, the userData value is using values fetched previously.
useEffect(() => {
findUser(match.params.id)
setUserData(user)
},[])
I'm guessing the findUser method updates the user in the parent component.
This should work.

Categories

Resources