Knockout.js - 使用新值每5秒更新一次页面

时间:2013-07-04 15:08:38

标签: jquery asp.net-mvc knockout.js asp.net-web-api

我只是在使用MVC-Web-API查看knockout.js,我正在尝试创建一个Hello World页面,它将每5秒更新页面上的时间。它每隔5秒拨打一次电话,我可以在我的控制器(断点)中看到这个,但屏幕上仍然没有显示。

更新: 我一直在研究这个问题,现在我已经确定我从服务器获取数据,每5秒钟调用一次控制器,它返回我需要的JSON(警报显示这个)但是页面上的span元素上仍然没有显示任何内容。

我实际上需要使用映射功能,因为我正在开发一个更大的网站,它拥有一个包含50多个属性的模型,并且不特别想要在viewmodel中单独映射它们。

我在下面提供了我的代码。

<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)
    {
    }
}
}

3 个答案:

答案 0 :(得分:6)

如果你遵循documentation,那就不应该太难了。在第一次调用服务器时,请执行以下操作:

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

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

之后,在您的重复功能中,执行:

ko.mapping.fromJS(model, viewModel);

来自文档:

  
      
  • 对象的所有属性都将转换为可观察对象。如果更新会更改值,则会更新observable。
  •   
  • 将数组转换为可观察数组。如果更新会更改项目数,则会执行相应的添加/删除   动作。它还会尝试保持订单与原始订单相同   JavaScript数组。
  •   

答案 1 :(得分:4)

您不需要替换完整的视图模型,而是可以更新从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中制作的small example

答案 2 :(得分:3)

免责声明:我与Ben合作。

代码存在一些问题,第一个是缺少一些javascript引用,其次,每次定时器循环时,viewModel对象始终为null。

您需要从here下载淘汰映射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实例无法从代码中的任何其他位置访问,只能从该类中访问,因此它可以是私有的。如果从其他地方访问它,最好的做法是将其保密,并通过属性公开。更多信息here