Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP MVC form to call specific action and not redirect but update original page

I am using ASP.net MVC 3 for a project, and at a point now where I understand more of it, but also trying to learn differences between it and the WebForms world I have used for so long. Previously in WebForms you would just put the fields out there, add a button, and create an event, and then handle whatever you need to with with the postback.

For example, I have a simple view that shows details about an error. I want to push some of the information about this error to our issue tracker's API. Lets say just the subject and content of the error. I would in HTML do something like:

<form action="@Url.Action("Send")" method="post">
    <input id="subject" name="subject" type="text" value="@Model.subject" />
    <br />
    <input id="content" name="content" type="text" value="@Model.content" />
    <br />
    <input type="submit" value="Send" />
</form>

I found that naming my input ID's to match parameter names in my controller would then let me pass these parameters. This is similar to what you see in this older post by Scott Guthrie.

First of all, I want to call the 'Send' action in my Errors controller, and not my Details one. This actually does call my 'Send' action, but then redirects to localhost/Errors/Send, which I don't want it to.

I want to be able to submit this form, which calls and action and does the work with the remote API, and then update a message on the current page stating that the error has been transferred.

Once the issue had been submitted to the bug tracker, how do I then, for example, show a DIV on the original page passing content back to it (for example, a link to the issue in the issue tracker)?

Update: Here is what I am doing in my controller:

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://localhost/redmine/issues.json");
request.Credentials = new NetworkCredential("username", "password");
request.Method = "POST";
request.ContentType = "application/json";
request.Accept = "application/json";

using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
    writer.Write("'issue': { " +
                      "'project_id': 'project', " +
                      "'subject': 'Test issue'" +
                      "}");
}

WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
string json = "";

using (StreamReader reader = new StreamReader(stream))
{
    json = reader.ReadToEnd();
}

Also, here is what I am doing in my view (simplified, and after help from Phillip)

@model webapp.Models.app_errors

<script type="text/javascript">
 function SendErrors() {    

           alert(@Model); // here I get a 'webapp undefined error'
           alert(Model); // Model is undefined. If I reference @Model.App_name or another value anywhere, works fine in rest of view

        $.ajax({
            type: 'POST', //(probably)
            url: '../SendToRedmine',
            cache: false, //(probably)
            dataType: 'json', //(probably)
            data: @Model,
            success: function(result)
            {
                alert("The error has been transferred");
                //you can also update your divs here with the `result` object, which contains whatever your method returns
            }
            });
    }
</script>

<input type="button" onclick='SendErrors()'/>
like image 265
jmlumpkin Avatar asked Oct 23 '22 21:10

jmlumpkin


1 Answers

In response to your first question, try this overload of Url.Action:

Url.Action("ActionName","ControllerName")

And your second question: You'll want to do it via AJAX.

Basically, for the first time the page is loaded, return whatever you want to display to the screen. Then, have an ajax function of this form:

<script type="text/javascript">
    function SendErrorsOrWhatever()
    {
        dummy = 'error: myError, someOtherProperty = property';  //this of course assumes that 'myError' and 'property' exist
        $.ajax({
        type: 'GET', //i changed this because it actually probably better suits the nature of your request
        url: '../Details/Send',
        cache: false, //(probably)
        dataType: 'json', //(probably)
        data: dummy,  //json object with any data you might want to use
        success: function(result)
        {
            alert("The error has been transferred");
            //you can also update your divs here with the `result` object, which contains whatever your method returns
        }
        });
    }
</script>

A few things to note: 1) The url is automatically appended to include the data from data. 2) Your action method now needs to accept a parameter. There are many ways to go about this. I have added an example of what your action method might look like in the code below.

and then your button's onclick event will call that function, like this:

<input type="button" onclick='SendErrorsOrWhatever()'/>

What happens here is that when your button is clicked, Ajax will asynchronously (by default) hit your action method, and your action method will do whatever it needs to do with the errors, and then when it is finished, the success callback will be hit.

EDIT: now, your action might look something like this:

[AcceptVerbs(HTTP.Get)]
public static Error GetErrors(Error error)
{
    //do all your processing stuff
}

Now, this assumes that the JSon object dummy has the same fields as the Error class. If so, MVC will do automatic data binding on it. You can also use a more generic FormCollection for the parameter as well. Really, you can use whatever you want, but you'll want to wrap whatever you want in a JSon object.

Edit-- for your last question, this should work:

Add the following extension method to your app:

public static class JsonExtensions
{
    public static string ToJson(this Object obj)
    {
        return new JavaScriptSerializer().Serialize(obj);
    }
}

Or if you want, you can just add a ToJson() method to your model class, and then:

var model = @Model.ToJson();

in the js right before the ajax call. Then use the model variable for your data parameter.

like image 78
Phillip Schmidt Avatar answered Oct 29 '22 22:10

Phillip Schmidt