문제

I think I've tried everything on this one, but I cannot figure this out. I'm simply trying to update the total price for each row in a table when the user increases the quantity. So far I've tried

  • math in the HTML: data-bind="text: parseFloat((total * quantity), 10)"
  • using ko.computed() (which "works" but returns the same value for each row's total)
  • subscribing to an event
  • looping through each observableArray's item with ko.utils.arrayForEach and jQuery $.each()
  • adding a ko.computed property with a create() function as part of a mapping option, but I didn't really understand that one.

Here's a fiddle. If anyone has any suggestions as to how I can accomplish this seemingly simple task I'd appreciate it.

Most of the failed attempts are in the comments on that fiddle. The closest I've come was the ko.computed but I could only get it to return one value - the value for the last row in the table. Thanks

도움이 되었습니까?

해결책

Depends what you want to achieve. For simple display purpose a function will do:

viewModel.calcTotal = function ( row ) {
    return parseFloat(( row.total() * row.quantity() ), 10);
};

There is special variable in for loop $data that will pass your row data:

<td><span data-bind="text: $root.calcTotal($data)"></span></td>

Also, your first point with math in HTML will work if you add parentheses. Simple form of binding observables won't work in expressions.

data-bind="text: parseFloat(( total() * quantity() ), 10)"

다른 팁

I have implemented a working version, I am not too well versed in knockout though so I am not sure if it's "correct".

See the following fiddle http://jsfiddle.net/YeSZ8/7/.

I've created a model for each row called ItemModel.

It's defined like this

var ItemModel = function (arg) {
    var that = this;

    this.supplier     = arg.supplier;
    this.itemNumber   = arg.itemNumber;
    this.description  = arg.description;
    this.quantity     = ko.observable(parseInt(arg.quantity, 10));
    this.price        = arg.price;
    this.total        = ko.computed(function () {
        return that.price * that.quantity();
    });
};

It handles computing the new total value. Instead of using mapping.fromJSON which might be more correct I have loaded the json manually and populated the main viewmodel with several rows.

EDIT: I read some about about the mapping plugin and I've come to the conclusion that it should be used with the create method to initiate the ItemModel instances.

EDIT2: Fixed broken filtering, http://jsfiddle.net/YeSZ8/8/

here is a solution using the mapping plugin:

....
var mappingOptions = {
    'cartItemsList': {
        create: function (options) {
            var result = ko.mapping.fromJS(options.data, {});
            result.total = ko.computed(function () {
                return result.quantity() * parseFloat(result.price());
            });
            return result;
        }
    }
};

var model = {cartItemsList: JSON.parse(jsonData)};
var viewModel = ko.mapping.fromJS(model, mappingOptions);
viewModel.filter = ko.observable("");
...

The adapted fiddle: http://jsfiddle.net/YeSZ8/10/

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top