如何使用 KnockoutJS 通过 AJAX 观察服务器上的数据?

Posted

技术标签:

【中文标题】如何使用 KnockoutJS 通过 AJAX 观察服务器上的数据?【英文标题】:How to use KnockoutJS to observe data on server via AJAX? 【发布时间】:2011-05-22 22:17:03 【问题描述】:

我玩过knockoutjs 并生成了以下示例,这足以让我对在 javascript 中构建这些视图模型的想法感到兴奋,以便可以以更简单、声明性的方式编写视图,即首先你定义您想要观察的内容,然后使用data-bind 属性定义当您的视图模型以某种方式发生变化时您想要发生的事情

但所有这些都只发生在客户端上。

如何扩展此示例以使用 knockoutjs 来观察服务器上对象的状态,例如通过 AJAX 调用?

index.htm:

<!doctype html>
<html>
    <title>Knockout example</title>
    <head>
        <script type="text/javascript" src="js/knockout-1.1.1.debug.js"></script>
        <script type="text/javascript" src="js/main.js"></script>
        <link rel="stylesheet" href="css/main.css" type="text/css"/>
    </head>
    <body>

        <!-- FIRST AREA -->
        <div class="infobox">
            <div data-bind="visible: noNamesFilled">
                <p>This is an example with NO names filled.</p>
            </div>
            <div data-bind="visible: bothNamesFilled">
                <p>This is an example with both names filled.</p>
            </div>
            <div data-bind="visible: firstNameOnlyFilled">
                <p>This is an example with only the first name filled.</p>
            </div>
            <div data-bind="visible: lastNameOnlyFilled">
                <p>This is an example with the last name filled but not the first name</p>
            </div>
        </div>

        <!-- SECOND AREA -->
        <p>First name: <input data-bind="value: firstName, valueUpdate:'afterkeydown'" /></p>
        <p>Last name: <input data-bind="value: lastName, valueUpdate:'afterkeydown'" /></p>
        <div data-bind="visible: bothNamesFilled">
            <h2 class="normal">Hello, <span data-bind="text: fullName"></span>.</h2>
        </div>
        <div data-bind="visible: firstNameOnlyFilled">
            <h2 class="informal">Hi there <span data-bind="text: fullName"></span>!</h2>
        </div>
        <div data-bind="visible: lastNameOnlyFilled">
            <h2 class="formal">Hello, Mr. <span data-bind="text: fullName"></span>.</h2>
        </div>

        <!-- THIRD AREA -->
        <div data-bind="visible: noNamesFilled">
            <p><span class="bad">:-(</span> Please fill in both names.</p>
        </div>
        <div data-bind="visible: bothNamesFilled">
            <p><span class="good">:-)</span> Good job, both names are filled!</p>
        </div>
        <div data-bind="visible: firstNameOnlyFilled">
            <p><span class="ok">:-(</span> Please fill in the last name, too.</p>
        </div>
        <div data-bind="visible: lastNameOnlyFilled">
            <p><span class="ko">:-(</span> Please fill in the first name as well.</p>
        </div>
    </body>
</html>

ma​​in.css:

*  margin: 0; padding: 0
body  margin: 10px
p  margin: 10px
.infobox 
    background-color: #eee;
    width: 300px;
    height: 100px;
    padding: 10px;

.informal 
    color: purple;
    font-family: arial;

.normal 
    color: black;
    font-family: new courier;

.formal 
    color: black;
    font-size: 11pt;
    font-family: times roman;
    background-color: #eee;

.good 
    width: 20px;
    background-color: lightgreen;

.ok 
    width: 20px;
    background-color: yellow;

.bad 
    width: 20px;
    background-color: tomato;

ma​​in.js:

window.onload= function() 

    var viewModel = 
        firstName : ko.observable(''),
        lastName : ko.observable('')
    ;
    viewModel.fullName = ko.dependentObservable(function () 
        return viewModel.firstName() + " " + viewModel.lastName();
    );

    viewModel.bothNamesFilled = ko.dependentObservable(function () 
        return viewModel.firstName().length > 0 && viewModel.lastName().length > 0;
    , this);
    viewModel.firstNameOnlyFilled = ko.dependentObservable(function () 
        return viewModel.firstName().length > 0 && viewModel.lastName().length == 0;
    , this);
    viewModel.lastNameOnlyFilled = ko.dependentObservable(function () 
        return viewModel.firstName().length == 0 && viewModel.lastName().length > 0;
    , this);
    viewModel.noNamesFilled = ko.dependentObservable(function () 
        return viewModel.firstName().length == 0 && viewModel.lastName().length == 0;
    , this);

    ko.applyBindings(viewModel);

【问题讨论】:

【参考方案1】:

我会使用 setTimeout 来调用使用 JQuery 进行 $.ajax 调用的函数。当它返回 JSON 数据时,将该数据设置为您的视图模型,最后再次 setTimeout 以调用该函数。

【讨论】:

【参考方案2】:

这是一个更新的示例,主要更新 main.js 以与 JQuery 一起执行 ajax 调用。

HTML 文件包含 Knockout 3 而不是 1。HTML 还包含最新的 JQuery 以使 JQuery 功能正常工作。

js/server_data.js 在那里,因此您可以从一些有效的 json 数据开始。您可以将 $.ajax 设置中的 url 更改为您拥有的任何服务器端脚本,但尝试将其内容类型设置为 application/json。例如,php 脚本可以将 Content-type 标头设置为: header('Content-type: application/json');在以 JSON 格式打印数据之前。

新的 main.html:

<!doctype html>
<html>
    <title>Knockout example</title>
    <head>
        <script type="text/javascript" src="js/knockout-3.0.0.debug.js"></script>
        <script src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script type="text/javascript" src="js/main.js"></script>
        <link rel="stylesheet" href="css/main.css" type="text/css"/>
    </head>
    <body>

        <!-- FIRST AREA -->
        <div class="infobox">
            <div data-bind="visible: noNamesFilled">
                <p>This is an example with NO names filled.</p>
            </div>
            <div data-bind="visible: bothNamesFilled">
                <p>This is an example with both names filled.</p>
            </div>
            <div data-bind="visible: firstNameOnlyFilled">
                <p>This is an example with only the first name filled.</p>
            </div>
            <div data-bind="visible: lastNameOnlyFilled">
                <p>This is an example with the last name filled but not the first name</p>
            </div>
        </div>

        <!-- SECOND AREA -->
        <p>First name: <input data-bind="value: firstName, valueUpdate:'afterkeydown'" /></p>
        <p>Last name: <input data-bind="value: lastName, valueUpdate:'afterkeydown'" /></p>
        <div data-bind="visible: bothNamesFilled">
            <h2 class="normal">Hello, <span data-bind="text: fullName"></span>.</h2>
        </div>
        <div data-bind="visible: firstNameOnlyFilled">
            <h2 class="informal">Hi there <span data-bind="text: fullName"></span>!</h2>
        </div>
        <div data-bind="visible: lastNameOnlyFilled">
            <h2 class="formal">Hello, Mr. <span data-bind="text: fullName"></span>.</h2>
        </div>

        <!-- THIRD AREA -->
        <div data-bind="visible: noNamesFilled">
            <p><span class="bad">:-(</span> Please fill in both names.</p>
        </div>
        <div data-bind="visible: bothNamesFilled">
            <p><span class="good">:-)</span> Good job, both names are filled!</p>
        </div>
        <div data-bind="visible: firstNameOnlyFilled">
            <p><span class="ok">:-(</span> Please fill in the last name, too.</p>
        </div>
        <div data-bind="visible: lastNameOnlyFilled">
            <p><span class="ko">:-(</span> Please fill in the first name as well.</p>
        </div>
    </body>
</html>

js/main.js:

$(document).ready( function() 

    var viewModel = 
        firstName : ko.observable(''),
        lastName : ko.observable('')
    ;
    viewModel.fullName = ko.dependentObservable(function () 
        return viewModel.firstName() + " " + viewModel.lastName();
    );

    viewModel.bothNamesFilled = ko.dependentObservable(function () 
        return viewModel.firstName().length > 0 && viewModel.lastName().length > 0;
    , this);
    viewModel.firstNameOnlyFilled = ko.dependentObservable(function () 
        return viewModel.firstName().length > 0 && viewModel.lastName().length == 0;
    , this);
    viewModel.lastNameOnlyFilled = ko.dependentObservable(function () 
        return viewModel.firstName().length == 0 && viewModel.lastName().length > 0;
    , this);
    viewModel.noNamesFilled = ko.dependentObservable(function () 
        return viewModel.firstName().length == 0 && viewModel.lastName().length == 0;
    , this);

    ko.applyBindings(viewModel);

    // send request to the server to download the server's model information.
    $.ajax(
    
        'url': 'js/server_data.js',
        'dataType': 'json',
        'method': 'post',
        'error': function(jqXHR, textStatus, errorThrown)
        
            // error callback in case you play with this code and run into trouble.
            alert('There was a problem handling the ajax request.  The error information is: jqXHR: '
            +jqXHR+", textStatus: "+textStatus+", errorThrown: "+errorThrown);
        ,
        'success': function(data)
        
            // when it is downloaded and parsed to create the "data" parameter, update the viewModel.
            viewModel.firstName(data.firstName);
            viewModel.lastName(data.lastName);
        
    
    );

);

js/server_data.js 表示可能来自数据库的动态生成的数据:


    "firstName": "John",
    "lastName": "Doe"

jsteve 有正确的总体思路,但如果您只想在页面加载时下载数据,请不要使用 setTimeout。相反,请使用 JQuery 的文档就绪回调和 JQuery 的 ajax 成功回调,以便事情在您希望的时候准确运行。

如果您想持续侦听服务器中数据的更改并对其做出反应,请研究长轮询技术。与需要频繁向服务器发出新请求的忙等待相比,长轮询器更有效且计时更准确。

【讨论】:

以上是关于如何使用 KnockoutJS 通过 AJAX 观察服务器上的数据?的主要内容,如果未能解决你的问题,请参考以下文章

knockoutjs:使用 ajax 调用发送 MultipartFile 和其他数据

KnockoutJS,ajax 调用后更新 ViewModel

当页面通过ajax作为部分加载时,如何重新绑定淘汰视图模型?

将 knockoutjs 视图模型传递给多个 ajax 调用

将 KnockoutJS 可观察数组传递给 HTTP Post 控制器方法的 AJax 调用失败

使用 knockoutjs 时 Chrome 中的 Maxlength 约束验证异常