7

我只是在使用 MVC-Web-API 研究 knockout.js,我正在尝试创建一个 Hello World 页面,该页面将每 5 秒更新一次页面上的时间。它每 5 秒调用一次,我可以在我的控制器(断点)中看到它,但屏幕上仍然没有显示任何内容。

更新:我仍在努力,现在我已经确定我正在从服务器获取数据,每 5 秒对控制器进行一次调用,并且它正在返回我需要的 JSON(正在显示警报this) 但是页面上的 span 元素上仍然没有显示任何内容。

我实际上需要使用映射功能,因为我正在开发一个更大的网站,该网站有一个具有 50 多个属性的模型,并且不特别想通过并将它们单独映射到视图模型中。

我在下面包含了我的代码。

<span data-bind="text: TimeString"></span>

<script type="text/javascript">
    var viewModel;
var getUpdates = setInterval(function () {
    $.getJSON(
        "/Values/Get", {},
        function (model) {
            alert(model.TimeString);
            ko.mapping.fromJS(model, viewModel);
        });
}, 5000);

$(document).ready(
    function () {
        $.getJSON(
            "/Values/Get", {},
            function (model) {
                var viewModel = ko.mapping.fromJS(model);
                alert(model.TimeString);
                ko.applyBindings(viewModel);
            });
    });

function bindViewModel(model) {
    ko.applyBindings(model);
}

public class HelloWorldModel
{
    public DateTime TimeDT { get; set; }
    public String TimeString { get; set; }
}

    public class ValuesController : Controller
{
    public HelloWorldModel Model = new HelloWorldModel();

    [System.Web.Mvc.AcceptVerbs(HttpVerbs.Get)]
    public JsonResult Get()
    {
        Model.TimeDT = DateTime.Now;
        Model.TimeString = Model.TimeDT.ToString("HH:mm:ss");

        return Json(Model, JsonRequestBehavior.AllowGet);
    }

    // POST api/values
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    public void Delete(int id)
    {
    }
}
}
4

3 回答 3

6

如果您遵循文档,则应该不会太难。在您第一次调用服务器时,请执行以下操作:

var viewModel = ko.mapping.fromJS(model);
ko.applyBindings(viewModel);

您正在使用 JS 对象应用绑定(如果我正确阅读文档,getJSON 返回一个 JS 对象,而不是 JSON 字符串)。

之后,在您重复的功能中,执行以下操作:

ko.mapping.fromJS(model, viewModel);

从文档中:

  • 对象的所有属性都转换为可观察对象。如果更新会更改值,它将更新可观察对象。
  • 数组被转换为可观察数组。如果更新会改变项目的数量,它将执行适当的添加/删除操作。它还将尝试保持与原始 JavaScript 数组相同的顺序。
于 2013-07-04T15:44:35.087 回答
6

您不需要替换完整的视图模型,而是可以更新从 Ajax 请求返回的属性,如下所示:

$(function() {
    var vm = {
        TimeDT: ko.observable(),
        TimeString: ko.observable()
    };

    function updateValues() {    
        $.getJSON("/Values/Get").done(function(data) {
            vm.TimeDT(data.TimeDT);
            vm.TimeString(data.TimeString);
        });
    }

    ko.applyBindings(vm);

    updateValues();
    setInterval(updateValues, 5000);
});

你可以在这里看到我在 JsFiddle 中制作的一个小例子。

于 2013-07-04T16:08:38.527 回答
3

免责声明:我和本一起工作。

代码存在一些问题,首先是您缺少一些 javascript 引用,其次每次计时器循环时 viewModel 对象始终为空。

您需要从此处下载敲除映射 Javascript 文件,将其命名为 knockout.mapping-latest.js 并将其保存在 Scripts 目录中。然后确保添加了对 jquery 和 knockout.js 的引用。

更新后的 Razor 视图如下:

<div id="body">

    <span data-bind='text: TimeString'></span>

    <script src="~/Scripts/jquery-1.8.2.js" type="text/javascript"></script>
    <script src="~/Scripts/knockout-2.2.0.debug.js" type="text/javascript"></script>
    <script src="~/Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
    <script type="text/javascript">
        var viewModel;
        var getUpdates = setInterval(function () {
            $.getJSON(
                "/Values/Get", {},
                function (model) {
                    //alert(model.TimeString);
                    ko.mapping.fromJS(model, viewModel);
                });
        }, 5000);

        var viewModelSet = false;

        $(document).ready(
            function () {
                $.getJSON(
                    "/Values/Get", {},
                    function (model) {
                        viewModel = ko.mapping.fromJS(model);
                        ko.applyBindings(viewModel);
                    });
            });

        function bindViewModel(model) {
            ko.applyBindings(model);
        }
    </script>    

</div>

补充一点,类中的公共字段通常是不可行的,在您的 ViewModel 中,您的 HelloWorldModel 实例不会从代码中的其他任何地方访问,只能从该类中访问,因此它可以是私有的。如果它是从其他地方访问的,最好的做法是将其保密,并通过属性将其公开。更多信息在这里

于 2013-07-05T13:11:37.573 回答