0

我有与 Knockout.js 几乎完全相同的问题- 数据绑定上的 javascript 函数, 但我使用映射插件。

这是我的视图模型和映射:

var viewModel = ko.mapping.fromJS(data);
viewModel.FromUnixTs = function (uts) {
    var date = new Date(uts * 1000);
    var hours = date.getHours();
    var minutes = date.getMinutes();
    var seconds = date.getSeconds();
    return hours + ':' + minutes + ':' + seconds;
};
ko.applyBindings(viewModel);

这是我的 html 绑定:

<tbody data-bind="foreach: $root">
    <tr class="gv">
        <td data-bind="text: id"></td>
        <td data-bind="text: number"></td>
        <td data-bind="text: FromUnixTs(date_time())"></td>
    </tr>
</tbody>

也试过:

  • <td data-bind="text: FromUnixTs(date_time)"></td>
  • <td data-bind="text: $root.FromUnixTs(date_time())"></td>
  • <td data-bind="text: $root.FromUnixTs(date_time)"></td>
  • <td data-bind="text: date_time"></td>有效,但不像日期时间那样格式化

  • viewModel.prototype.FromUnixTs = function (uts) {

我不断收到的错误是:FromUnixTs is not defined或未找到。除了解决方案之外,我还想为我的错误提供更多背景信息。我做错了什么以及为什么等等。

4

2 回答 2

1

You have several issues. Here's my 2 cts.

  1. Not a biggie, but it's clearer if you could structure your data in a way that the top-level isn't the array itself, but an object with that array, e.g. { items: [/* original data here*/] }.

  2. With the MVVM pattern it's best not to put logic in your view, and text: FromUnixTs(date_time()) borders that. Instead, put all that logic on your view model and just have a text: UnixTx binding. This also works around the problematic code in your question surrounding the prototype stuff.

  3. If you want to augment view models created with the mapping plugin, you can do so by creating mapping options that allow you to tweak the model upon creation.

  4. Finally, a problem that prevents others from helping you: your question contains irrelevant code (the jQuery ajax stuff) making it harder to understand things, and the examples are incomplete and invalid snippets (unclosed tags, etc). In addition, you ask many questions in one, creating a very large question (almost a review request) which SO users tend to shy away from.

If I put all this together (at least 1-3), then I'd suggest a different approach like the following. Update your View to this:

<table>
    <tbody data-bind="foreach: items">
        <tr class="gv">
            <td data-bind="text: id"></td>
            <td data-bind="text: number"></td>
            <td data-bind="text: unixTs"></td>
        </tr>
    </tbody>
</table>

No logic there.

Then, assuming the following data:

var data = {
    items: [{id: 1, number:  42, date_time: 1375948769449},
            {id: 2, number: 106, date_time: 1375948769349}]
};

I'd construct the view model using the mapping plugin like this:

var mapping = {
    'items': {
        create: function (item) {
            return new ItemViewModel(item.data);
        }
    }
};

var viewModel = ko.mapping.fromJS(data, mapping, {});

This uses an ItemViewModel constructor function that augments the mapped VM with the unixTs observable:

var ItemViewModel = function (data) {
    var self = this;
    ko.mapping.fromJS(data, {}, self);
    this.unixTs = ko.computed(function () {
        var date = new Date(self.date_time());
        var hours = date.getHours();
        var minutes = date.getMinutes();
        var seconds = date.getSeconds();
        return hours + ':' + minutes + ':' + seconds;
    });
};

You can see all this at work in this fiddle. Hope this helps.


If you can't change the structure of the data from the server, you can still use the augmented view model version. With a few changes:

// Data not augmented, just the raw array OP gets from the service
var data = [{id: 1,number: 42,date_time: 1375948769449},
            {id: 2,number: 106,date_time: 1375948769349}];

// Augment the data into an object to make a clearer view model:
var viewModel = ko.mapping.fromJS({items: data}, mapping, {});

See this fiddle.

于 2013-08-08T08:34:36.727 回答
0

您不能在这样的对象实例上使用原型,将函数直接添加到参考作品中

http://jsfiddle.net/DGzrR/

var vm = ko.mapping.fromJS(data);
vm.foo = function() {
    console.log("foo");
};

但不是很好的做法,而是做 http://jsfiddle.net/DGzrR/1/

MyViewModel = function(data) {
    this.items = ko.mapping.fromJS(data);
}

MyViewModel.prototype = {
    foo: function() {
        console.log("foo");
        console.log(this.items().length);
    }
};
于 2013-08-08T07:52:16.140 回答