Jeremy Noble
Jeremy Noble

Reputation: 183

How do I use a computed function to specify the CSS binding within a foreach observable array

I have a page listing multiple projects which are breeze entities in an observable array. Using a foreach loop, I want the CSS of a label to vary depending upon the status of the project.
Because I'm using breeze, I define var projects = ko.observableArray(); and breeze takes care of the rest, including values from a related entity (projectStatus). For the element I am trying to style, it exists within a foreach: projects list, and has binding of data-bind="text: projectStatus().name. This works perfectly. However, when I code the computed observable in the viewmodel for the CSS value, it raises an undefined error at the 3rd line (below). Otherwise (and I've checked) the function works on the CSS if it returns a valid string:

    projectStatusStyle = ko.computed(function () {
    var x = "left label label-large label-info";

    var projStatus = projects().projectStatus().name();

    var style = "left label label-large label-"
    switch (projStatus) {
        case 'Live':
            x = style + "success";
            break;
        case 'Identified':
            x = style + "info";
            break;

        case 'In conversation':
            x = style + "purple";
            break;

        case 'Complete':
            x = style + "grey";
            break;
        case 'Unsuccessful':
            x = style + "yellow";
            break;

    }
    return x;
},vm);

So my question is, how should I refer to the projects().projectStatus().name(); observable value?

Thanks

Upvotes: 1

Views: 794

Answers (1)

JeffB
JeffB

Reputation: 1867

It's hard to tell without seeing the rest of your code, but I think you have a context issue. You are defining your computed observable on your view model, but your code is kinda assuming it's defined on each object in the projects observable array. It's not, so your third line can't work. It's defined on the view model, which has no way or knowing or tracking which project in the foreach you're referencing.

You have a couple of options. You could change projectStatusStyle to a function on your view model that takes the name as a parameter:

vm.projectStatusStyle = function (projStatusName) {
  var x = "left label label-large label-info";

  var style = "left label label-large label-"
  switch (projStatusName()) {
    case 'Live':
        x = style + "success";
        break;
    case 'Identified':
        x = style + "info";
        break;

    case 'In conversation':
        x = style + "purple";
        break;

    case 'Complete':
        x = style + "grey";
        break;
    case 'Unsuccessful':
        x = style + "yellow";
        break;

  }
  return x;
};

Then you can have a binding like

<span data-bind="css: $root.projectStatusStyle(projectStatus().name)"/>

You could use $root or $parent, depending on how your view model is defined.

Honestly, I would probably just do this in your foreach:

<span class="left label label-large"
  data-bind="css: {'label-info': projectStatus().name() === 'Identified', 
  'label-success': projectStatus().name() === 'Live', 
  'label-purple': projectStatus().name() === 'In conversation', 
  'label-grey': projectStatus().name() === 'Complete', 
  'label-yellow': projectStatus().name() === 'Unsuccessful'}"/>

This way you're not putting style information in your JS model code.

Upvotes: 3

Related Questions