0

i am trying to show order Summary through partial View and ajax.Request is going to server but my action method of Showsummary never hits. i want to summary of order through partial view.

    [HttpPost]
    public PartialViewResult Showsummary(OrderViewModel model)
    {
        try
        {
            var p = model.Packages.SelectMany(x => x.Packages).Select(y => new OrderPackagesViewModel()
            {
                PkgName = y.PkgName,
                pkg_Id = y.id,
                Ser_Id = y.Ser_Id,
                Quantity = y.Quantity,
                price = (y.TotalPrice - (y.DiscountPercent / 100 * y.TotalPrice)) * y.Quantity
            }).ToList();
            model.OrderPackages = p;
            return PartialView("OrderSummary", model);
        }
        catch
        {
            return PartialView("OrderSummary", model);
        }
    }

My Ajax

    $("#summary").click(function () {
            console.log("calling summary");
            event.preventDefault();
            $.ajax({
                type: "POST",
                url: "/Order/Showsummary",
                data: $("form.signup-form").serialize(),
                success: function (data) {
                    console.log(data)
                    $('#page_2').hide();
                    $('#page_3').show();
                    $('#page_3').html(data);
                },
                failure: function (response) {
                    console.log(response.responseText);
                },
                error: function (response) {
                    console.log(response.responseText);
                }
            });

        })

//Html Code

<div id="page_1">
            <input asp-for="cus_name" placeholder="First Name" >
            <input asp-for="Email" placeholder="Email" >
            <select asp-for="Country" class="ui search dropdown">
                                        <option value="">Select Country</option>
                                        <option value="AF">Afghanistan</option>
                                        <option value="AX">Åland Islands</option>
            </select>
            <input asp-for="cus_phone"  placeholder="Phone Number"/>
            <select asp-for="FirstPreferences" class="custom-select mr-sm-2"
                         asp-items="@(newSelectList(Preferences))">
                             <option value="">Select</option>
            </select>
            <select asp-for="FirstPreferedTimeStart" class="menu">
                   <option value="">HH:MM</option>
                   <option value="00:00:00">00:00</option>
                   <option value="01:00:00">01:00</option>
            </select>
           <textarea asp-for="Message" class="form-control"> </textarea>
    </div>

//Page2 details of packages available. It is list of GroupByServices which contain fields ser_id Ser_Name and List of ServicePackages.

<div id="page_2" style="display:none">
            <div>
                <h1 id="heading">Choose a Package!</h1>
            </div>
            <div class="buttons">
                @foreach (var services in Model.Packages)
                {
                    <a href="#service_@services.Ser_Id"><div class="logo-p"> 
                    <h2>@services.Ser_Name</h2></div></a>
                }
            </div>
    
            <!-- packages -->
            @for (int i = 0; i < Model.Packages.Count; i++)
            {
    
          <div class="packages" id="service_@Model.Packages[i].Ser_Id">
              <h1 id="custom-website-design">
                        @Model.Packages[i].Ser_Name    
              </h1>
              <div class="packs-content">
    
                   @for (int j = 0; j < Model.Packages[i].Packages.Count(); j++)
                   {    
                     <div class="pack1">
                          <div class="pack-price">
                              <div>
                                <input asp-for="@Model.Packages[i].Packages[j].id" hidden />
                                <input asp-for="@Model.Packages[i].Packages[j].PkgName" hidden />
                                <input asp-for="@Model.Packages[i].Packages[j].Ser_Id" hidden />
                                 <input asp-for="@Model.Packages[i].Packages[j].Ser_Name" hidden />
                                        
                   <h1>@Model.Packages[i].Packages[j].PkgName</h1>
                                        
                    <p>@Model.Packages[i].Packages[j].Ser_Name PACKAGE</p>
              </div>
                                    
             <p>$@Model.Packages[i].Packages[j].TotalPrice</p>
             <input asp-for="@Model.Packages[i].Packages[j].TotalPrice" hidden />
        </div>
                                <div class="pack-features">
                                    <div class=""></div>
                                    @foreach (var features in Model.Packages[i].Packages[j].Description)
                                    {
                                        <h2>@features</h2>
                                    }
                                </div>
                                <div class="pack-order">
                                    <div class="row-1">
                                        @{
                                            double discount = (Model.Packages[i].Packages[j].DiscountPercent / 100 * Model.Packages[i].Packages[j].TotalPrice);
                                            double PriceAfterDiscount = Model.Packages[i].Packages[j].TotalPrice - discount;
    
                                        }
                                        <p>SPECIAL DISCOUNT</p>
                                        <P>-$@discount</P>
                                    </div>
                                    <div class="row-2">
                                        <p>FINAL PRICE FOR LIMITED TIME</p>
                                    </div>
                                    <div class="row-3">
                                        <a asp-controller="Packages" asp-action="Detail" asp-route-id="@Model.Packages[i].Packages[j].id" target="_blank">view details</a>
                                        <h1>$@PriceAfterDiscount</h1>
                                        <input asp-for="@Model.Packages[i].Packages[j].DiscountPercent" hidden />
                                    </div>
                                    <div class="row-4">
                                        <h4>Add To Buying List</h4>
                                        <div class="input-group mb-3 order-btn-pack">
                                            <div class="input-group-prepend">
                                                <div class="input-group-text">
                                                    <input asp-for="@Model.Packages[i].Packages[j].is_selected" aria-label="Checkbox for following text input">
                                                </div>
                                            </div>
                                            <input asp-for="@Model.Packages[i].Packages[j].Quantity" value="1" min="1" required placeholder="Quantity" class="form-control" aria-label="Text input with checkbox">
                                        </div>
    
                                    </div>
                                    <div class="row-5">
                                        <p>Discuss this offer with expert</p>
                                        <div class="discuss">
                                            <p>12345467889</p>
                                            <p id="chat-btn_10">Live Chat</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        }
                        <input asp-for="HoldPackage" hidden/>
                    </div>
                </div>
            }
            <div>
                <button type="button" class="btn btn-danger px-2 btn-lg" onclick="PageBack(this.parentElement.parentElement)">Back</button>
                <button type="button" class="btn btn-danger px-2 btn-lg" id="summary">Summary!</button>
            </div>
        </div>

