0

I've seen many posts on SO considering this topic, though applying solutions didn't work for me and I am confused right now. Mb I'm missing sth?

Please consider I'm a noob at .js stuff.

So I get my values from dynamicly created form elements with this JS and attempt to post it:

EDIT 12:21: I got this script which should parse each element from form into custom made array resembling json. I still get null reference though. Got any idea how to get it?

 var getValues = function (myForm) {
        var array = [];
    var parser;

    $("formElement").each( function (i, elem) {

            parser.empty()
            parser = {
                Id: $(elem,"#Id ").val(),
                someOption: $(elem, "#someOption ").val(),
                someText: $(elem, "#someText ").val(),
                someNumber: $(elem, "#someNumber  ").val()
            }
            array.push(parser);

        });

    console.log(array);


    $.ajax({
        type: "POST",
        url: 'angus',
        traditional: true,
        data:  {json: array },
        success: function (data) {
            $("#getData").empty();
            $("#getData").append(array);
        }
    });            
    };

I get this in log: (objects of index like i,i+1,i+2,i+3 match the viewmodels - is it right? and I have mixed feelings about those proto and functions - what is it?) enter image description here

In my controller action I get null exception:

 [HttpPost]
        public ActionResult angus(IEnumerable<TrashViewModel> json)
        {

            return View(json.ToList());
        }

I created my viewmodel:

  [Serializable]
public class TrashViewModel
{
    public int Id { get; set; }
    public string someOption { get; set; }
    public string someText { get; set; }
    public string someNumber { get; set; }

}

I had my forms HTML attributes names match those of viemodel class.

EDIT: html:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="formExample" ng-controller="ExampleController">

    <button class="btn btn-primary" ng-controller="addRow" ng-click="addLine()">Dodaj przycisk</button>

    <form novalidate class="simple-form">
        <div class="here">
            <div class="formElement row">

                  <input type="hidden" name="Id" value="1"/>
                <div class="col-md-2">
                    <select name="someOption" class="optns form-group col-md-12" ng-model="user.class">
                        <option selected value="1"> Rodzaj... </option>
                        <option value="test">2</option>
                        <option value="2">test</option>
                        <option value="2">2</option>
                        <option value="3">3</option>
                        @*tutaj beda dodane opcje*@
                    </select>
                </div>
                <div class="col-md-1">
                    <input name="someNumber" class="form-group col-md-12" type="number" ng-model="user.number" value="" text="Ilość..." /><br />
                </div>
                <div class="col-md-9">
                    <input name="someText" class="form-group col-md-12" type="text" ng-model="user.text" value="" text="Uwagi..." /><br />
                </div>
            </div>
        </div>
        <input type="button" value="Reset" />
        <input type="submit" value="Save" />
    </form>
</div>

appended html:

 var strVar = "";
            strVar += "<div class=\"formElement row\">";
            strVar += "                  <input type=\"hidden\" name=\"Id\" value=\" "+ $scope.counter +"\"\/>";
            strVar += "                <div class=\"col-md-2\">";
            strVar += "                    <select name=\"someOption\" class=\"optns form-group col-md-12\" ng-model=\"user.class\">";
            strVar += "                        <option selected value=\"1\"> Rodzaj... <\/option>";
            strVar += "                        <option value=\"test\">2<\/option>";
            strVar += "                        <option value=\"2\">test<\/option>";
            strVar += "                        <option value=\"2\">2<\/option>";
            strVar += "                        <option value=\"3\">3<\/option>";
            strVar += "                        @*tutaj beda dodane opcje*@";
            strVar += "                    <\/select>";
            strVar += "                <\/div>";
            strVar += "                <div class=\"col-md-1\">";
            strVar += "                    <input name=\"someNumber\" class=\"form-group col-md-12\" type=\"number\" ng-model=\"user.number\" value=\"\" text=\"Ilość...\" \/><br \/>";
            strVar += "                <\/div>";
            strVar += "                <div class=\"col-md-9\">";
            strVar += "                    <input name=\"someText\" class=\"form-group col-md-12\" type=\"text\" ng-model=\"user.text\" value=\"\" text=\"Uwagi...\" \/><br \/>";
            strVar += "                <\/div>";
            strVar += "            <\/div>";

I end up with null exception which by what other posts suggest is because of viemodel class doesn't match the serialized objects. Don't know what to do at this point.

Thank you!

Aleksander Dudek
  • 133
  • 1
  • 13
  • Your need to show the html your generating. Show some typical `name` attributes - are they correctly indexed? –  Sep 01 '16 at 07:20
  • @StephenMuecke added it to the post, thx for consideration – Aleksander Dudek Sep 01 '16 at 07:37
  • 1
    If your dynamically adding multiple items with duplicate `name` attributes, then using `serializeArray()` (or `serialize()`) is simply not going to work. You could generate the correct name attributes with indexers as per [this example](http://stackoverflow.com/questions/29161481/post-a-form-array-without-successful/29161796#29161796)in which case its simply `data: form.serialize(),` and remove `traditional: true,` –  Sep 01 '16 at 08:53
  • 1
    The alternative is to manually generate an array of objects by looping through each `
    ` - it would need to look like `[{ Id: 1, someOption: 'xxx', ... }, { Id: 2, someOption: 'yyy', ... }, ... ]` and then `JSON.stringify()` it and set `contentType: 'json',`
    –  Sep 01 '16 at 08:57
  • thx @StephenMuecke will try it out :) – Aleksander Dudek Sep 01 '16 at 09:07
  • Not sure if your updating those answers but they are all wrong and will not work –  Sep 01 '16 at 09:12

