0

I have a Model that as one of its properties has a list of child models. In my view each child model is validated separately using custom client side validation. Everything is being validated correctly, and the correct validation messages are being displayed.

The only thing is, I have a lot of these child models and editors on screen at a time, and need to make the invalid editors stand out a bit more, by giving the surrounding div a red outline for example (not just the input as is default).

So I need to detect the validity of the child models within their partials views and append the appropriate CSS class to the div. I have read in several places that this can be done with Html.ViewData.ModelState.IsValid but this seems to pick up on whether or not the ParentModel and ALL the ChildModels are valid or not.

Here is an example of my ParentModel, ChildModel, View for the parent, and partial view for the ChildModels:

public class ChildModel
{
    public Guid Child_Id { get; set; }

    public List<Guid> Selected_Ids { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> Errors = new List<ValidationResult>();

        if (this.Selected_Ids == null || !this.Selected_Ids.Any())
        {
            Errors.Add(new ValidationResult("You must select at least one id.", new List<string> { "Selected_Ids" }));
        }

        return Errors;
    }
}

public class ParentModel
{
    public Guid Parent_Id { get; set; }

    public List<ChildModel> Children { get; set; }

    public List<Guid> Available_Ids { get; set; }
}

@* View *@
@model ParentModel  
<div>
    @using(Html.BeginForm())
    {
        @Html.HiddenFor(m => m.Parent_Id)

        @Html.EditorFor(m => m.Children, new { Model.Available_Ids })

        <button type="submit">Save</button>
    }
</div>

@* Partial View / Editor Template *@
@model ChildModel
@ {
    List<Guid> Available_Ids = (List<Guid>)ViewData["Available_Ids"];
}
<div class='child_model @(Html.ViewData.ModelState.IsValid ? string.Empty : "Invalid")'>
    @Html.HiddenFor(m => m.Child_Id)

    @foreach(Guid Available_Id in Available_Ids)
    {
        @Html.CheckBoxFor(m => m.Selected_Ids, Available_Id.ToString())
    }
</div>
Ben
  • 5,525
  • 8
  • 42
  • 66

1 Answers1

0

You could try using the following to test a particular Field in the Model

Html.ViewData.ModelState.IsValidField("Child_Id")

It will return whether given field is valid or not, I'm unsure how you go within a collection, I've not used it in that way before.

Mark
  • 2,454
  • 4
  • 26
  • 29
  • Same thing I'm afraid, it seems to depend on the validity of all instances of that field. eg if all `Selected_Ids` across all the `ChildModels` are valid it returns true, and false if any of them are not valid – Ben Mar 18 '14 at 08:47
  • Try adding a field to the model which is purely for validation of that particular object. Then each object will have its own field. There is no problem adding field to your viewmodel for this purpose its what the viewmodel is for. Should be able to loop through collection then and set error field when theres an error. – Mark Mar 18 '14 at 09:08
  • If I am understanding your suggestion correctly, then that is exactly what I have done since posting this question, but it feels like a bodge. Just to clarify, my models were created by entity framework, so I added the validation to a partial class, and I have also now added a `bool Is_Valid` property to the `ChildModel` which gets set to false when the validation fails. I was really hoping that there was a way of doing this using the `ModelState` or something similar, so I will leave this open a bit longer. – Ben Mar 18 '14 at 09:20
  • Personally i would advise against using a model directly from the orm and keep your viewmodel completely separate to your data model. Its less flexible and also gives you the mindset you currently have ie. Limiting what you put into your viewmodel your viewmodel is used to show and manipulate the view only not limits it use due to other constraints. Separate out your data model then use a tool like automapper to map between datamodel and viewmodel it more work but separates concerns which is the whole point of mvc. – Mark Mar 18 '14 at 09:39