Edit!!!! i have changed this line in ajax now it start hitting my controller action but still all form values are empty seems model binding is unable to recognize my fields

 **const model= $("form").serialize()**
   console.log(model); //data is there thats fine

and in ajax
data: { model }, my model have field called packages which is list of some fields and inside it there is one another list.

One thing is clear. $("form").serialize() is not working in my case its giving me 415 Unsupported Media Type client error response. I think problem is due to nested List

Muhammad Sami
  • 520
  • 2
  • 8
  • 21
  • Have you checked the console after clicking the button? I think it should throw error at line "event.preventDefault();" as you are not passing event to your button click function – Naveen Chandra Tiwari Jul 06 '20 at 13:14

1 Answers1

1

I have checked your code on my side with a simple OrderViewModel object, it works well. I suggest you could try to add '[FromBody]' in the action method, Like this:
....

Edit

According your description, it seems that you are using the Nested List and meet 415 error when using the [FromBody]. I have modified the sample code, in the action method, it's not using the [FromBody] attribute and in the JQuery Ajax method, there is no need to use the JSON.stringify method to change the JavaScript object. More detail information, please check the following code:

Model Class (Suppose the OrderViewModel contain a List):

public class OrderViewModel
{
    public int OrderId { get; set; }
    public string OrderName { get; set; }

    public List<Package> Packages { get; set; }
}

public class Package
{
    public int Pid { get; set; }
    public string PackageTitle { get; set; }
}

Code in the Controller:

    /// <summary>
    /// //display the order
    /// </summary>
    /// <returns></returns>
    public IActionResult ShowOrder()
    {
        OrderViewModel ovm = new OrderViewModel()
        {
            OrderId = 1001,
            OrderName = "order 1",
            Packages = new List<Package>()
            {
                new Package(){ Pid=101, PackageTitle="first Package"},
                new Package(){ Pid=102, PackageTitle="second package"}
            }

        };
        return View(ovm);
    }

    /// <summary>
    /// JQuery ajax post method 
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    [HttpPost]
    public PartialViewResult Showsummary(OrderViewModel model)
    {
        try
        {
            //...
            return PartialView("OrderSummary", model);
        }
        catch
        {
            return PartialView("OrderSummary", model);
        }
    }

ShowOrder.cshtml:

@model MVCSample.Models.OrderViewModel

@{
    ViewData["Title"] = "ShowOrder";
}
 
