1

I found some similar examples to what I'm trying to do in Access viewModel in javascript function outside viewModel's scope, but have not been able to figure out what to do in my particular case. I have several teachers, show their salaries, along with total salaries, but want to show the relative percentage of their salary as it relates to the total. Here's my view:

<table>
    <tr>
    <th></th>
    <th>Salary</th>
    <th>Salary Percent</th>
    </tr>
    <tbody data-bind="foreach: teachers">
    <tr>
        <td data-bind="text: name"></td>
        <td data-bind="text: salary"></td>
        <td data-bind="text: salaryPercent"></td>
    </tr>
    </tbody>
    <tr>
    <td>Total Salary</td>
    <td data-bind="text: totalSalary"></td>
    </tr>
</table>

view model:

var Teacher = function(id, name, salary) {
    this.id = id;
    this.name = name;
    this.salary = salary;
    this.salaryPercent = ko.computed(function() {
        // return accounting.toFixed((this.salary/178000)*100, 0) + '%';    // works with hard-coded total salary
        return accounting.toFixed((this.salary/viewModel.totalSalary)*100, 0) + '%';
        // return this.salary;    // works, returns the same salary as this.salary above
    }, this);
};

var viewModel = function(teachers) {
    var self = this;
    self.teachers = ko.observableArray(teachers);
    self.totalSalary = ko.computed(function() {
        var total = 0;
        ko.utils.arrayForEach(self.teachers(), function(teacher) { total += teacher.salary; });
        return total;
    });
};

var initialTeachers = [
    new Teacher(1, "Tom", 40000),
    new Teacher(2, "Betty", 41000),
    new Teacher(3, "Charles", 45000),
    new Teacher(4, "Daniel", 52000)
];

var vm = new viewModel(initialTeachers);
ko.applyBindings(vm);

and css:

td, th {
    border: solid 1px black;
    padding: 2px;
}

JSFiddle

TIA, Steve

Note: I'm using the accounting.js library, included with jsfiddle.

1
  • The problem is in the line return accounting.toFixed((this.salary/viewModel.totalSalary)*100, 0) + '%';. viewModel is not defined within the current scope. Commented Aug 12, 2014 at 21:48

2 Answers 2

2

This JSFiddle does what you were looking to do in the first place. I added a function inside viewModel, calculateSalaryPercent, which takes a salary as an argument. I removed salaryPercent from Teacher since it's now calculated at a higher level.

One quick note: calling accounting.toFixed with zero decimal places can result in percentages that add up to less than 100%.

3
  • Sweet - this is what I was looking for. I'm still learning knockout, and had started to put a function in the view model, but couldn't figure out how to call it. It's clear I need to read about $parent and $root! Commented Aug 13, 2014 at 13:09
  • Good! Props to you for taking the time to put it together in JSFiddle. Commented Aug 13, 2014 at 13:22
  • On the percentages not adding up to 100%, yeah, that's somewhat of an issue, but even the requirements document I've got shows whole numbers that add up to 99%. Interestingly, changing to a precision of 1 allows it to add up to 100%, but precision of 2 displays 99.99%. For this particular application, it's really more of a rough estimate and we're replacing a spreadsheet that was already doing the same thing in showing whole numbers. Not an issue for them, but thanks for pointing it out. Commented Aug 13, 2014 at 13:28
1

Besides gorilly's solution, the other way is to build the logic directly on the view itself using knockout's binding context $parent.

But this solution is ugly for people (not me) who pursue "logic-less template".

http://jsfiddle.net/2tgqb4gg/27/

<tbody data-bind="foreach: teachers">
 <tr>
  <td data-bind="text: name"></td>
  <td data-bind="text: salary"></td>
  <td data-bind="text: accounting.toFixed(salary/$parent.totalSalary()*100,0)+'%'"></td>
 </tr>
</tbody>
1
  • For the record, this works, and appreciate very much the additional education here. I just don't/haven't had my brain wrapped around how $parent and $root works yet. Thanks for this. Commented Aug 13, 2014 at 13:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.