0

I have a bar which displays a varibale number of values in sub-bars. The total width of the bar is fixed. Whenever a value changes, I need to recompute the width of all the bars as proportions of the new sum of all values.

The sub-bars are templated based on a knockout.js observable array:

<div data-bind="foreach: subBars">
   <div data-bind="style: { width: (width() + 'px'), backgroundColor: color }"></div>
</div>

The Array itself passes an initial width and a value into the subBars:

this.subBars = ko.observableArray ([
   new subBar(initialWidth01, color01);
   new subBar(initialWidth02, color02);
]);

Whenever a value for a subBar is changed, the total sum of all values is calculated as

this.subBarsTotal = ok.computed... (this works)

within the view model.

The subBar function, outside of the view model, is:

function subBar (initialWidth, color) {
  var self = this;
  self.initialWidth = initialWidth; 
  self.width = ok.computed(function(){
     var adjustedWidth = self.initialWidth() / subBarsTotal() * widthOfBar;  
  return adjustedWidth;
  }
  self.color = color;
}

However much I try, I haven't found a way to get at the value of subBarsTotal.

What am I not seeing here?

(edit: typo) (edit: whole code) (edit: back to basics - whole code not

gzost
  • 2,375
  • 1
  • 18
  • 25

2 Answers2

0

You cant reach viewModel's variables - functions directly from subBar.

If you define your viewModel like this :

function vm() {
  var self = this;
  this.subBars = ko.observableArray ([
     new subBar(initialWidth01, color01);
     new subBar(initialWidth02, color02);
  ]);
  this.subBarsTotal = ko.computed(function(){...});  
  ...
}

var viewModel = new vm();

You can call its properties :

function subBar (initialWidth, color) {          
      self.initialWidth = initialWidth; 
      self.width = ok.computed(function(){
         var adjustedWidth = self.initialWidth() / viewModel.subBarsTotal() * widthOfBar;  
      return adjustedWidth;
      }
      self.color = color;
}

Or you can pass instance of viewModel to subBar like this :

function vm() {
   var self = this;
   this.subBars = ko.observableArray ([
     new subBar(initialWidth01, color01, self);
     new subBar(initialWidth02, color02, self);
   ]);
}

function subBar (initialWidth, color , vm) {
   ...
   vm.subBarsTotal();
   ...
}

EDIT :

I changed your code little bit. Pushed the array values after defined computed function.

Check this JsFiddle link

function hundred_bar_section(width, color, dvm) {
    this.hundred_width = ko.observable(width);
    this.section_color = color;
    console.log(dvm.hundred_bar_total()); // is now defined
}

function DashboardViewModel() {
    var self = this;
    this.hundred_bar_sections = ko.observableArray([]);
    // adds the total current values of all hundred_bar_section widths
    this.hundred_bar_total = ko.computed(function() {
        var hundred_bar_length = self.hundred_bar_sections().length;
        //console.log (hundred_bar_length);
        var hundred_bar_added = 0;
        for (var i = 0; i < hundred_bar_length; i++) {
            hundred_bar_added += self.hundred_bar_sections()[i].hundred_width();
        }
        console.log(hundred_bar_added);
        return hundred_bar_added;
    });

    this.hundred_bar_sections.push(new hundred_bar_section(100, "#f60", self));
    this.hundred_bar_sections.push(new hundred_bar_section(200, "#6f0", self));
    this.hundred_bar_sections.push(new hundred_bar_section(100, "#06f", self));

}

$(document).ready(function() {

    var vm = new DashboardViewModel();
    ko.applyBindings(vm);

})​
Luffy
  • 2,257
  • 16
  • 24
  • Thanks! The changed code solves the basic problem here: self is passed into the observable array, but as it is at the time it is passed. If the array is filled initially, before all functions that need to be accessible within the array element function have been defined, then these are missing. – gzost Aug 07 '12 at 12:04
0

You can pass a parameter to your width computed observable. See knockoutjs: can we create a dependentObservable function with a parameter?

Therefore, I would just pass the subBarsTotal value into your computed observable. This will avoid making your design too coupled.

Community
  • 1
  • 1
Mark Robinson
  • 13,128
  • 13
  • 63
  • 81
  • 1
    Yep just like Mark said you can pass only needed variable to function also. But if you want to use other functions and variables defined in viewModel, passing instance of viewModel is the shortcut i think. – Luffy Aug 04 '12 at 10:41