43

I am trying to pass my model to a controller using JQuery/Ajax, I'm not sure how to do this correctly. So far I have tried using Url.Action but the model is blank.

Note: none of the duplicate threads on stackoverflow seem to address using ASP.NET 5 MVC 6.

View:

$("#inpDateCompleted").change(function () {
        var url = '@(Url.Action("IndexPartial", "DashBoard", Model, null))';
        $("#DailyInvoiceItems").load(url);
});

Controller:

 [HttpGet]
 public PartialViewResult IndexPartial(DashBoardViewModel m)
 {
      // Do stuff with my model
      return PartialView("_IndexPartial");
 }
Reafidy
  • 8,240
  • 5
  • 51
  • 83
  • Its a bit unclear what your trying to do. The 3rd parameter of your `Url.Action()` would be the original model when you first generated the view, and if your model contained any properties which are complex objects or collection it would all fail anyway. –  Nov 26 '15 at 22:36
  • @Stephen Muecke I am loading a page that contains a datepicker and some other data based on the model. When I change the datepicker I want to load a partialview on the same page without a refresh which shows the ammended model in another DIV. I thought by passing the model in the URL action's third parameter as you mentioned I would have access to it in the PartialVIewResult above but the model is null. – Reafidy Nov 26 '15 at 22:40
  • 1
    That would only pass the original model (`Url.Action()` is razor code that is parsed on the server before its sent to the view). If your only wanting to send the selected date to the method, use `$("#DailyInvoiceItems").load('@(Url.Action("IndexPartial", "DashBoard")', { date: $(yourdatecontrol).val()); });` and change the method to have a `DateTime date` parameter. –  Nov 26 '15 at 22:46
  • @StephenMuecke, thanks I see why its failing now. Unfortunately I am not just changing the datetimepicker, that's just the trigger to load the partial view. There are lots of textboxes that are based on the model. Is there no way to pass the entire model back? – Reafidy Nov 26 '15 at 22:49
  • 2
    You can use `$('form').serialize()` to serialize all the controls in your form. e.g. `$.post('@(Url.Action("IndexPartial", "DashBoard"), `$('form').serialize()`, function(data) { $("#DailyInvoiceItems").html(data); }); –  Nov 26 '15 at 22:51
  • Ok great, but then how can I get it back to a strongly typed model in my partialviewresult method? – Reafidy Nov 26 '15 at 22:57
  • 1
    Thats what `$('form').serialize()` will do. Your `DashBoardViewModel m` parameter will be correctly bound (assuming you have generated you form controls correctly) –  Nov 26 '15 at 22:59
  • I see, that's cool - thanks. Does that mean that every item of the model must be on the page? Because at the moment the page does not have controls for every item in the model just the ones I'm changing values. – Reafidy Nov 26 '15 at 23:02
  • 1
    Well that means you really should be using a view model (i.e containing only those properties you need in the view), but no, any properties you exclude will just be their default value in the method. –  Nov 26 '15 at 23:05
  • @Reafidy I have provided you with full solution below – Julius Depulla Nov 26 '15 at 23:16
  • If you down-voted, please let me know why so I can fix my post and future questions. – Reafidy Nov 27 '15 at 01:56

4 Answers4

83

Looks like your IndexPartial action method has an argument which is a complex object. If you are passing a a lot of data (complex object), It might be a good idea to convert your action method to a HttpPost action method and use jQuery post to post data to that. GET has limitation on the query string value.

[HttpPost]
public PartialViewResult IndexPartial(DashboardViewModel m)
{
   //May be you want to pass the posted model to the parial view?
   return PartialView("_IndexPartial");
}

Your script should be

var url = "@Url.Action("IndexPartial","YourControllerName")";

var model = { Name :"Shyju", Location:"Detroit"};

$.post(url, model, function(res){
   //res contains the markup returned by the partial view
   //You probably want to set that to some Div.
   $("#SomeDivToShowTheResult").html(res);
});

Assuming Name and Location are properties of your DashboardViewModel class and SomeDivToShowTheResult is the id of a div in your page where you want to load the content coming from the partialview.

Sending complex objects?

You can build more complex object in js if you want. Model binding will work as long as your structure matches with the viewmodel class

var model = { Name :"Shyju", 
              Location:"Detroit", 
              Interests : ["Code","Coffee","Stackoverflow"]
            };

$.ajax({
    type: "POST",
    data: JSON.stringify(model),
    url: url,
    contentType: "application/json"
}).done(function (res) {
    $("#SomeDivToShowTheResult").html(res);
});

For the above js model to be transformed to your method parameter, Your View Model should be like this.

public class DashboardViewModel
{
  public string Name {set;get;}
  public string Location {set;get;}
  public List<string> Interests {set;get;}
}

And in your action method, specify [FromBody]

[HttpPost]
public PartialViewResult IndexPartial([FromBody] DashboardViewModel m)
{
    return PartialView("_IndexPartial",m);
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Shyju
  • 214,206
  • 104
  • 411
  • 497
  • Thanks, I understand regarding the Post/Get, but it appears in your code you are just posting one parameter of the model, is it not possible just to pass the entire model? The entire DashboardVIewModel. – Reafidy Nov 26 '15 at 22:44
  • @ Reafidy See full implementation below – Julius Depulla Nov 26 '15 at 23:12
  • 2
    @Reafidy Cool. Check out http://stackoverflow.com/a/20226220/40521 for a more detailed explanation on posting models to controllers. – Shyju Nov 27 '15 at 02:21
  • Is it possible for jquery to read the model parameters back from the PartialView once it returns? For example, I want to create a new element and read the new Model Id passed back from the controller to add an additional dom element? I know I could include this in the partial view, but what if I want the Id for another section unrelated to the partial view, but with that element id? – Allen Wang Feb 13 '18 at 15:31
15

Use the following JS:

$(document).ready(function () {
    $("#btnsubmit").click(function () {

             $.ajax({
                 type: "POST",
                 url: '/Plan/PlanManage',     //your action
                 data: $('#PlanForm').serialize(),   //your form name.it takes all the values of model               
                 dataType: 'json',
                 success: function (result) {
                     console.log(result);
                 }
             })
        return false;
    });
});

and the following code on your controller:

[HttpPost]
public string PlanManage(Plan objplan)  //model plan
{
}
Imran Saeed
  • 3,414
  • 1
  • 16
  • 27
kavita sharma
  • 169
  • 1
  • 2
  • 2
    Add some explanation to your code so that the answer is more reusable for others. – Imran Saeed Mar 17 '17 at 11:45
  • This technique was amazingly simple and effective for me. I placed the ajax call on an actionlink with javascript, rather than on a submit button. – Dave May 13 '19 at 19:16
8

As suggested in other answers it's probably easiest to "POST" the form data to the controller. If you need to pass an entire Model/Form you can easily do this with serialize() e.g.

$('#myform').on('submit', function(e){
    e.preventDefault();

    var formData = $(this).serialize();

    $.post('/student/update', formData, function(response){
         //Do something with response
    });
});

So your controller could have a view model as the param e.g.

 [HttpPost]
 public JsonResult Update(StudentViewModel studentViewModel)
 {}

Alternatively if you just want to post some specific values you can do:

$('#myform').on('submit', function(e){
    e.preventDefault();

    var studentId = $(this).find('#Student_StudentId');
    var isActive = $(this).find('#Student_IsActive');

    $.post('/my/url', {studentId : studentId, isActive : isActive}, function(response){
         //Do something with response
    });
});

With a controller like:

     [HttpPost]
     public JsonResult Update(int studentId, bool isActive)
     {}
Rob
  • 10,004
  • 5
  • 61
  • 91
7
//C# class

public class DashBoardViewModel 
{
    public int Id { get; set;} 
    public decimal TotalSales { get; set;} 
    public string Url { get; set;} 
     public string MyDate{ get; set;} 
}

//JavaScript file
//Create dashboard.js file
$(document).ready(function () {

    // See the html on the View below
    $('.dashboardUrl').on('click', function(){
        var url = $(this).attr("href"); 
    });

    $("#inpDateCompleted").change(function () {   

        // Construct your view model to send to the controller
        // Pass viewModel to ajax function 

        // Date
        var myDate = $('.myDate').val();

        // IF YOU USE @Html.EditorFor(), the myDate is as below
        var myDate = $('#MyDate').val();
        var viewModel = { Id : 1, TotalSales: 50, Url: url, MyDate: myDate };


        $.ajax({
            type: 'GET',
            dataType: 'json',
            cache: false,
            url: '/Dashboard/IndexPartial',
            data: viewModel ,
            success: function (data, textStatus, jqXHR) {
                //Do Stuff 
                $("#DailyInvoiceItems").html(data.Id);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                //Do Stuff or Nothing
            }
        });

    });
});

//ASP.NET 5 MVC 6 Controller
public class DashboardController {

    [HttpGet]
    public IActionResult IndexPartial(DashBoardViewModel viewModel )
    {
        // Do stuff with my model
        var model = new DashBoardViewModel {  Id = 23 /* Some more results here*/ };
        return Json(model);
    }
}

// MVC View 
// Include jQuerylibrary
// Include dashboard.js 
<script src="~/Scripts/jquery-2.1.3.js"></script>
<script src="~/Scripts/dashboard.js"></script>
// If you want to capture your URL dynamically 

<div>
    <a class="dashboardUrl" href ="@Url.Action("IndexPartial","Dashboard")"> LinkText </a>
</div>
<div>
    <input class="myDate" type="text"/>
//OR
   @Html.EditorFor(model => model.MyDate) 
</div>
Julius Depulla
  • 1,493
  • 1
  • 12
  • 27
  • @NEDian Thanks for Indentation – Julius Depulla Nov 26 '15 at 23:30
  • Thanks, using 'var viewModel = { Id : 1, MyDate:};' how do I get a value from a textbox on the page into the mydate parameter? – Reafidy Nov 26 '15 at 23:33
  • Sorry I was meaning how do I get a date from a textbox into the viewModel parameter? – Reafidy Nov 26 '15 at 23:42
  • Great, and sorry - once last question, how do I get the results of the ajax query to load in the "#DailyInvoiceItems" DIV? – Reafidy Nov 26 '15 at 23:53
  • Hope you can see the code changes and how you handle the result on success of ajax call – Julius Depulla Nov 27 '15 at 00:07
  • Using your code I can see the IndexPartial is fired and has the correct date but the page does not load the partial view in the DIV DailyInvoiceItems. It does not seem to do anything. – Reafidy Nov 27 '15 at 00:13
  • Using "text" did not work, I added my full controller code to help make sense of what I am trying to do. – Reafidy Nov 27 '15 at 00:33
  • That is not the reason. Look at your Action Method Implementation, it has to look like my one – Julius Depulla Nov 27 '15 at 00:36
  • Sorry but it still doesnt seem to work with changing the controller code to match yours. The only difference is I removed , 'JsonRequestBehavior.AllowGet' as System.Web.MVC is gone from asp.net 5. – Reafidy Nov 27 '15 at 00:45
  • You will need JsonRequestBehavior.AllowGet to allow json object to be returned from your controller to the view. It is disabled in ASP.NET MVC 5 for security reason, but if you need to return json data, that is how you enable it. – Julius Depulla Nov 27 '15 at 00:50
  • I cant use that code I get a compile error: The name 'JsonRequestBehavior' does not exist in the current context. Because System.Web.MVC does not exist in asp.net 5 mvc 6. – Reafidy Nov 27 '15 at 00:56
  • Please read this blog, you will get help on adding dependencies and also more http://tinyurl.com/o2dabre – Julius Depulla Nov 27 '15 at 01:08
  • I don't see how the articles you linked to will help. There is no dependency to add. System.Web.MVC will not work with asp.net 5. – Reafidy Nov 27 '15 at 01:52
  • @Reafidy Your action method was mvc 5, I gave you solution for mvc 5. If you need mvc 6, I gave you links to learn mvc 6. But now I realize you want mvc 6, I have just changed the action method to mvc 6, all you have to do is wrap your data in Json() method and changed the return type to IActionResult in mvc 6. See my edit in my code. an – Julius Depulla Nov 27 '15 at 07:25
  • @'Julius Depulla' This method of MVC/ajax/jquery wasn't working for me. I Debugged through the jquery and discovered that while in the ajax section there was a parser error. However the definition of `var viewModel = { Id : 1, TotalSales: 50,` ...etc. was fine, as I was able to peek into the viewModel var. only after it got into the ajax section, did it failed with parser error. Do you or anyone else have any ideas? – George Geschwend Jan 06 '18 at 00:24
  • One more quick question... Shouldent the json definining the var veiwModel have quotations around the words? Ergo: `{ "Id": 1, "MyDate": "myDate"...`etc.. . If the answer is no, was curious to know why? – George Geschwend Jan 06 '18 at 05:48