Analytic Lunatic
Analytic Lunatic

Reputation: 3934

$.AJAX .post() not working - Server responded with a status of 404 (Not Found)?

I am working on a View for an MVC5 app. This is an Edit View with multiple properties, several of which are related to other models. I have my main INV_Assets model and then several other tables for Location, Manufacturer, Model, Status, Type, Vendor, etc. On this Edit view, I'm displaying those particular properties as dropdown lists containing all values currently in those tables, along with a [CREATE NEW] button by each list.

When user selects the [CREATE NEW] button, I have a hidden form which appears and allows a user to enter a new value for the specific Table/DropDown. I've got everything working except the POST where I add the value to the Table and refresh the DropDown list.

Below is what I have put together for my first dropdown (the Model selection) -- everything is functioning up to the POST:

INV_Assets.Edit View:

<div class="form-group">
        <span class="control-label col-md-2">Manufacturer:</span>
        <div class="col-md-4">
            @Html.DropDownListFor(model => model.Manufacturer_Id, (SelectList)ViewBag.Model_List, htmlAttributes: new { @class = "form-control dropdown" })
            @Html.ValidationMessageFor(model => model.Manufacturer_Id, "", new { @class = "text-danger" })
        </div>
        <div class="col-md-1">
            <div class="btn-group">
                <button type="button" class="btn btn-success" aria-expanded="false">CREATE NEW</button>
            </div>
        </div>
    </div>

INV_Assets.Edit Script:

<script type="text/javascript">

        $(document).ready(function () {
            // Show() form to enter new Model.
            $('#createNewModel').click(function () {
                $('#createModelFormContainer').show();
            })

            // Submit new Model value and refresh dropdown
            $('#submitNewModel').click(function () {
                alert("New Function!"); // WORKING

                var form = $(this).closest('form');
                var url = form.attr('action');
                var data = { Text: form.find('input').first().val() };

                alert("Prior to Post"); // WORKING

                $.post(url, form.serialize(), function (data) {

                    alert("Begin POST!"); // NOT BEING REACHED!

                    $('#selectModel').append($('<option></option>').val(data.ID).text(data.Text));
                    form[0].reset();
                    $('#createModelFormContainer').hide();
                })
            });
        });
</script>

When my code hits the $.post something goes wrong. It was previously getting:

Script1

Since post() seemed to be the anonymous function, I assumed I did not have ajax installed. I then installed Microsoft.jQuery.Unobtrusive.Ajax, which now renders my error as: Failed to load resource: the server responded with a status of 404 (Not Found) - http://localhost:4545/INV_Assets.

Any thoughts on this?

As best as I understand it, my submit should be posting to my below createNewModel() method inside my INV_AssetsController:

    [HttpPost]
    public JsonResult createNewModel(INV_Models model)
    {
        model.created_date = DateTime.Now;
        model.created_by = System.Environment.UserName;
        model.modified_date = DateTime.Now;
        model.modified_by = System.Environment.UserName;

        if (ModelState.IsValid == false && model.Id == 0)
        {
            ModelState.Clear();
        }

        if (ModelState.IsValid)
        {
            db.INV_Models.Add(model);
            db.SaveChangesAsync();
        }

        return Json(new { ID = model.Id, Text = model.model_description });
    }

Assuming it is something to do with my routing, this is my current RouteConfig.cs:

public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

Anyone with more expertise able to see what I'm doing wrong?


EDIT:

