rStackSharper
rStackSharper

Reputation: 19

POST to MVC controller is NULL from KnockoutJS

It looks like this has been talked to death, but I still can't seem to get my code to work.

I'm attempting to use Knockoutjs's editable table and use an AJAX post to a controller to add to the model. However, the post is always null in the controller.

Here's the model:

using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace Adder_Web.Models
{
    public class User
    {
        [Display(Name = "ID")]
        [Required]
        [StringLength(9, ErrorMessage = "SSO must be 9 numbers", MinimumLength = 9)]
        public virtual string ID { get; set; }

        [Display(Name = "First Name")]
        [Required]
        public string FirstName { get; set; }

        [Display(Name = "Last Name")]
        [Required]
        public string LastName { get; set; }

    }

    public class UserContext : DbContext
    {
        public DbSet<User> Users { get; set; }
    }


}

Here's the controller I'm attempting to post to. The users is null when posted to:

 [HttpPost]
    public async Task<ActionResult> CreateMultiple(IEnumerable<User> users)
    {
        if (ModelState.IsValid)
        {
            foreach (User oneUser in users)

            {
                db.Users.Add(oneUser);
                await db.SaveChangesAsync();
                return RedirectToAction("Index");
            }

        }

        return View(users);
    }

And here's the javascript:

    script>
    var UserModel = function (users) {
        var self = this;
        self.users = ko.observableArray(users);

        self.addUser = function () {
            self.users.push({
                id: "",
                firstName: "",
                lastName: ""
            });
        };

        self.removeUser = function (user) {
            self.users.remove(user);
        };

        self.save = function (form) {

            sendData = JSON.stringify(self.users);

            $.ajax({
                url: '/Users/CreateMultiple',
                contentType: "string",
                async: true,
                type: "POST",
                data: JSON.stringify(sendData),
                error: function (jqXHR, textStatus, errorThrown) {
                    console.log("FAIL: " + errorThrown);
                },
                success: function (data, textStatus, jqXHR) {
                    console.log("SUCCES");
                }
            });


        };
    };

    var viewModel = new UserModel([
        { id: "123456789", firstName: "John", lastName: "Doe" }
    ]);
    ko.applyBindings(viewModel);

    // Activate jQuery Validation
    $("form").validate({ submitHandler: viewModel.save });
</script>

Upvotes: 0

Views: 684

Answers (5)

confused
confused

Reputation: 199

@rStackSharper

Just make it sure that your user models on the back end and on the front end have identical properties.

Example:

on your back end,

class User
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
}

on your front end should be,

var user = { FirstName: "John", LastName: "Doe" };

or if you create a function to it;

function user(){

    this.FirstName = "John";
    this.LastName = "Doe";  
}

then when you send it to the server you have to JSON.stringify(user) for it to be accepted

Upvotes: 0

rStackSharper
rStackSharper

Reputation: 19

I was able to get it sorted by making the following changes:

AJAX:

self.save = function (form) {

        sendData = ko.toJSON(self.users);


        $.ajax({
            url: '/Users/CreateMultiple',
            contentType: 'application/json',
            async: true,
            type: 'POST',
            dataType: 'json',
            data: sendData,
            error: function (jqXHR, textStatus, errorThrown) {
                console.log("FAIL: " + errorThrown);
            },
            success: function (data, textStatus, jqXHR) {
                console.log("SUCCES");
            }
        });


    };

CONTROLLER:

[HttpPost]
    public ActionResult CreateMultiple(List<User> users)
    {
        if (ModelState.IsValid)
        {
            foreach (User oneUser in users)
            {
                    db.Users.Add(oneUser);
                    db.SaveChanges();
            }
            return RedirectToAction("Index");
        }

        return View();
    }

Upvotes: 0

kunal gaikwad
kunal gaikwad

Reputation: 110

do changes to your ajax method as below it might be help you. Thank You

or else Simply change ajax method data attribute like ex:- data: JSON.stringify(sendData) to data: ({users:sendData}),


Note:- users in 'data:({users:sendData})' is your CreateMultiple(IEnumerable users) method parameter name

$.ajax({
            url:'@Url.Content("~/Users/CreateMultiple")', 
            async: true,
            cache:false,           
            type: 'POST',
            data: ({users:sendData}),
            error: function (jqXHR, textStatus, errorThrown) {
                console.log("FAIL: " + errorThrown);
            },
            success: function (data, textStatus, jqXHR) {
                console.log("SUCCES");
            }
        });

Upvotes: 0

Mustafa Tığ
Mustafa Tığ

Reputation: 101

Can you try to remove Content-Type and stringfy, i hope it wil work and if your ajax method is post with an object, you dont have to put [FromBody] attribute. You can use this attribute like following.

[HttpPost]
public async Task<IActionResult> CreateMultiple([FromBody] string userCode){

}
[HttpGet]
public async Task<IActionResult> CreateMultiple(string userCode){

}

Upvotes: 0

take
take

Reputation: 2222

Javascript Part:

  • You stringify your sendData two times
  • you have to set the correct Content-Type (application/json)

C# Part:

In your Controller you have to inform your Method that the Model comes from the body of your http post request.

public async Task<IActionResult> CreateMultiple([FromBody] IEnumerable<User> users)
{ 
    /*..*/ 
}

Upvotes: 1

Related Questions