How do I display only one validation error in form? - asp.net-core

I have several input fields in registration form.
For example, there are 5 fields. 'Email' and "Phone Number" fields are wrong, I do not want to display both validation errors. I only want to check "Email" field and display Email error, if it will be correctly written on second try, only then 'Password' error message can appear.
Can I accomplish it with server-side validation only?
Screenshot: Both validation errors are displayed at the same time.

You can dynamically modify the ModelState and check the errors :
if (ModelState.IsValid)
{
....
}
else
{
var flag = false;
foreach (var modelState in ViewData.ModelState.Values)
{
if (flag)
{
modelState.Errors.Clear();
}
if (modelState.Errors.Count >0)
{
flag = true;
}
if (modelState.Errors.Count>1)
{
var firstError = modelState.Errors.First();
modelState.Errors.Clear();
modelState.Errors.Add(firstError);
}
}
}
return View("index", movie);

Set maximum model validation errors to 1 in stratup, the validation process stops when max number is reached (200 by default):
services.AddMvc(options =>
{
options.MaxModelValidationErrors = 1;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
but in this case it will stop on the first error even if there is more than one validation error on the same property (e.g. password length is not valid, password must contain upper case letter, etc...).
If you need to show all errors at once for each property you will need another solution.
ref: https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-2.2

Related

Validate Form on Change ONLY

Because much of our imported data technically has validation errors, users are unable to update fields without first correcting previously entered bad data. This wouldn't be a problem except that many times this user doesn't have the information needed to enter a correct value into that field but we still need to save their update.
Is it possible to disable the validate on submit for a DynamicForm?
Is it possible to disable the validate on submit for a DynamicForm?
there's a disableValidation attribute, it disables client-side validators.
The best solution I could find thus far.
I'm disabling validation and overridding getValues, which is called as part of saveData so I manually parse through any fields and look for errors. If I find an error I remove it from the return value and store it under the valuesManager.invalidatedFields.
If a field had an error it will not be included in the save, but because the server will return the original value I had to override setValues as well to prevent your (bad) change from being overridden.
Also, because getValues is called on initial load it validates on load as well.
isc.ValuesManager.create({
disableValidation: true,
invalidatedFields: {},
setValues: function(values){
console.log("setting values..", this.invalidatedFields);
for (var key in this.invalidatedFields) {
if (this.invalidatedFields.hasOwnProperty(key)) {
values[key] = this.invalidatedFields[key];
}
}
this.Super("setValues", arguments);
},
getValues: function () {
this.invalidatedFields = [];
var data = this.Super("getValues");
for (var key in data) {
if (data.hasOwnProperty(key)) {
var form = this.getMemberForField(key);
if (form && !form.getField(key).validate()) {
console.log(key + " failed validation", data[key]);
this.invalidatedFields[key] = data[key];
delete data[key];
}
}
}
return data;
}
});

adminhtml/session in Magento addError not showing after redirect

I am working on a custom magento admin module with grids. When you add a new entry, I perform custom validation and throw an error (when & if it occurs) using Mage::getSingleton('adminhtml/session')->addError() method.
The error message I set does not appear, when I redirect back to the edit form.
This is my save action on the grid controller:
public function saveAction()
{
// Look For HTTP Post
if ($data = $this->getRequest()->getPost())
{
// Load Data
$manualOrderSyncModel = Mage::getModel('mycompany_mymodule/manualordersync')
->setData($data)
->setId($this->getRequest()->getParam('id'));
// Anticipate Errors
try
{
// Get If Order Number Is Valid
$order = Mage::getModel('sales/order')->load($manualOrderSyncModel->getOrderNumber(), 'increment_id');
if (null === $order->getId())
throw new Exception('No such order exists in the system. Check that order number.');
// Check If This Order Already Exists In Queue
$existingManualOrderSyncModel = Mage::getModel('mycompany_mymodule/manualordersync')
->load($manualOrderSyncModel->getOrderNumber(), 'order_number');
if (null !== $existingManualOrderSyncModel->getId())
{
// Update Existing Entry
$existingManualOrderSyncModel
->setCreatedAt(now())
->setCreatedBy(Mage::getSingleton('admin/session')->getUser()->getUsername())
->setIsSynced(Mycompany_Mymodule_Model_Yesno::NO)
->save();
}
else
{
// Update Timestamps
if ($manualOrderSyncModel->getCreatedAt() == NULL) {
$manualOrderSyncModel
->setCreatedAt(now())
->setCreatedBy(Mage::getSingleton('admin/session')->getUser()->getUsername());
}
$manualOrderSyncModel->save();
}
// Set Success
Mage::getSingleton('adminhtml/session')->addSuccess($this->__('Manual order sync updated.'));
Mage::getSingleton('adminhtml/session')->setManualordersyncData(false);
// Handle Redirect
$this->_redirect('*/*/');
return;
}
catch (Exception $e)
{
// Error
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
Mage::getSingleton('adminhtml/session')->setManualordersyncData($data);
$this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
return;
}
}
// Error
Mage::getSingleton('adminhtml/session')->addError($this->__('Invalid request - unable to find manual order sync to save.'));
$this->_redirect('*/*/');
}
I have noticed, the issue only occurs when I do this:
// Error
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
Mage::getSingleton('adminhtml/session')->setManualordersyncData($data);
$this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
return;
However, If set error and redirect back to grid like this, the error message shows:
// Error
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
Mage::getSingleton('adminhtml/session')->setManualordersyncData($data);
$this->_redirect('*/*/');
return;
This is not ideal because I am no longer in the edit form and I have lost the old data from the form. Any ideas on how to fix this?
Experiencing exactly this issue myself, disappointing that this question hasn't received any replies
The reason is that your edit page is not configured to display the session messages. Instead the message persists until the first time it is displayed, and can even bulk up with multiple "copies" of the same message if you keep trying over and over.
The answer is to make sure that your controller and layout is outputting the messages.
The bare minimum required is the following lines in your controller:
$this->loadLayout();
// other code goes here...
$this->_initLayoutMessages('adminhtml/session'); // <--- this line is key
$this->renderLayout();
If you are using a session other than the adminhtml/session, then init those messages instead.

How to return error on shipping step using getOrderShippingCost()

I am working on a carrier module. Delivery price is dynamically fetched from remote server.
After that price is included in order details using getOrderShippingCost() method in modulename.php.
So, when customer sets a correct address, everything works fine, price is calculated properly.
But if there is an error in any address field, for example zipcode is not found, price is just set to 0.
Instead of having 0 I would like to insert a note about what field is wrong and block carrier, but not hide it.
I can identify what field is wrong from response of remote server, but how do I display this information on shipping step of order process?
At the moment just I use return false if there is an error. So carrier is just not shown.
Here is the basic code scheme I am using right now:
public function getOrderShippingCost($params)
{
...
if (no errors found)
return $ret['total'];
else
return false;
// instead of return false I would need something like
// Tools::displayError('Error text'), or trigger a JS event
}
PS 1.5.4.1
If somebody else needs this, here is how I managed to display the warning message:
public function getOrderShippingCost($params)
{
...
//error is defined as public variable
$this->carrierError = $ret['errormsg'];
if (no errors found)
return $ret['total'];
else
return false;
// when false is returned, carrier is not displayed, but warning message is displayed using hookDisplayHeader
}
public function hookDisplayHeader($params)
{
if (isset($this->carrierError) &&
Tools::getValue('controller') == 'order' &&
Tools::getValue('step') == '2')
{
//running JS do display a warning message that carrier may be available if you fix the wrong field
...
}
}

Saving data with cakephp won't work

I'm trying to load, edit and save a record with CakePHP 2.0 but I get a generic error during the save method that don't help me to understand where is the problem.
if I try with debug($this->User->invalidFields()); I get an empty array, but I get false from $this->User->save() condition.
Here is the controller action where I get the error:
public function activate ($code = false) {
if (!empty ($code)) {
// if I printr $user I get the right user
$user = $this->User->find('first', array('activation_key' => $code));
if (!empty($user)) {
$this->User->set(array (
'activation_key' => null,
'active' => 1
));
if ($this->User->save()) {
$this->render('activation_successful');
} else {
// I get this error
$this->set('status', 'Save error message');
$this->set('user_data', $user);
$this->render('activation_fail');
}
debug($this->User->invalidFields());
} else {
$this->set('status', 'Account not found for this key');
$this->render('activation_fail');
}
} else {
$this->set('status', 'Empty key');
$this->render('activation_fail');
}
}
When I try the action test.com/users/activate/hashedkey I get the activation_fail template page with Save error message message.
If I printr the $user var I get the right user from cake's find method.
Where I'm wrong?
I think the problem may be in the way you're querying for the User record. When you do this:
$user = $this->User->find('first', array('activation_key' => $code));
The variable $user is populated with the User record as an array. You check to ensure it's not empty, then proceed; but the problem is that $this->User hasn't been populated. I think if you tried debug($this->User->id) it would be empty. The read() method works the way you're thinking.
You could try using the ID from that $user array to set the Model ID first, like so:
if (!empty($user)) {
$this->User->id = $user['User']['id']; // ensure the Model has the ID to use
$this->User->set(array (
'activation_key' => null,
'active' => 1
));
if ($this->User->save()) {
...
Edit: Well another possible approach is to use the $user array instead of modifying the current model. You said that you get back a valid user if you debug($user), so if that's true you can do something like this:
if (!empty($user)) {
$user['User']['activation_key'] = null;
$user['User']['active'] = 1;
if ($this->User->save($user)) {
...
This method works in the same way as receiving form data from $this->request->data, and is described on the Saving Your Data part of the book.
I'm curious though if there's another part of your setup that's getting in the way. Can other parts of your app write to the database properly? You should also check to make sure you aren't having validation errors, like their example:
<?php
if ($this->Recipe->save($this->request->data)) {
// handle the success.
}
debug($this->Recipe->validationErrors);

How to validate >1 field at a time, in a Zend sub-form?

I've created a 3 screen "wizard" using the Zend_Form_SubForm example from the online reference documentation.
The requirement I'm having trouble meeting is this:
If fields 1, 2, & 3 of the first screen are already in the database, notify the user that they are trying to add a duplicate record. Each of those fields has their own validators. Somehow I need to add this "group validator".
So, at its most basic level, I'm trying to do:
if($field_1_not_in_db && $field_2_not_in_db && $field_3_not_in_db){
return true;//validation OK
} else {
return false;//invalid data
}
I am coming up against several issues, though:
1) Because it applies to multiple fields, I don't know which field to attach it to. Error messages appear beside the field they are attached to, so this is important... unless I can get these "multi-field validator" errors to appear at the top of the screen, which would be ideal.
2) My validator is only receiving a single value (the value of the field I attach it to, not the values of the multiple fields it is supposed to validate).
3) I provide a link to the original (non-duplicate) record in the error message, but it escapes the link, and I can't figure out how to get around that.
The setup I'm currently using (below) actually executes fine, but NewPlace validator receives $_POST['city_fk'] as $fields, instead of the desired group of posted values.
$city_fk = new Zend_Form_Element_Select('city_fk');
$cities = array();
$city_fk->setMultiOptions($cities)
->setLabel('City')
->setDescription('The city this place is in')
->setRequired(true);
$v = array(
'place_is_unique' => array(
'NewPlace',
'fields' => array('place_name','phone_number','phone_extension','street','post_code_name'),
)
);
$city_fk->addValidators($v);
$addressSubForm->addElement($city_fk);
class My_Validate_NewPlace extends Zend_Validate_Abstract
{
public function isValid($fields)
{
$result = false;
if(!$result)
{
$this->_error('sorry, this is duplicate data. see it here');
return false;
}
return true;
}
}
This won't help you decide which field to attach the validation to, but...
There is a thing called a "validation context" that helps.
When you create your custom validator or form IF you specify a second optional parameter ($context = null), then Zend will auto-populate this with the entire array of posted data, which you can use to incorporate other fields values into your validation. Here's a very basic example:
$city_name = new Zend_Form_Element_Text('city_name');
$place_name = new Zend_Form_Element_Text('place_name');
$place_name->addValidator('NewPlace');
class My_Validate_NewPlace extends Zend_Validate_Abstract
{
public function isValid($value, **$context = null**)
{
if(trim($value)!='' && trim($context['city_name']) != '')
{
return true;
}
return false;
}
}