nick gowdy
nick gowdy

Reputation: 6521

MVC 4 multiple buttons in form - why isn't this code working

I am trying to use a variation of the code from this page:

Multiple button in MVC

But everytime I click on the buttons it goes to the index actionresult method and not one of the button methods. Index is the view name but the button clicks are happening in a partial view called "P_NewPersonForm.cshtml"

P_NewPersonForm.cshtml

  @using (Html.BeginForm())
    {

        <div id="divClaimType">
            @Html.Label("Claim type:")
            @Html.DropDownListFor(m => m.modelClaim.ClaimType, new List<SelectListItem>
                     {
                        new SelectListItem{ Text="Legal", Value = "Legal" }, 
                        new SelectListItem{ Text="Immigration", Value = "Immigration" },
                        new SelectListItem{ Text="Housing", Value = "Housing" }
                     })
        </div>
        <div id="divClaimStatus" style="padding: 5px;">

        @foreach(var item in Model.LinkerStatusOfClaim)
        {
            @Html.Label("Claim status:")
            @Html.DropDownListFor(m => m.LinkerStatusOfClaim[0].ClaimStatusID, new SelectList(Model.modelClaimStatus, "ClaimStatusID", "ClaimStatus"))

            @Html.LabelFor(m => m.LinkerStatusOfClaim[0].Notes)
            @Html.TextAreaFor(m => m.LinkerStatusOfClaim[0].Notes)

            @Html.LabelFor(m => m.LinkerStatusOfClaim[0].StartDate)
            @Html.TextBoxFor(m => m.LinkerStatusOfClaim[0].StartDate, new { @id = "datepicker", @Value = DateTime.Now, @readonly = true, Style = "background:#cccccc;" })

            <br />
            @Html.ValidationMessageFor(model => model.LinkerStatusOfClaim[0].StartDate)
            <br />
        }
              <input type="submit" value="Add another status to this claim..." name="action:add"/>
              <input type="submit" value="Delete status." name="action:remove"/>
            @*  @Ajax.ActionLink("Add another status to this claim...", "AddClaim", "Client", new AjaxOptions { HttpMethod = "POST"})*@
        </div>
    }
</div>

I have one button for adding to the collection of claims and another to remove one from the collection.

ClientController

public ActionResult Index()
    {
        var Model = new modelPersonClaim();
        // Add one item to model collection by default
        LinkerStatusOfClaim LinkerStatusOfClaim = new LinkerStatusOfClaim();
        Model.LinkerStatusOfClaim.Add(LinkerStatusOfClaim);
        DataLayer.RepositoryClient RC = new RepositoryClient();

        Model.isValidModel = true;
        RC.GetClaimTypes(Model, PersonTypes.NewPerson.ToString());
        return View(Model);
    }

    [HttpPost]
    public ActionResult P_NewPersonForm(modelPersonClaim Model)
    {
        DataLayer.RepositoryClient RC = new RepositoryClient();
        RC.GetClaimTypes(Model, PersonTypes.NewPerson.ToString());

        Model.isValidModel = ModelState.IsValid;
        if (ModelState.IsValid)
        {
            RC.CreatePerson(Model);
            Model.SuccessfulInsert = true;
            Model.InsertString = "Person data has been successfully inserted into the database.";

            if (Model.modelClaim.ClaimMade)
            {
                RC.CreateClaim(Model);
            }
        }
        else
        {
            Model.SuccessfulInsert = false;
            Model.InsertString = "Person data could not be inserted into the database. Missing key fields.";
        }
        return View("Index", Model);
    }


    [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited = true)]
    public class MultiButtonAttribute : ActionNameSelectorAttribute
    {
        public string Name { get; set; }
        public string Argument { get; set; }

        public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
        {
            var isValidName = false;
            var keyValue = string.Format("{0}:{1}", Name, Argument);
            var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

            if (value != null)
            {
                controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
                isValidName = true;
            }

            return isValidName;
        }
    }

    [HttpPost]
    [MultiButtonAttribute(Name = "action", Argument = "Add another status to this claim...")]
    public ActionResult AddClaimStatus(modelPersonClaim Model)
    {
        Model.LinkerStatusOfClaim.Insert(Model.LinkerStatusOfClaim.Count, new LinkerStatusOfClaim());
        return View("Index", Model);
    }

    [HttpPost]
    [MultiButtonAttribute(Name = "action", Argument = "Delete status.")]
    public ActionResult RemoveClaimStatus(modelPersonClaim Model)
    {
        // Can't remove IF only 1 
        if (Model.LinkerStatusOfClaim.Count == 1)
        {

        }
        else
        {
            Model.LinkerStatusOfClaim.RemoveAt(Model.LinkerStatusOfClaim.Count);

        }
        return View("Index", Model);  
    }

When I click one the buttons it hits the public override bool IsValidName twice. Once for each button. But then because the action name is always index, it goes to the index method and not one of the button methods.

Does anyone have any ideas how to fix this?

Upvotes: 0

Views: 398

Answers (1)

Marthijn
Marthijn

Reputation: 3392

Something is wrong with this part:

var keyValue = string.Format("{0}:{1}", Name, Argument);
var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

Your attribute is this:

[MultiButtonAttribute(Name = "action", Argument = "Add another status to this claim...")]

So in that case keyValue will become: "action:Add another status to this claim..." while your HTML states: <input type="submit" value="Add another status to this claim..." name="action:add"/>, so I think Argument in your attribute should be add.

Upvotes: 1

Related Questions