0
votes

A little help or advice if any of you can? I have an MVC form (it's actually an Umbraco form/surface controller, but I don't know that that has any bearing on this), the model for which contains a list of objects being used to generate check-boxes using HTML helper methods; see the following post for how I am rendering these and receiving them in my child action: https://stackoverflow.com/a/20687405/1285676

All appears to be working well, except that although all check-boxes are being posted on submit, not all are being picked up by the model received by the ActionResult method in my controller. I have looked at the posted data using the network tools in chrome, and all appears to be ok.. (all check-boxes appear to be being posted back in the same format), so the million dollar question is, what could be preventing some values from being picked up in the model?

Here's a snipet of my form rendering the check-boxes, cut down as the rest should not be relevant (yes there is a submit button in the real thing..):

@model MemberPreferencesVM
@using (Html.BeginUmbracoForm<MemberAccountSurfaceController>("HandleDealerMemberPreferencesAccountUpdate", FormMethod.Post, new { @class = "", @id = "dealer-member-account-preferences-form" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    @for (var j = 0; j < Model.Brands.Count; j++)
    {
        if (Model.Brands[j].Division == Model.Divisions[i].Id.ToString())
        {
            var divisionSelected = Model.Divisions.Any(x => x.Id.ToString() == Model.Brands[j].Division) ? Model.Divisions.FirstOrDefault(x => x.Id.ToString() == Model.Brands[j].Division).Checked : false;
            var checkboxAttr = new Dictionary<string, object> { { "class", "styled" }, { "data-division", Model.Brands[j].Division } };
            var brandSelected = Model.Brands[j].Checked;

            <div class="col-xs-4">
                <label class="option @if (divisionSelected && brandSelected){<text>active</text>}">
                    <img src="@(Model.Brands[j].LogoUrl)" class="center-block" alt="@(Model.Brands[j].Name)" />
                    <span class="checkbox">
                        @Html.HiddenFor(model => model.Brands[j].Id)
                        @Html.HiddenFor(model => model.Brands[j].Name)
                        @Html.CheckBoxFor(model => model.Brands[j].Checked, checkboxAttr)
                    </span>
                </label>
            </div>
        }
    }
}

Slightly cut down version of the model:

public class MemberPreferencesVM: IValidatableObject
{
    public MemberPreferencesVM()
    {
        init();
    }
    private void init()
    {
        Divisions = [Logic to fetch divisions];
        Brands = [Logic to fetch brands];
    }
    public IList<DivisionVM> Divisions { get; set; }
    public IList<BrandVM> Brands { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var pDivisions = new[] { "Divisions" };
        var pBrands = new[] { "Brands" };
        if (!Divisions.Any(x => x.Checked))
        {
            yield return new ValidationResult("Select at least 1 division to view by default", pDivisions);
        }
        if (!Brands.Any(x => x.Checked))
        {
            yield return new ValidationResult("Select at least 1 brand to view by default", pBrands);
        }
    }
}

BrandVM:

public class BrandVM
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string LogoUrl { get; set; }
    public bool Checked { get; set; }
    public string Division { get; set; }
}

The ActionResult:

[ValidateAntiForgeryToken]
[ValidateInput(true)]
[HttpPost]
public ActionResult HandleDealerMemberPreferencesAccountUpdate(MemberPreferencesVM model)
{
    //logic removed as model doesn't arrive will all values so not relevant 
    return CurrentUmbracoPage();
}

The model should contain 24 Brands, it only ever seems to arrive at 'HandleDealerMemberPreferencesAccountUpdate' with 12.

Any help appreciated (am hoping it's something simple where I've slipped up)..

Mark

1
You have to add hidden filed for values that are not part of the form UI and you want to submit them.Aleksandar Toplek
Alas, I have already tried that, but it made no difference... 12 of the 24 are passed in. It also seems to not matter if they are checked or not, the 12 passed in is a mix of various brands associated with various divisions.Mark Johnson
I think there's other stuff going on outside of what you've told us. Are any of the checkboxes being disabled via JavaScript? Of course, then they wouldn't show up when you're looking through the Posted Data. Are all 24 in the data being shown in the Dev Tools?krillgar
Ok, so I have disabled any javascript that had been targeting the check-boxes before posting, and removed anything that might disable them. On submitting the form, I can see the following being posted using the network tab in Chrome's Dev Tools: pastebin linkMark Johnson
@krillgar That was my first thought too.. if no-one is able to spot something obvious then I might have to restart from scratch as I am sure it's something simple I'm missing (I am not the only one who's worked on this, so I have had to dig through lots of scripts etc. to see what else might be wrong, to no avail). I just want to make sure it's not something to do with my html & controller..Mark Johnson

1 Answers

0
votes

Ok, this turned out to be an issue with my data, that shouldn't have been possible.

Stephen Muecke's comment above was indeed correct

You have an if block inside your for loop. If that ever evaluates to false it means you skip an 'indexer' and binding will fail when you submit. by default, collection indexers must start at zero and be consecutive. While you can add an input for the indexer to make this work, you should be using a view model that contains only the objects you need in the view.

Essentially, one of my brands didn't have a division associated with it and so it broke the solution by not being posted to the controller correctly. The code does need refactoring so that this isn't possible, though I have made changes in the CMS to prevent this from happening again.

Hopefully this will help someone else, thanks all for the pointers.