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

时间:2010-12-09 15:05:41

标签: javascript ajax mvvm knockout.js

我和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>

的main.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;
}

main.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);
}

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

这是一个更新的示例,主要更新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格式打印出数据之前。

new 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成功回调,这样就可以在你想要的时候运行。

如果您想持续监听并响应服务器中数据的更改,请查看长轮询技术。长轮询器比忙于等待需要经常向服务器发出新请求更有效且精确定时。