Using wahwahwah's suggestion, I made the following modification to my script:

        $('#createNewModel').click(function () {
            $('#createModelFormContainer').show();
        })

        $('#submitNewModel').click(function () {
            var form = $(this).closest('form');
            var data = { Text: form.find('input').first().val() };
            $.ajax({
                type: "POST",
                dataType: "JSON",
                url: '@Url.Action("createNewModel", "INV_Assets")',
                data: data,
                success: function (resp) {
                    alert("SUCCESS!");
                },
                error: function () {
                    alert("ERROR!");
                }
            });

Going this route, my createNewModel() action is correctly called in the controller, but fails out at db.SaveChangesAsync():

    [HttpPost]
    public JsonResult createNewModel(INV_Models model)
    {
        model.created_date = DateTime.Now;
        model.created_by = System.Environment.UserName;
        model.modified_date = DateTime.Now;
        model.modified_by = System.Environment.UserName;

        if (ModelState.IsValid == false && model.Id == 0)
        {
            ModelState.Clear();
        }

        if (ModelState.IsValid)
        {
            db.INV_Models.Add(model);
            db.SaveChangesAsync();
        }

        return Json(new { ID = model.Id, Text = model.model_description });
    }

The error is as follows:

An exception of type 'System.Data.Entity.Validation.DbEntityValidationException' occurred in EntityFramework.dll but was not handled in user code

Additional information: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

EDIT2:

Modified my troublesome code to be in a try/catch and then set a Watch on ex:

    [HttpPost]
    public JsonResult createNewModel(INV_Models model)
    {

            model.created_date = DateTime.Now;
            model.created_by = System.Environment.UserName;
            model.modified_date = DateTime.Now;
            model.modified_by = System.Environment.UserName;

            // Set ID
            int lastModelId = db.INV_Models.Max(mdl => mdl.Id);
            model.Id = lastModelId+1;

            if (ModelState.IsValid == false && model.Id > 0)
            {
                ModelState.Clear();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    db.INV_Models.Add(model);
                    db.SaveChangesAsync();}
                catch (Exception ex)
                {
                    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
                }
            }

            return Json(new { ID = model.Id, Text = model.model_description });  
    }

ex Details:

DbEntityValidationErrorDetails

Apparently the description I'm entering for the new Model is not being included in the new Model that is being saved?


EDIT3:

Below is my current script/controller action code. When I break inside the controller and type ?model.model_description into the Immediate Window, it returns null.

Regarding my below alerts, the value in my <input type="text" name="model_description" /> appears to not be correctly stored in the variable for use by JSON, and thus is not passed to the controller?

INPUT FORM:

            <div id="createModelFormContainer" style="display:none">
                <form action="/createNewModel">
                    <input type="text" name="model_description" />
                    <input type="button" id="submitNewModel" value="Submit" />
                </form>
            </div>

Script:

        $('#submitNewModel').click(function () {

            var form = $(this).closest('form');

            var test = form.find('input').first().val();
            alert(test);

            var data = { model_description: form.find('input').first().val() };
            alert(data.model_description);

            //var data = { model_description: $("input[name = 'model_description']").text.toString() };

            var jsonData = JSON.stringify(data);
            alert(jsonData.valueOf());

            $.ajax({
                type: "POST",
                dataType: "JSON",
                url: '@Url.Action("createNewModel", "INV_Assets")',
                data: jsonData,
                success: function (resp) {
                    alert("SUCCESS!");
                },
                error: function () {
                    alert("ERROR!");
                }
            });

Upvotes: 1

Views: 16219

Answers (1)

wahwahwah
wahwahwah

Reputation: 3177

Here are a few things that might help you troubleshoot your View / jQuery:

  1. Make sure you are actually posting JSON
  2. That you are retrieving a value when calling `form.find('input').first().val()'
  3. You are posting to an accurate URL
  4. That the JSON object you are posting has the same property naming conventions as the model in your controller

Here's an example (not in order):

//... earlier code omitted for brevity

var test = form.find('input').first().val();
alert(test); // <--- should return the value you want to post (2)

// ... (4) need to change 'Text' to 'model_description' to reflect your model
// properties (otherwise, how can your controller bind your model to the json object your submitting to it?)

var data = { model: [{ model_description: form.find('input').first().val(); }]};

// need to make data a JSON object (1a)

var jsonData = JSON.stringify(data);

$.ajax({
    type: "POST", //<-- specify POST (1b)
    dataType: "JSON", // <-- specify JSON (1c)
    url: '@Url.Action("createNewModel", "INV_Assets")', // <-- Easier way to do URL (3)
    data: jsonData, // JSON
    success: function(resp){ 
        //callback 
    },
    error: function() {
       //callback
   }
});

Now, with your Controller...

Toggle a breakpoint and make sure that your JSON object is binding to your model object:

public JsonResult createNewModel(INV_Models model)
{
    // jsonData.model_description should have automatically bound to 
    // model.model_description because the property names are the same
}

With regards to your SaveChanges() issue, this error is normally thrown when there's a type mismatch - or null data where required - you might want to wrap your db call in a try-catch then read/handle the error:

try 
{
   db.INV_Models.Add(model);
   db.SaveChangesAsync();
}
catch (Exception Ex)
{
   // toggle breakpoint --> read error --> do something else? 
   // throw http error --> catch in ajax error callback?
}

Upvotes: 2

Related Questions