views:

51

answers:

3

Early yesterday, the following validation notice was working correctly. Then we converted the Index view where the request for this action originates to use a partial view, and the Delete ActionLink is now inside that partial view, and now the string argument to the JavaScript method call is rendered literally and as the only content on the 'destination' Delete view.

    public ActionResult Delete(int id)
    {
        var perm = JobCardService.CheckBusinessRules(id);
        if (!string.IsNullOrEmpty(perm))
        {
            return JavaScript("NotifyFailure('You may not delete this Installation: " + perm + "', false, 2000);");
        }
        JobCardViewData viewData = ViewDataFactory.CreateBaseViewData<JobCardViewData>("Installation List");
        return View("Delete", viewData);
    }

The Filter action returns the partial view, and is requested as below:

<div class="editor-field">
    <% using (Ajax.BeginForm("Filter", "JobCard", new AjaxOptions { UpdateTargetId = "jobList" }))
       { %>
    <%= Html.DropDownListFor(model => model.RequesterId, new SelectList(Model.RequesterList, "RequesterID", "CompanyName", Model.RequesterId), new { onchange = "$('#Select_Save').click();" })%>
    <input id="Select_Save" type="submit" value="Save" style="display: none" />
    <% 
        }%>
</div>
+1  A: 

Refer to the comment of this question http://stackoverflow.com/questions/1312408/asp-net-mvc-javascript-actionresult/1312455#1312455

The other aspect is that using this return type is considered to be an anti-pattern and should be avoided. The suggested approach is to use a Json result.

  1. http://stackoverflow.com/questions/1677325/working-example-for-javascriptresult-in-asp-net-mvc/1677518#1677518
  2. http://devlicio.us/blogs/billy_mccafferty/archive/2009/02/07/beware-of-asp-net-mvc-javascriptresult.aspx

Edit:

Since javascript is being returned from the Controller, an alternative would be to send script back to the browser that redirects the user to the correct page.

   public ActionResult Delete(int id)
    {
        var perm = JobCardService.CheckBusinessRules(id);
        if (!string.IsNullOrEmpty(perm))
        {
            return JavaScript("NotifyFailure('You may not delete this Installation: " + perm + "', false, 2000);");
        }
        // you may need to do a bit more to create a URL in the form of http://...
        UrlHelper u = new UrlHelper(this.ControllerContext.RequestContext);
        string url = u.Action("ActionName","ControllerName", new{id=1}); // the new Action will return the delete view
        return Javascript(String.Format("window.location =""{0}"",url);
    }

Refer to http://stackoverflow.com/questions/699782/creating-a-url-in-the-controller-net-mvc for more on the UrlHelper.

Ahmad
@Ahmad, wow, talk about a can of worms. Everyone is citing McCafferty's blog, but he offers no alternative, which I think is a poor show. Your first link is very enlightening though, thanks.
ProfK
A: 

This may not be the best way to do this, but every other answer I have come across has required extensive rework to achieve. This requires one small, simple change and works exactly as required. All I had to do was change the Delete action link from this:

<%= Html.ActionLink("Delete", "Delete", new { id = item.InstallationDBNumber }) %>

to this:

<%= Ajax.ActionLink("Delete", "Delete", new { id = item.InstallationDBNumber }, new AjaxOptions { HttpMethod = "Get" }) %>
ProfK
A get should not change data. Google (for public websites) or Lucene (internal site) might scan your website with some bad sideefects.Better perform a post-redirect-get. I see that you check rights in the action but its still not a good idea.
Malcolm Frexner
Correct me if I am wrong, although this will return a complete page/response from the server , nothing will be updated on the screen?
Ahmad
The get doesn't change data. It checks whether the Delete may happen, and if not, executes a JavaScript function telling the user that. @Ahmad, when I return the JavaScriptResult, I don't need anything updated on the screen. This is why all the other, 'better', ways of doing this weren't. The model side 'permanent' delete happens in the post override of the Delete action, called from the Delete view.
ProfK
@ProfK - sorry, I was actually referring to `return View("Delete", viewData);` in the case when user has permissions.. this view does not get updated on the screen?
Ahmad
Ooops, I dont know if I checked that!
ProfK
@Profk - i have updated my answer
Ahmad
@Ahmad, it's the 'return JavaScript("NotifyFailure' that needs work, not the 'return View("Delete'. The latter has always worked perfectly.
ProfK
+1  A: 

Hey,

If the action method is responsible for returning a view, seems like the response shouldn't be returning a JavaScript if in error because no underlying ASP.NET page would be served, which means that you would see it as literal text.

Consider assigning the method call to ViewData, and in your client do something like:

<% if (ViewData["X"] != null) { %>
    <script type="text/javascript">
        <%= ViewData["X"] %>
    </script>
<% } %>

Calling VIewData["X"] like I do should render the JavaScript code directly and get directly executed when parsed.

I think that might work; you can always utilize other mechanisms like eval to parse content, or do whatever else you might need....

Brian
Thanks Brian, this looks like something I can use, rather than beating the JavaScript result into submission.
ProfK