0

I have a situation where I have a ViewModel that has a number of fields (As an example):

public class myVM
{
     [Required(errorMessage="SomeMessage")]
     public string Name;

     [Required(errorMessage="SomeMessage")]
     public string Address;

     [Required(errorMessage="SomeMessage")]
     public string PhoneNumber;
}

In the real world its a bit more complicated.

The user is given a choice of what they are on the page to edit, Name Info, Address Info, Phone Number Info etc.

Each of those options corresponds to a partial view that is loaded with the form for each section.

The issue that I have is that if a user goes on and selects that they want to just edit the Name section, so only the name form is rendered they still get the validation messages for the Address and Phone numbers...

I know WHY this is happening, just not sure what the best way to get round it is?

UPDATE.

Noted that the above is unclear, these form parts (Partial views) are all loaded into one BIG form.

Something like this :

@using (Html.BeginForm())
{

    @Html.ValidationSummary(false)

    Html.RenderPartial("Partials/_AddressForm", Model.Address);
    Html.RenderPartial("Partials/_Phonenumber", Model.PhoneNumber);

    <input type="submit" value="SAVE"/>

}

The resulting form is posted back into one action which does a ModelState.IsValid - Which of course validates the WHOLE model.

5NRF
  • 401
  • 3
  • 12
  • 1
    create separate Vm for each case. – teo van kot Jul 11 '16 at 17:33
  • I was thinking along those lines, however what may not have been clear is that these are all elements of the same form. Ill update the example. – 5NRF Jul 11 '16 at 17:36
  • That's not a good practice to write like you do. Pretty much complete overview of validation problems in MVC you can [read here](http://stackoverflow.com/q/28090143/1849444). – teo van kot Jul 11 '16 at 17:49
  • Thats what I am asking.. I have a requirement to allow users to select which parts of a form that they are going to fill in and then validate it based on that selection. Thats what i was asking - how can I achieve this? I know its not best practice, but it cant be impossible? Maybe not the way that I have shown above - any ideas how this could be achieved? – 5NRF Jul 11 '16 at 17:53
  • it's better to create separate ViewModels as i already mention. Alternative - get rid of validation with attributes and validate you model in controller custom way – teo van kot Jul 11 '16 at 17:55
  • I understand your suggestion of using different view models, However I dont see how to implement this, I have one view with multiple partial views which make up the form with one action that the form posts back to. The example above is only for illustrative purposes, the actual form has 20+ fields, not really wanting to manually validate each one server side unless I have no other option. – 5NRF Jul 11 '16 at 18:00

1 Answers1

1

In Webforms you would use Validation groups where you have a bunch of form controls that all need to be validated depending on different buttons being pressed.

You can achieve this with a single view model by implementing a custom validation annotation like this :

public class RequiredIfISaySo : ValidationAttribute//, IClientValidatable
{
    public RequiredIfISaySo(int RequiredReason)
    {
        _reqReason = RequiredReason;
    }

    private RequiredAttribute _reqAttribute = new RequiredAttribute();
    private int _reqReason;

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (_reqReason == 1)
        { 
            if (!_reqAttribute.IsValid(value))
            {
                return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName });
            }
        }

        return ValidationResult.Success;
    }
}

You can then annotate your model like this:

 [RequiredIfISaySo(3, ErrorMessage = "NAME REQUIRED")]
    public string Name { get; set; }

    [RequiredIfISaySo(2, ErrorMessage = "PHONE REQUIRED")]
    public string Phone { get; set; }

    [RequiredIfISaySo(1, ErrorMessage ="ADDRESS REQUIRED")]
    public string Address { get; set; }

I'd probably change that int to something easier to read, and change it so that you can pass an array rather than a single value (that way you can have overlap in the validation (ie validate anything where 1 or 2 is passed.

For bonus points you can also hook this up to the client side validation by implementing the (commented out) IClientValidatable interface.

D3vy
  • 831
  • 7
  • 19