4 Answers4

1

try replacing

 var parsed = $(myForm).serializeArray();

with

 var parameters = {
            Id : $("#Id ").val(),
            someOption : $("#someOption ").val(),
            someText : $("#someText ").val(),
             someNumber  : $("#someNumber  ").val()
       };

then pass it to the submit

JSON.stringify(parameters)
Emil
  • 281
  • 1
  • 2
  • 11
  • it does the job for single element, now I'm changing it for array since that's the whole point - if it works will sure mark as answer :) thx – Aleksander Dudek Sep 01 '16 at 09:09
1

in your JavaScript code, 3 things jump out at me:

  1. you're using .serializeArray(), which creates an array of objects each with a name and value property. this does not match the structure of your TrashViewModel object
  2. you're wrapping the serialized object inside a new object with a single property called "json", which adds more structure to your data
  3. you're stringifying said object

all of that is unnecessary, since the .ajax() method will package the data in the correct format for you. you simply need to pass the serialized form as the data parameter.

data: $(myform).serialize()

on the controller, you should just set the parameter on the action to be your TrashViewModel object. please note that it's a single object, not an enumerable.

public ActionResult Angus(TrashViewModel form)
{
    // do something
}

if you were to use .serializeArray(), then you'd need to create a model object with Name and Value properties so that the model binder can properly resolve the params.

// JavaScript 
data: $(myform).serializeArray()

// Controller
public class NameValueModel
{
    public string Name { get; set; }
    public string Value { get; set; }
}

public ActionResult Angus(NameValueModel[] form)
{
    // do something
}
Jeff M
  • 477
  • 2
  • 5
1

In order to POST your array, you need to stringify the data and set the contentType option. You ajax code needs to be

$.ajax({
    type: 'POST',
    url: '@Url.Action("angus")', // do not hard code url's
    contentType: "application/json; charset=utf-8",
    data: JSON.stringify({ model: array }), 
    success: function (data) {

and the controller

[HttpPost]
public ActionResult angus(IEnumerable<TrashViewModel> model)
0

I'm not 100% happy about outcome, because I still have to parse json string at the end on server side. I think I'll soon do Q&A, so others won't have to fight a week to do sth like this. Thanks to:

  • @StephenMuecke
  • @Emil
  • @Jeff M

So actually what I did:

js to get inputs and push it custom style then do post ajax request:

        var array = [];
        var parser;

        $(".formElement").each( function (i, elem) {

                //parser.empty()
                parser = {
                    Id: $("#Id", $(this)).val(),
                    someOption: $("#someOption", $(this)).val(),
                    someText: $("#someText", $(this)).val(),
                    someNumber: $("#someNumber", $(this)).val()
                };
                console.log(parser);
                array.push(parser);

            });

        console.log(array);


        $.ajax({
            type: "POST",
            url: 'angus',
            traditional: true,
            data: { json: JSON.stringify(array) },
            success: function (data) {
                $("#getData").empty();
                $("#getData").append(array);
            }
        });

controller: (don't mind the logic, because it's useless here except it gave info during debugging)

the most important thing was to give string type as parameter; I'm 100% sure that my json bounced off of the complex type viewmodel

       [HttpPost]
        public ActionResult angus(string json)
        {

            var check = json.ToString() == null;

            return RedirectToAction("ErrorAction");
        }
Aleksander Dudek
  • 133
  • 1
  • 13
  • 1
    You DO NOT have to parse the parameter. Change `string json` to `IEnumerable model` then modify the ajax as per my previous comments - delete `traditional: true,` add `contentType: 'json'` and change it to `data: JSON.stringify({ model: array })` –  Sep 02 '16 at 00:03
  • @StephenMuecke tried both stringify and serialization you mentioned - still get null results $.ajax({ type: "POST", url: 'angus', contentType: 'json', //data: JSON.stringify({ json: array }), data: $(myForm).serialize(), success: function (data) { $("#getData").empty(); $("#getData").append("Sukces!"); $("#getData").addClass(); } }); – Aleksander Dudek Sep 05 '16 at 07:01
  • 1
    Sorry, that needed to be `contentType: "application/json; charset=utf-8",` (and have tested and works fine). But you have invalid html (duplicate `id` attributes) so you would be posting back duplicate values of the controls in the first `formElement` - you need to use class names –  Sep 05 '16 at 07:21
  • @StephenMuecke mother of god... it works! will edit top and give upvote with answer :o btw if you'd like to do the honors just post the answer for this, I can't stress enough how you have helped me :) and you deserve 100% of it – Aleksander Dudek Sep 05 '16 at 07:35
  • @StephenMuecke I meant your answer (though it could've been unclear at 1st) :) – Aleksander Dudek Sep 05 '16 at 07:41
  • I rolled back the edit to your question (answers cannot be in the question) –  Sep 05 '16 at 08:20