Simon Fox
Simon Fox

Reputation: 10591

Knockout JS initializing observable array from server data using a javascript type

I'm looking for the best way to initialize a knockout observable array from some server data (ViewBag), and I want the array contents to be of a javascript type I have defined. Without the requirement of the JS type I could just use:

materialVarieties: ko.observableArray(@Html.Raw(Json.Encode(ViewBag.Materials)))

but I also have a material JS type that I want to use so I can have some extra ViewModel specific properties and functions i.e.:

var material = function(id, name) {
    this.id = id;
    this.name = name;
    this.selected = ko.observable(false);

    this.select = function()
     {
        jQuery.each(processViewModel.materials(), function(index, item)
        {
            item.selected(false);
        });
        this.selected(true);
      }
}

And then the required initialization becomes:

materialVarieties: ko.observableArray([new material(1, "Apricot"), .....

Currently I build up a string from the ViewBag data and then render that as the initializer like this:

@{ var items = string.Join(",",
                ((IEnumerable<MaterialVariety>) ViewBag.Materials)
                            .Select(m => string.Format("new material({0}, {1})",
                                      Json.Encode(m.Id), Json.Encode(m.Name)))); }

var processViewModel = {
    material: ko.observableArray([@Html.Raw(items)])

But I'm wondering if there is a cleaner way than the string.Join bit. I could wrap it up in a Helper. What do you do?

Upvotes: 8

Views: 8370

Answers (1)

RP Niemeyer
RP Niemeyer

Reputation: 114792

I would typically serialize the array first, then map it when putting it in the view model. Would be like:

var originalVarieties = @Html.Raw(Json.Encode(ViewBag.Materials))

var processViewModel = {
   materialVarieties: ko.observableArray(ko.utils.arrayMap(originalVarieties, function(variety) {
      return new material(variety.id, variety.name);
   }))
}

Requires a minor amount of additional processing on the client-side, but seems cleaner than building strings.

Upvotes: 15

Related Questions