0

I have a problem which I have never encountered before, so here is a basic rundown. I'm building a area on a website where users can submit warranty claims. Working on localhost so can't provide link.

I have one form where a user enters name etc. I have another form where user enters product information, now this is where my problem lies. The user can add more than one item for their warranty claim. So the next step is add another item, or submit warranty claim.

Now I don't want to add the data to the database until the user submits all their information, so clicks the submit warranty claim button.

At the moment I have a button to add another item, and when the user clicks the add another item button I send an ajax request to the server. Then I clear the product information form and then the user can add a second product.

So here is the code that is triggered when the user clicks the add another item button:

$.ajax({
            cache: false,
            url: '@(Url.RouteUrl("Nop.Plugin.Widgets.CustomerReturnsWidget.CustomerReturns.NoAccountWarrantyFormProduct"))',
            type: 'post',
            data: $("#add-warranty-claim-form-product-details").serialize(),
            success: function (data) {
                //reset form
                $("#add-warranty-claim-form-product-details")[0].reset();

                numItemsCount++;
            }
        });

Here is the ajax for final submit button:

$.ajax({
                cache: false,
                url: '@(Url.RouteUrl("Nop.Plugin.Widgets.CustomerReturnsWidget.CustomerReturns.NoAccountWarrantyFormYourDetails"))',
                type: 'post',
                data: $("#add-warranty-claim-form, #add-warranty-claim-form-product-details").serialize(),
                success: function (data) {
                    console.log("success = " + data.success + ":");
                }
            });

As you can see I serialize both forms and send to controller. What would be the best way to go about this?

I thought maybe I could have a temporary table, where that product form gets entered into. Then if the user doesn't go through with the claim that data isn't entered into the warranty claim tables. Then I could build a task which would run once a week and delete everything from that temp product table which is older than one week. But I feel like there would be a better solution.

Now it's also worth noting I'm using validation on my models, so the model must be validated for the product form before another product can be added.

Here is my model:

namespace Nop.Plugin.Widgets.CustomerReturnsWidget.Models
{
    [Validator(typeof(CustomerReturnsValidator))]
    public partial class CustomerReturnsModel : BaseNopModel
    {
        public CustomerReturnsModel() {
            Items = new List<CustomerReturnItemModel>();
        }
        public int CustomerReturnID { get; set; }

        //customer details
        [NopResourceDisplayName("Plugin.CustomerReturns.Fields.CustomerEmail")]
        public string CustomerEmail { get; set; }

        [NopResourceDisplayName("Plugin.CustomerReturns.Fields.CustomerFullName")]
        public string CustomerFullName { get; set; }

        [NopResourceDisplayName("Plugin.CustomerReturns.Fields.CustomerPhoneNumber")]
        public string CustomerPhoneNumber { get; set; }

        [NopResourceDisplayName("Plugin.CustomerReturns.Fields.InvoiceNumber")]
        public int? InvoiceNumber { get; set; }

        [NopResourceDisplayName("Plugin.CustomerReturns.Fields.DateSubmitted")]
        public DateTime? DateSubmitted { get; set; }

        public IList<CustomerReturnItemModel> Items { get; set; }

        [Validator(typeof(CustomerReturnItemValidator))]
        public partial class CustomerReturnItemModel : BaseNopModel
        {
            public CustomerReturnItemModel()
            {
                ClaimOptionTypeList = new List<SelectListItem>();
            }

            public int Id { get; set; }

            public int CustomerReturnID { get; set; }

            //claim form warranty
            [NopResourceDisplayName("Plugin.CustomerReturns.Fields.ClaimOptionType")]
            public string ClaimOptionType { get; set; }

            [NopResourceDisplayName("Plugin.CustomerReturns.Fields.PurchaseDate")]
            public string PurchaseDate { get; set; }

            [NopResourceDisplayName("Plugin.CustomerReturns.Fields.ProductBrand")]
            public string ProductBrand { get; set; }

            [NopResourceDisplayName("Plugin.CustomerReturns.Fields.ProductBrandQuantity")]
            public int ProductBrandQuantity { get; set; }

            [NopResourceDisplayName("Plugin.CustomerReturns.Fields.ProductName")]
            public string ProductName { get; set; }

            public IList<SelectListItem> ClaimOptionTypeList { get; set; }
        }
    }
}

Here is the action result from my controller:

