简体   繁体   中英

Populating Select options using Knockout.js with MVC 4

I am a beginner with knockout.js. I am having trouble getting a select's options to populate in an MVC 4 view. Here's my code.

(Break point in the controller shows data populating the viewbag correctly. The list contains only two fields per item: shown in the creation of the SelectList in the controller.)

The controller:

public ActionResult Index()
{
    List<Brewery> breweries = new List<Brewery>(_commonProvider.GetBreweryList());
    ViewBag.Breweries = new SelectList(breweries.AsEnumerable(), "BreweryCode", "BreweryDescription");
    return View();
}

The view:

/*** html stuff ***/
<select class="ui-select" id="BrewerySelect" name="BrewerySelect" data-bind="options: GetBreweries,
                                                                             optionsText: BreweryDescription,
                                                                             optionsValue BreweryCode,
                                                                             value: selectedBrewery,
                                                                             optionsCaption: Select a Brewery"></select>

/*** javascript stuff ***/
@section footer {
    @Scripts.Render("~/bundles/viewscripts-js")
    <script type="text/javascript">
        var config = {
            GetBrewery: '@Url.Action("GetBrewery")',
            GetLine: '@Url.Action("GetLine")',
            GetUrl: '@Url.Action("GetUrl")'
        };

        var data = {
            Brewery: "@ViewBag.Breweries",
            Date: '@DateTime.Today.ToString("MM/dd/yyyy")'
        };

        var viewModel = DashboardReportViewModel(config, data);
        ko.applyBindings(viewModel);


    </script>
}

The ViewModel

var DashboardReportViewModel = function (config, originalData) {
    var self = this;

    self.GetBreweries = ko.observableArray([originalData.Breweries]);
}

I've also tried:

var DashboardReportViewModel = function (config, originalData) {
    var self = this;

    self.GetBreweries = ko.observableArray([]);

    var loadBreweries = function () {
        self.GetBreweries(originalData.Brewery);
    }

    loadBreweries();
}

Just to clarify, the ViewBag will hold an object or array of objects, but when you call that ViewBag property from the view it will call ToString on that property.

Consequently,

"@ViewBag.Breweries"

Is the same as writing

"@ViewBag.Breweries.ToString"

And unless you've overriden SelectList.ToString() then all you'll get out of this is the fully-qualified class name.

The preferable approach - as you've now done - is to expose the Breweries as retrievable data (JSON, XML, etc. ) and retrieve this asynchronously, but you could also add an extension method called, say, SelectList.ToJson() which returns the contents of the SelectList formatted in such a way that you can easily output it in <script> tags on a view.

After discovering that sending the Viewbag simply resulted in a string being passed, I moved the controller BreweryList building to a seperate ActionResult and used ajax to call it.

Changes

View:

 <select class="ui-select" id="BrewerySelect" name="BrewerySelect" data-bind="options: GetBreweries,
                                                                              optionsText: 'Text',
                                                                              optionsValue: 'Value',
                                                                              optionsCaption: 'Select a Brewery'"></select>

Controller:

    public ActionResult Index()
    { 
        return View();
    }

    [HttpGet]
    public ActionResult GetBreweries()
    {
        List<Brewery> breweries = new List<Brewery>(_commonProvider.GetBreweryList());
        SelectList breweryList = new SelectList(breweries, "BreweryCode", "BreweryDescription");
        return Json(breweryList, JsonRequestBehavior.AllowGet);
    }

ViewModel:

var DashboardReportViewModel = function (config, originalData) {
    var self = this;

    self.GetBreweries = ko.observableArray([]);    

    var loadBreweries = function () {
        $.ajax({
            url: config.GetBreweries,
            type: "GET",
            error: function (xhr, status, error) {
                alert(xhr.responseText);
            },
            success: function (data) {
                self.GetBreweries(data);
            },
            cache: false
        });
    };
    loadBreweries();

};

Nothing else changed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM