views:

120

answers:

2

I'm developing a web app with ASP.NET MVC 2 (.NET 4.0), and I've run into a difficult problem.

I've got the following code in a partial view:

<% using (Ajax.BeginForm("CompleteTask", "Agenda", new AjaxOptions {HttpMethod = "POST"})) { %>
    <%: Html.EditorFor(x => x.Remarks) %>
    <%: Html.HiddenFor(x => x.TaskId) %>
    <%: Html.HiddenFor(x => x.AgendaId) %>

    <% if (Model.RequiresApproval) { %>
        <input type="image" name="Result" value="0" src="../../Content/Icons/thumbs_up.png" />
        <input type="image" name="Result" value="1" src="../../Content/Icons/thumbs_down.png" />
    <% } else { %>
        <input type="image" name="Result" value="0" src="../../Content/Icons/accept.png" />
    <% } %>
<% } %>

The following parameters are posted:

  • AgendaId - 1046
  • Remarks - sample remarks
  • Result.x - 8
  • Result.y - 8
  • TaskId - 0
  • X-Requested-With - XMLHttpRequest

I was expecting the following:

  • AgendaId - 1046
  • Remarks - sample remarks
  • Result - 0 or 1
  • TaskId - 0
  • X-Requested-With - XMLHttpRequest

The code seemed to work fine with Html.BeginForm(), but that won't suffice as I need to handle JSON results.

Can someone shed some light on what's going wrong? Thanks!


NOTE: I should also note that switching to a "submit" type attribute (from the "image" type attribute) seems to work as well, but I need to use an image submit. I'm thinking this might be a bug in the ASP.NET MVC JavaScript code...

A: 

The HTML spec only requires that the xy coordinates of the click event on the image are sent to the post, so that's why you are seeing the Results.x and Results.y.

I'd try to just give the different image inputs different names and base my back end logic on what name came over in post for a quick workaround

curtisk
Thanks for your suggestion. My only concern is, if I use different names, won't I still get back ImageInputName.x and ImageInputName.y?
Jon Nadal
This is entirely off the cuff, but if you have different names then you know which was clicked "thumbs_up.x" in the post versus "thumbs_down.x" then you can act accordingly
curtisk
curtisk is right. I believe it will post the button that was clicked...
Bryce Fischer
Unfortunately, the model won't be bound correctly. The ".x" will throw it off.
Jon Nadal
A: 

I came up with a work-around that maintains model binding. Add an extension method such as the following:

public static MvcHtmlString AjaxCapableImageSubmit(this HtmlHelper html, string name, object value, string iconSrc, string cssClass = null, string onClick = null)
{
    var style = string.Format("background: url({0}) no-repeat;", iconSrc);

    var input = new TagBuilder("input");
    input.AddCssClass("image-submit-button");
    input.MergeAttribute("type", "submit");
    input.MergeAttribute("name", name);
    input.MergeAttribute("value", value.ToString());
    input.MergeAttribute("style", style);
    if (cssClass != null) input.AddCssClass(cssClass);
    if (onClick != null) input.MergeAttribute("onclick", onClick);

    return MvcHtmlString.Create(input.ToString(TagRenderMode.SelfClosing));
}

Then add something like the following to your primary style sheet:

.image-submit-button {
    border: none;
    color: transparent;
    cursor: pointer;
}
.icon {
    height: 16px;
    width: 16px;
}

Here's an example:

<%: Html.AjaxCapableImageSubmit("Result", 0, "../../Content/Icons/thumbs_up.png", cssClass: "icon", onClick: "return confirm('Accept?')") %>
<%: Html.AjaxCapableImageSubmit("Result", 1, "../../Content/Icons/thumbs_down.png", cssClass: "icon", onClick: "return confirm('Decline?')") %>

Please post comments with drawbacks to this approach if anything comes to mind. Thanks!

Jon Nadal