【问题标题】:MVC Model Binding before KnockoutJS Model BindingKnockoutJS 模型绑定之前的 MVC 模型绑定
【发布时间】:2012-06-24 00:36:46
【问题描述】:

那么,如果你的 Controller Action 返回一个带有预填充值的模型,你如何让 KnockoutJS 知道它们?

例如:

@Html.TextBoxFor(m => m.Title, new { data_bind="value: title"} )

但是,在我绑定 knockout.js ViewModel 的 $(document).ready() 上,此值尚未填充:

$(document).ready({
  var viewModel = {
    title: ko.observable($("#Title").val()) // too early for this?!
  }

  ko.applyBindings(viewModel);​
});

如何使 KnockoutJS 与 MVC 的模型绑定一起工作? 我发现的一种解决方法是在我的 Razor 视图中设置 JavaScript 变量,如下所示:

<script>
  var strTitle = '@Model.Title';
</script>

然后在 Knockout 模型绑定中使用它。这行得通,但我讨厌它。如果您的表单有数百个字段怎么办?您不希望页面中有那么多 JavaScript 变量。 我在这里错过了显而易见的事情吗?

【问题讨论】:

    标签: asp.net-mvc razor knockout.js


    【解决方案1】:

    这似乎类似于this question。通常,您可以通过在脚本中将 @Model 转换为 JSON 来设置视图模型:

    <script type="text/javascript">
    var model = @(new HtmlString(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model)));
    </script>
    

    您还可以创建自己的绑定处理程序,该处理程序最初会根据控制值加载视图模型。这个新的myvalue 处理程序基本上调用了现有的value 处理程序,除了它 init 上的初始控制值更新视图模型。

    ko.bindingHandlers['myvalue'] = {
        'init': function (element, valueAccessor, allBindingsAccessor) {
            // call existing value init code
            ko.bindingHandlers['value'].init(element, valueAccessor, allBindingsAccessor);
    
            // valueUpdateHandler() code
            var modelValue = valueAccessor();
            var elementValue = ko.selectExtensions.readValue(element);
            modelValue(elementValue); // simplified next line, writeValueToProperty isn't exported
            //ko.jsonExpressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'value', elementValue, /* checkIfDifferent: */ true);
        },
        'update': function (element, valueAccessor) {
            // call existing value update code
            ko.bindingHandlers['value'].update(element, valueAccessor);
        }
    };
    

    然后当你调用 ko.applyBindings 时,你的 observable 将根据控件的初始值进行设置:

    <input type="text" data-bind="myvalue: Title" value="This Title will be used" />
    <input type="text" data-bind="value: Title" value="This will not be used" />
    <!-- MVC -->
    @Html.TextBoxFor(m => m.Title, new { data_bind="myvalue: Title"} )
    

    SAMPLE FIDDLE

    【讨论】:

    • 谢谢,不幸的是,这似乎对我不起作用:(由于这条线,ko 模型绑定后值消失了:"viewModel.Title = ko.observable()"
    • ...如果我用 viewModel.Title = ko.observable(viewModel.Title) 设置初始值,knockout.validation.js 会抛出“Uncaught TypeError”
    • @Tsar - 我更新了答案以使其工作并给出了一个示例小提琴, ko.jsonExpressionRewriting.writeValueToProperty 函数未导出,仅适用于淘汰赛的调试版本,我将其更改为一个更简单的调用,只要 Title 是一个 observable 就可以工作。
    【解决方案2】:

    使用 JSON.NET 或类似方法将整个页面模型简单地序列化为 json 怎么样。然后,您的页面将通过非 js 用户的普通 razor 视图绑定填充。那么你的页面脚本可以是这样的:

    <script>
        ko.applyBindings(@Html.ToJSON(Model));
    </script>
    

    或者如果你有一个类型化的视图模型

    <script>
        var viewModel = new MyViewModel(@Html.ToJSON(Model));
        ko.applyBindings(viewModel);
    </script>
    

    将客户端和实际视图模型构造成相同是有意义的,因此不需要对 json 形状进行操作。

    编辑

    toJSON 帮助器示例。

    public static MvcHtmlString ToJson(this HtmlHelper html, object obj)
    {
      JavaScriptSerializer serializer = new JavaScriptSerializer();
      return MvcHtmlString.Create(serializer.Serialize(obj));
    }
    

    希望这会有所帮助。

    【讨论】:

    • toJSON() 是从哪里来的?我需要在我的 MVC 模型中编写此方法吗?
    • 是的,对不起,真的应该解释一下。写在手机上:) 编辑举例。
    • @JasonGoemaat - 不,我不是好地方。应该学会在我可以运行代码之前永远不要回答问题。干杯。
    【解决方案3】:

    因为我没有 50 分的声誉来向 Jason Goemaat answer 添加评论,所以我决定在此处添加我的评论作为答案。

    所有的功劳归于 Jason Goemaat。

    我无法让代码为我工作。所以我不得不做一个小改动。

            ko.bindingHandlers['myvalue'] = {
        'init': function (element, valueAccessor, allBindingsAccessor) {
            //get initial state of the element            
            var modelValue = valueAccessor();
            var elementValue = ko.selectExtensions.readValue(element);
    
            // call existing value init code
            ko.bindingHandlers['value'].init(element, valueAccessor, allBindingsAccessor);
    
            //Save initial state
            modelValue(elementValue);
        },
        'update': function (element, valueAccessor) {
            // call existing value update code
            ko.bindingHandlers['value'].update(element, valueAccessor);
        }
    };
    

    如果我在顶部有这条线,

    // call existing value init code
    ko.bindingHandlers['value'].init(element, valueAccessor, allBindingsAccessor);
    

    它正在删除元素的原始状态。所以无论我在输入字段中有什么值,它都会被删除。

    在模型里面我有这个:

    //publishing comment
    self.publishingComment = ko.observable();
    

    我的 MVC 看起来像这样

    @Html.TextBoxFor(model => model.Comment, new { data_bind = "myvalue: publishingComment" })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多