Knockout JS创建脏标志

Knockout JS Creating a Dirty flag

本文关键字:标志 创建 JS Knockout      更新时间:2023-09-26

我有一个ASP.NET MVC项目,我正在将IEnumerable类型的Model转换为JS字符串,并存储在隐藏输入中。然后,我在applyBindings时间将该字符串解析为一个viewModel对象,元素上的databind="foreach:rows"绑定到该对象。该系统是我工作的地方内部开发的MVC框架的一部分,需要构建为一个易于重用的系统。主要的设计目标是让消耗代码只构建一个具有驱动布局的属性的.NET ViewModel。我试图防止开发人员需要编写JS视图模型来匹配。

我在一个示例项目中用于初始化绑定的JS如下:

var thingy = function(rowData){
    rows = ko.mapping.fromJS(rowData);
};

var el1 = $("#someGrid > tbody");
if (el1.length > 0) {
    var dataStr = el1.attr("data-ko-data");
    var data = JSON.parse(dataStr);
    var vm = thingy(data);
    ko.applyBindings(vm, el1[0]);
}

我的.NET POCO看起来是这样的:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; } 
    public string Surname { get; set; }
    public int Age { get; set; }
    public bool IsDirty { get; set; }
    public Tuple<string, Type>[] Properties()
    {
        var propInfos = this.GetType().GetProperties();
        var ret = propInfos.Select(i => new Tuple<string, Type>(i.Name, i.PropertyType));
        return ret.ToArray();
    }
}

表单上的每个表都有一个"保存更改"按钮,用于扫描表的视图模型,并将标记为IsDirty=true的行发布回MVC操作进行保存。

$(".gridSaveButton").click(function () {
    var theUrl = $(this).attr("data-saveurl");
    var theTable = $(this).siblings("table"); 
    var dirtyRows = [];
    var theBody = theTable.children("tbody");
    var trs = theBody.children("tr");
    trs.each(function () {
        var row = $(this);
        var modelForRow = ko.dataFor(row[0]);
        if(modelForRow.IsDirty)
        {
            dirtyRows.push(modelForRow);
        }
    });
    var theData = ko.toJSON(dirtyRows);
    $.ajax({
        url: theUrl,
        type: "POST",
        contentType: "application/json",
        data: theData,
        success: function (status) {
            alert("Success: " + status.Success);
        },
        error: function (request, status, theError) {
            alert(theError);
        }
    });
});

因此,上述工作如预期。我遇到的问题是,当修改对象上的任何属性时,如何将特定行的IsDirty值设置为true。到目前为止,我在网上发现的每一个例子都涉及将IsDirty设置为基于某些其他ko.observable的ko.computed,但我不能直接这样做,因为用户必须为每种类型编写一个显式的JS视图模型。

我试图创建一个自定义绑定,但init和update都没有被调用,所以我有点迷失了方向,就这一点而言,这是否是正确的方法。

有没有人有过这种事情的经验,知道当对象的声明是隐式的时,我如何简单地响应对象上的任何其他变量?

--Steve

好的,所以我使用了这个示例作为基础,并使它工作得很好。http://jsfiddle.net/rniemeyer/7Nsuh/

这是一个修改后的版本,以满足我使用ko.mapping.fromJS的需求,尽管来自Ryan的原始versionhttp://jsfiddle.net/rniemeyer/dtpfv/viewModel上有一个dirtyItems列表。有了修改后的方法,有人知道如何将计算的dirtyItems添加到koRowMapping中吗?

我试过了,但绑定失败了,我甚至不确定这种方法是否正确:

var koRowMapping = {
    rows: {
        create: function (options) {
            return createRow(options.data);
        }
    },
    dirtyItems: ko.computed(function() {
        return ko.utils.arrayFilter(this.rows, function(row) {
            return row.dirtyFlag.isDirty();
        });
    }, this)
};

Roighto!!

我最终到达了那里。

因此,这与Ryan的原始示例一样:

var koRowMapping = {
    rows: {
        create: function (options) {
            return createRow(options.data);
        }
    }
};
var createRow = function (row) {
    var result = ko.mapping.fromJS(row);
    result.dirtyFlag = ko.dirtyFlag(result);
    return result;
}
ko.dirtyFlag = function (root, isInitiallyDirty) {
    var result = function () { },
        _initialState = ko.observable(ko.toJSON(root)),
        _isInitiallyDirty = ko.observable(isInitiallyDirty);
    result.isDirty = ko.computed(function () {
        return _isInitiallyDirty() || _initialState() !== ko.toJSON(root);
    });
    result.reset = function () {
        _initialState(ko.toJSON(root));
        _isInitiallyDirty(false);
    };
    return result;
};

然后在视图模型上放置dirtyItems和全局脏标志:

$(document).ready(function () {
    var people = '{"rows":[{"FirstName":"Steve","LastName":"O"},{"FirstName":"Someone","LastName":"Else"}]}';
    var vm = ko.mapping.fromJSON(people, koRowMapping, {});
    vm.dirtyItems = ko.computed(function() {
        return ko.utils.arrayFilter(this.rows(), function(item) {
            return item.dirtyFlag.isDirty();
        });
    }, vm);
    vm.isDirty = ko.computed(function () {
        return this.dirtyItems().length > 0;
    }, vm);

    var el = $("#theTable");
    ko.applyBindings(vm, el[0]);
}

太棒了!!!!