public ActionResult PartialNoAccountWarrantyProductFormView()
    {
        var model = new CustomerReturnsModel.CustomerReturnItemModel();

        //type of claim form options
        Dictionary<string, string> claimFormVals = new Dictionary<string, string>
        {
            { "I'd like to submit a warranty claim", "0" },
            { "An item was damaged in transit", "1"},
            { "I'd like to return an item", "2" }
        };

        foreach (var val in claimFormVals)
        {
            model.ClaimOptionTypeList.Add(new SelectListItem
            {
                Text = val.Key,
                Value = val.Value,
                Selected = (model.ClaimOptionType != null && model.ClaimOptionType != "0") ? val.Value == model.ClaimOptionType : val.Value == "0"
            });
        }

        return View("~/Plugins/Widgets.CustomerReturns/Views/CustomerReturns/PartialNoAccountWarrantyProductForm.cshtml", model);
    }

For the add another item button I post to this controller method:

[HttpPost]
    public ActionResult NoAccountWarrantyFormProduct(CustomerReturnsModel.CustomerReturnItemModel model, FormCollection form)
    {
        CustomerReturnsModel Model = new CustomerReturnsModel();
        //IList<CustomerReturnItemModel> myList = new List<CustomerReturnItemModel>();

        if (ModelState.IsValid)
        {
            //insert customer return items
            model.ProductBrand = form["ProductBrand"];
            model.ProductBrandQuantity = Int32.Parse(form["ProductBrandQuantity"]);
            model.ProductName = form["ProductName"];

            //myList.Add(model);
            Model.Items.Add(model);

            //return Json(new
            //{
            //    success = true
            //});

        }

        //If we got this far, something failed, redisplay form
        return PartialNoAccountWarrantyProductFormView();
    }

when final submit button occurs goes to this method.

[HttpPost]
    public ActionResult NoAccountWarrantyFormYourDetails(CustomerReturnsModel model, FormCollection form)
    {
        CustomerReturns CustomerReturn = new CustomerReturns();//to customer return table
        CustomerReturnItems CustomerReturnItem = new CustomerReturnItems();//to the items table
        int CustomerReturnID;

        if (ModelState.IsValid)
        {

            CustomerReturn.CustomerEmail = model.CustomerEmail;
            CustomerReturn.CustomerFullName = model.CustomerFullName;
            CustomerReturn.CustomerPhoneNumber = model.CustomerPhoneNumber;
            CustomerReturn.InvoiceNumber = model.InvoiceNumber ?? CustomerReturn.InvoiceNumber;
            CustomerReturn.DateSubmitted = DateTime.Now;

            CustomerReturnID = _customerReturnsService.InsertCustomerReturn(CustomerReturn);


            //insert customer return items
            CustomerReturnItem.CustomerReturnID = CustomerReturnID;
            CustomerReturnItem.ProductBrand = form["ProductBrand"];
            CustomerReturnItem.ProductBrandQuantity = Int32.Parse(form["ProductBrandQuantity"]);
            CustomerReturnItem.ProductName = form["ProductName"];

            _customerReturnItemsService.InsertCustomerReturnItems(CustomerReturnItem);

            var items = model.Items;

            foreach (var CustomerReturnItems in items)
            {
                CustomerReturnItem.CustomerReturnID = CustomerReturnID;
                CustomerReturnItem.ProductBrand = CustomerReturnItems.ProductBrand;
                CustomerReturnItem.ProductBrandQuantity = CustomerReturnItems.ProductBrandQuantity;
                CustomerReturnItem.ProductName = CustomerReturnItems.ProductName;
            }

            return Json(new
            {
                success = true,
                CustomerReturnId = CustomerReturnID
            });
        }

        //If we got this far, something failed, redisplay form
        return View("~/Plugins/Widgets.CustomerReturns/Views/CustomerReturns/CustomerReturnsNoAccount.cshtml");
    }

I'm not sure why this wouldn't work, seems so close.

I hope this makes sense. Cheers

chris c
  • 321
  • 2
  • 14
  • 1
    You appear to be wanting to dynamically add multiple items (Products) to a collection, in which case refer the answers [here](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) and [here](http://stackoverflow.com/questions/40539321/partial-view-passing-a-collection-using-the-html-begincollectionitem-helper/40541892#40541892) for some options –  Jun 13 '18 at 23:19
  • @StephenMuecke please see my updated question. I tried what you suggested but could not seem to make it work. I have tried another way, but when I add the model as an item `Model.Items.Add(model);` I can't grab it from other controller method. Thanks for the help – chris c Jun 15 '18 at 06:58
  • Without seeing what you tried, I cannot guess what you may have been doing wrong (and I do not even know which option you tried,but I assure you both work) –  Jun 15 '18 at 07:37

0 Answers0