سؤال

Little by little I'm learning this...

In my C#/MVC4 demo build I've created a controller to send data to my view through JSON. In my view I am able to parse the response and populate a drop down list.

I'm using knockout similar to a cart to create additional lines (colors) for posting to the controller.

code:

MVC ViewModel:

function Color(data) {
    this.ID = ko.observable(data.ID);
    this.ColorName = ko.observable(data.ColorName);
    this.Duration = ko.observable(data.Duration);
    this.bNotPermanent = ko.observable(1);
}

function ViewModel() {
    self = this;
    self.CurrentColors = ko.observableArray([]);
    self.AddColors = ko.observableArray([]);
    self.AllColors = ko.observableArray([]);

    $.ajax({
        type: "POST",
        url: '@Url.Action("GetUsersColors", "EditUser")',
        data: { szUserRecID: RecID },
        success: function (data) {
            var colors = $.map(data, function (item) {
                return new Color(item)
            });
            self.CurrentColors(colors);
        },
        error: function (err) {
            alert(err.status + " : " + err.statusText);
        }
    })

    $.ajax({
        type: "POST",
        url: '@Url.Action("GetVisibleColors", "EditColor")',
        contentType: "application/json; charset=utf-8",
        dataType: "json", 
        data: {},
        success: function (data) {
            var colors = $.map(data, function (item) {
                return new Color(item)
            });
            self.AllColors(colors);
        },
        error: function (err) {
            alert(err.status + " - " + err.statusText);
        }
    })

    self.removeLine = function (color) { self.AddColors.remove(color);

    };
    self.addColor = function (color) { 
        self.AddColors.push(new Color({ ColorName: "", ID: "", Duration: "Permanent" }))
    };

    self.save = function () 
    {
        // I've also tried data: ko.mapping.toJSON(this) 
        // based on my issues I've seen, I'm almost positive this is where my issue is
        // I think the mapping is having an issue but I don't know what it should look like
        // with an array of objects
        $.ajax({
            url: '@Url.Action("PostColors", "EditColor")',
            type: "POST",
            data: ko.mapping.toJSON(this.AddColors()),
            async: true,
            contentType: "application/json"
        }).success(function (data) {

        });

};

this does work...

View

<table>
<thead>
    <tr data-bind =" visible: $root.AddColors().length > 0">
        <th padding: 10px; >Color</th>
        <!--<th padding: 10px; >Duration</th>-->
    </tr>
</thead>
<tbody data-bind="foreach: AddColors">
    <tr>
    <!-- This works, it displays all the colors provided by the controller -->
        <td><select data-bind="options: $root.AllColors, optionsText: 'ColorName', value: ID, optionsCaption: 'Select Color...'"></select></td>
        <td>
            <a href='#' data-bind='click: $parent.removeLine'>Remove</a>
        </td>
    </tr>
</tbody>
</table>

<button data-bind='click: addColor'>Add Color</button>


<button data-bind='click: save'>Submit Colors</button>

controller:

    [HttpPost]
    public void PostColors(List<ViewModels.ColorList> AddColors)
    {

           int t = 0; // to set a break point only
    }

C# ViewModel

    public class ColorList
{
    public int? ID { get; set; }
    public string ColorName { get; set; }
    public string Duration{ get; set; }
    public bool bNotPermanent { get; set; }
}

when I inspect AddColors in the above function, the Duration is set but the ColorName is null but I do have the correct number of elements coming through.

I can add lines(colors) over and over on the form and selecting them on the list. But why are they not showing in "AddColors" object list?

I did find another article on here referring to get; set; in the viewmodel and I did add that. Up until that point everything coming through was null.

Fiddler is showing this (and it doesn't look quite right...?)

[{"ID":    {"ID":11,"ColorName":"Green","Duration":null,"bNotPermanent":1},"ColorName":"","Duration":"Permanent","bNotPermanent":1},{"ID":    {"ID":17,"ColorName":"Red","Duration":null,"bNotPermanent":1},"ColorName":"","Duration":"Permanent","bNotPermanent":1}]

I really think my issue is with the data conversion / ajax post. Question is, what should it look like?

هل كانت مفيدة؟

المحلول

I'm guessing that you want the ID of the color to appear in the ID field on the added color entry. If so, what you need to do is that you need to set the optionsValue binding to select a single property from the selected item and use the value of that property to set the property you are binding to.

The Knockout documentation on the options binding states the following regarding the optionsValue binding.

Similar to optionsText, you can also pass an additional parameter called optionsValue to specify which of the objects’ properties should be used to set the value attribute on the elements that KO generates.

Since you don't want the whole object to be set into the ID property of your added color, you want Knockout to pick the ID property from the color. So just update your binding from:

<select data-bind="options: $root.AllColors, 
                   optionsText: 'ColorName', 
                   value: ID, 
                   optionsCaption: 'Select Color...'">
</select>

to:

<select data-bind="options: $root.AllColors, 
                   optionsText: 'ColorName', 
                   optionsValue: ID,
                   value: ID, 
                   optionsCaption: 'Select Color...'">
</select>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top