When the user picks a value from a select dropdown, the onChange calls a function in the parent container. There I need to check which fields are filled.
But it appears that the value hasn't been set in the form yet.
I have tried to use the selectors valid and getFormvalues, but they are not updated with the latest form value change.
See this codesandbox.
If I print getFormvalues in the render of the form component, it is updated, but I can't handle the form there.
So how can I handle the form after the user picks a value, where the form is updated?
You are already receiving values in the SimpleFormContainer due to connect. You don't need the callback from SimpleFormContainer to SimpleForm. You can use the componentWillReceiveProps in the SimpleFormContainer to check the values update and do whatever you want.
The final code might look like:-
class SimpleFormContainer extends React.Component {
componentWillReceiveProps(nextValues) {
if (this.props.formValues !== nextValues.formValues){
console.log(nextValues.formValues)
}
}
render() {
return (
<SimpleForm onSubmit={showResults}/>
)
}
}
SimpleFormContainer = connect(
state => ({
formValues: getFormValues('simple')(state)
}),
{ getFormValues }
)(SimpleFormContainer);
Working example
Related
I would like to add a required field to a Kendo form.
This works with:
validation: { required: true },
If I now want to set required myself in a function, this no longer works.
validation: {
required: function(){
return true;
}
},
I have created an example: https://dojo.telerik.com/epEzewIt/5
If no entry is made in the "MultiSelect" field, the required variant as a function is no longer displayed: "MultiSelect is required" when it is empty.
How can I store required with a function?
If you want to execute some code one time you can use an anonymous function like:
validation: {
required: (function(){
return true; // run your rules here
})()
But, as documentation suggests, those (required, max/min, pattern, etc.) are field attributes that map to HTML rules. So you can't pass a function.
Why not use the kendoValidator on your submit action. This can be used to validate all the fields and set custom messages.
Here are more details on how to use Kendo Validator to create custom validations:
https://docs.telerik.com/kendo-ui/controls/editors/validator/rules
There are a lot of examples there.
if you want to achieve this and to have a event handler, you can use the following code:
validation: {
validated: function (input) {
//here you can place your code
//you need to return true of false
//e.g
if(true){ return true; }
return false;
}
}
I had the same use case, as I was building it dynamically.
As you can see I was able to validate it:
I have a React-Redux app which displays a dashboard page when the user first logs on. The dashboard displays a number of statistics/graphs etc. which are components most (not all) of which are filtered based on a state site value. This site value is initially set when the user logs on and is derived from their profile.
The components mostly follow the pattern of using the componentDidMount lifecycle event to call a thunk method. Within the thunk method the site value is retrieved from redux state and passed in the database query. Reducer then adds results to state. Standard stuff. The redux state is fairly flat i.e. the state for the statistics/graphs etc. are not nested under the selected site but are their own objects off the root.
On the dashboard is also a dropdownlist which contains all sites. Initially this is set to the users default site. This dropdown is intended to allow the user to see statistics/graphs for sites other than their default.
What I would like is for all the (site specific) dashboard components to refresh when the user selects a different site from the dropdownlist. The problem I am having is how do I get these components to refresh? or more specifically, how to get their state to refresh.
UPDATE:
I tried two different approaches.
In the thunk action for handling the site change effect (changeSite) I added dispatch calls to each components thunk action. Although this worked I didn't like the fact that the changeSite thunk needed to know about the other components and what action creators to call. i.e. thunk action looked like:
changeSite: (siteId: number): AppThunkAction<any> => async (dispatch) => {
const promiseSiteUpdate = dispatch({ type: 'CHANGE_SITE', siteId });
await Promise.all([promiseSiteUpdate]);
dispatch(AncillariesStore.actionCreators.requestExpiring(siteId));
dispatch(AncillariesStore.actionCreators.requestExpired(siteId));
dispatch(FaultsStore.actionCreators.requestFaults(siteId));
dispatch(AssetsStore.actionCreators.requestAssetsCount(siteId));
dispatch(LicencesStore.actionCreators.requestLicencesCount(siteId));
dispatch(MaintenancesStore.actionCreators.requestMaintenancesCount(siteId));
dispatch(FaultsStore.actionCreators.requestFaultsCount(siteId));
}
Within a dependant component, included the Site value in the component properties, hooked into the componentDidUpdate lifecycle event. Checked if the Site had changed and then called the thunk action for updating the component state. I preferred this approach as it kept the business logic within the component so the changeSite thunk could now become a simple reducer call. An example of a dependent (site faults) component looks like this:
type FaultsProps =
{
faults: FaultsStore.FaultsItem[],
currentSiteId: number
}
& typeof FaultsStore.actionCreators;
const mapStateToProps = (state: ApplicationState) => {
return {
faults: state.faults?.faults,
currentSiteId: state.sites?.currentSiteId
}
}
class FaultyListContainer extends React.PureComponent<FaultsProps> {
public componentDidMount() {
// First load.
this.props.requestFaults(this.props.currentSiteId);
}
public componentDidUpdate(prevProps: FaultsProps) {
// Update state if site has changed.
if(prevProps.currentSiteId !== this.props.currentSiteId) {
this.props.requestFaults(this.props.currentSiteId);
}
}
public render() {
return React.createElement(FaultsList, {faults: this.props.faults});
}
}
export default connect(
mapStateToProps,
FaultsStore.actionCreators
)(FaultyListContainer as any);
Is #2 the best approach? is there a better way?
I'm creating a form with Angular2 and I created two custom validators for email address field.
The first validator checks for email validity, the second (async) validator checks if email address already exists on database.
In addition I would like to add a third validator for another verification.
Here is my code:
'email': ['', [validateEmail(), thirdValidator()], asyncValidator]
The behaviour that I want is the following:
Only when the first validator validates the control, the second validator should start. And only when the second validator terminates then the third validator can start its validation.
How to reach this?
Validators.compose method should do the job, example:
let formControls = {
'oldPassword': new FormControl({ value: ''}),
'newPassword': new FormControl({ value: ''}, Validators.compose([customValidator1, customValidator2]), customAsyncValidator)
};
Composed validators work simultaneously, meaning we can have multiple errors on the control at the same time (each validator attaches its own error if validation failed). If we need to have only one error on the control at a time, we can 'chain' validators by checking the status of the previous validation before performing next one. Something like this:
let customValidator2 = (ctrl: FormControl): any => {
if(ctrl.hasError('customValidationError1')) {
// there is the error attached by customValidator1,
// skip executing customValidator2 (nullify its error)
return null;
}
let isInvalid = true; // some condition...
return isInvalid ? { customValidationError2: true } : null;
}
This way we can accomplish 'ordering' the validators by their priority for example.
On a Yii2 project, in a user's Edit Info form (inside a modal):
I'm currently figuring out which fields were changed using the jQuery .change() method, and I'm grabbing their value with jQuery's .val() method.
However, I want to do less with JavaScript and do more with Yii's framework.
I can see in the Yii debugger (after clicking into the AJAX POST request) that Yii is smart enough to know which fields were changed -- it's showing SQL queries that only UPDATE the fields that were changed.
What do I need to change in the controller of this action to have Yii include the name of the field changed -- including it's value -- in the AJAX response? (since my goal is to update the main view with the new values)
public function actionUpdateStudentInfo($id)
{
$model = \app\models\StudentSupportStudentInfo::findOne($id);
if ($model === null) {
throw new NotFoundHttpException('The requested page does not exist.');
}
$model->scenario = true ? "update-email" : "update-studentid";
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->renderAjax('_student_support_alert_success');
}
return $this->renderAjax("_edit_student_info",[
"model" => $model,
]);
}
I'm currently returning a static success view.
You can use $model->dirtyAttributes just after load the data to get a $attrib => $value pair array.
http://www.yiiframework.com/doc-2.0/yii-db-baseactiverecord.html#getDirtyAttributes()-detail (this docs says:)
Returns the attribute values that have been modified since they are loaded or saved most recently.
The comparison of new and old values is made for identical values using ===.
public array getDirtyAttributes ( $names = null )
(sorry for formatting, sent by mobile)
I am building a pretty simple online shop in SilverStripe. I am writing a function to remove an item from the cart (order in my case).
My setup:
My endpoint is returning JSON to the view for use in ajax.
public function remove() {
// Get existing order from SESSION
$sessionOrder = Session::get('order');
// Get the product id from POST
$productId = $_POST['product'];
// Remove the product from order object
unset($sessionOrder[$productId]);
// Set the order session value to the updated order
Session::set('order', $sessionOrder);
// Save the session (don't think this is needed, but thought I would try)
Session::save();
// Return object to view
return json_encode(Session::get('order'));
}
My issue:
When I post data to this route, the product gets removed but only temporarily, then next time remove is called, the previous item is back.
Example:
Order object:
{
product-1: {
name: 'Product One'
},
product-2: {
name: 'Product Two'
}
}
When I post to remove product-1 I get the following:
{
product-2: {
name: 'Product Two'
}
}
Which appears to have worked but then I try and remove product-2 with and get this:
{
product-1: {
name: 'Product One'
}
}
The SON OF A B is back! When I retrieve the entire cart, it still contains both.
How do I get the order to stick?
Your expectation is correct, and it should work with the code you wrote. However, the way the session data is managed doesn't work well with data being deleted, because it is not seen as a change of state. Only existing data being edited is seen as such. See Session::recursivelyApply() if you want to know more.
Only way I know is to (unfortunately) emphasized textmanipulate $_SESSION directly before you set the new value for 'order'
public function remove() {
// Get existing order from SESSION
$sessionOrder = Session::get('order');
// Get the product id from POST
$productId = $_POST['product'];
// Remove the product from order object
unset($sessionOrder[$productId]);
if (isset($_SESSION['order'])){
unset($_SESSION['order']);
}
// Set the order session value to the updated order
Session::set('order', $sessionOrder);
// Return object to view
return json_encode(Session::get('order'));
}