<div class="row">
    <div class="col-md-4">
        <form asp-action="Showsummary" asp-controller="Home" method="post" class="signup-form">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="OrderId" class="control-label"></label>
                <input asp-for="OrderId" class="form-control" />
                <span asp-validation-for="OrderId" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="OrderName" class="control-label"></label>
                <input asp-for="OrderName" class="form-control" />
                <span asp-validation-for="OrderName" class="text-danger"></span>
            </div>
            <div id="packages">

                @for (int i = 0; i < Model.Packages.Count; i++)
                {
                <div class="form-group">
                    <label asp-for="@Model.Packages[i].Pid" class="control-label"></label>
                    <input asp-for="@Model.Packages[i].Pid" class="form-control" />
                    <span asp-validation-for="@Model.Packages[i].Pid" class="text-danger"></span>
                    <br />
                    <label asp-for="@Model.Packages[i].PackageTitle" class="control-label"></label>
                    <input asp-for="@Model.Packages[i].PackageTitle" class="form-control" />
                    <span asp-validation-for="@Model.Packages[i].PackageTitle" class="text-danger"></span>
                </div> 
                }

            </div>
            @*<div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>*@
        </form>
    </div>
</div>
<div>
    <input type="button" id="summary" value="Summary" />
    <div id="page_3">
    </div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
    $(function () {
        $("#summary").click(function () {
            console.log("calling summary");
            event.preventDefault();
            //create a object to store the entered value.
            var OrderViewModel = {};
            //using jquery to get the entered value.
            OrderViewModel.OrderId = $("input[name='OrderId']").val();
            OrderViewModel.OrderName = $("input[name='OrderName']").val();

            var packages = []; 
            //var count = $("#packages>.form-group").length; //you could use it to check the package count            
            $("#packages>.form-group").each(function (index, item) {
                var package = {}
                package.Pid = $(item).find("input[name='Packages[" + index + "].Pid']").val();
                package.PackageTitle = $(item).find("input[name='Packages[" + index + "].PackageTitle']").val();
                packages.push(package);
            });
            OrderViewModel.Packages = packages;

            $.ajax({
                type: "POST",
                url: "/Home/Showsummary",  //remember change the controller to your owns. 
                data: OrderViewModel,  
                success: function (data) {
                    console.log(data)
                    $('#page_3').html(data);
                },
                failure: function (response) {
                    console.log(response.responseText);
                },
                error: function (response) {
                    console.log(response.responseText);
                }
            });

        });
    });
</script>

Then the output as below:

enter image description here

Edit:

Besides, I also found that by using the above sample, if I just change the data: OrderViewModel to data: $("form.signup-form").serialize() (in the Ajax method), I could also get the OrderViewModel and the Packages in the action method.

Zhi Lv
  • 18,845
  • 1
  • 19
  • 30
  • It is working in my previous project where i dont have nested List but now after applying [FromBody] Unsupported Media Type client error response coming. Ihave edited my code – Muhammad Sami Jul 06 '20 at 08:15
  • The HTTP 415 Unsupported Media Type client error response code indicates that the server refuses to accept the request because the payload format is in an unsupported format.The format problem might be due to the request's indicated Content-Type or Content-Encoding, or as a result of inspecting the data directly. Please check your code to add the "contentType: "application/json"" property. Besides, you could check the second method, create a JavaScript object and send it to action method. – Zhi Lv Jul 07 '20 at 01:49
  • none of my post action method is hitting with this html. First it fail in OrderSummary, now Create action is also not hitting, where i used my OrderviewModel as a parameter model binding is not working. – Muhammad Sami Jul 07 '20 at 17:32
  • @MuhammadSami, I have modified the code without using the FromBody attribute, please check it. – Zhi Lv Jul 08 '20 at 09:45
  • Unfortunately you didnot get my question yet its not about using jquery and and prepare a model and submit a ajax instead it should by serializing form please check this also https://stackoverflow.com/questions/62781950/action-method-not-hitting-model-binding-failed/62787257#62787257 – Muhammad Sami Jul 08 '20 at 16:57
  • First of all, I'm sorry about that. In my previous reply, I just notice that you are meeting the 415 error when using the FromBody, so, I focus on the 415 error and have fixed it. And from your provide link, now the problem is that the Ajax method not hitting the action method, first, I suggest you check whether you have changed the routing setting, and you could add debugger in the summary click event, whether this event is clicked or not, and in the Ajax failure and error function, you could check the response text. You can also use F12 to check the Http Request (URL and parameters). – Zhi Lv Jul 09 '20 at 02:14
  • i already checked it. Request is going fine but not hitting my action method and their status is always pending but only by writing [FromBody] it start hitting with 415 error – Muhammad Sami Jul 09 '20 at 06:48
  • Sorry this is not the problem! unfortunately i tried to create the sample code with same html and same structure but i noticed that it is working in my sample project! i have spend around 4 days and tries to change every thing but it is not hitting any action method nor OrderSummary nor Create Order. The problem is some where in my application because with same html and application data it is working in my sample project – Muhammad Sami Jul 09 '20 at 06:51