使用Knockout和Breeze以及级联下拉列表

时间:2013-08-09 02:03:03

标签: javascript knockout.js breeze

所以我现在已经来回这么久了,所以我会谈到这一点。

我正在创建一个基于HotTowel模板的应用程序,所以我正在使用knockout,breeze,Q等。我正在使用一个轻微的查询来从服务器获取一些数据,然后我将这些数据加载到第一个选择(作为选项)。这会更改selectedModel observable和订阅触发器(订阅是当前的“解决方案”,我使用了数据绑定等具有相同的结果)。然后,订阅获取新的selectedModel值,并使用它来获取第二个observable的数据。此查询也会传递,结果存储在modelProperties可观察数组中,但UI不会更新第二个选择(它是空的)。奇怪的是,按ctrl + F5(我连续尝试了50次)总是正确地填充它,但从来没有在第一次加载。

TLDR; 2选择,第一个选择的选项定义第二个选项的查询。查询工作,observables填充,首先选择总是填充,第二次从不在第一次启动但总是在以下ctrl + F5。

以下是有关此应用程序的一些摘要: viewmodel:

define(['services/logger', 'services/datacontext'], function (logger, datacontext) {
    var models = ko.observableArray();
    var modelProperties = ko.observableArray();
    var selectedModel = ko.observable();
    var init = true;

    function activate() {
        logger.log('Search View Activated', null, 'search', true);
        return datacontext.getModels(models);
    }

    var sub = selectedModel.subscribe(function (newValue) {
        return datacontext.getModelProperties(modelProperties, newValue);
    });

    var vm = {
        activate: activate,
        models: models,
        selectedModel: selectedModel,
        modelProperties: modelProperties,
        title: 'Search View'
    };

    return vm;

视图的代码:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body id="one">
    <select id="entitySelect" class ="entitySelect" name="first"
        data-bind="options: models, value: selectedModel">
    </select>
    <select id="propertySelect" class ="propertySelect" data-bind=
    'options:modelProperties'></select>
</body>
</html>

datacontext中的方法:

        var getModels = function (modelsObservable) {
        var query = EntityQuery.from('Models');
        return manager.executeQuery(query)
            .then(querySucceeded)
            .fail(queryFailed);

        function querySucceeded(data) {
            logger.log("Query succeeded", true);
            logger.log(data);
            if (modelsObservable) {
                modelsObservable(data.results);
            }
            logger.log('Retrieved [Models] from remote data source',
                data, true);
        }
        function queryFailed(data) {
            logger.log(data.toString(), data, true);
        }
    };

    var getModelProperties = function (propertiesObservable,modelName) {
        var query = EntityQuery.from('ModelProperties').withParameters({ name: modelName });
        return manager.executeQuery(query)
            .then(querySucceeded)
            .fail(queryFailed);

        function querySucceeded(data) {
            logger.log("Query succeeded", null, true);
            logger.log(data);
            if (propertiesObservable) {
                propertiesObservable(data.results);
            }
            logger.log('Retrieved [Properties] from remote data source',
                data, true);
        }
        function queryFailed(data) {
            logger.log(data.toString(), data, true);
        }
    };

我再次指出所有查询都会通过,并且observableArrays会填充结果(使用.peek()进行检查)。

以下是一些澄清问题的截图: 从VS首次启动时: http://i.imgur.com/8Gd53Yh.png

然后,按ctrl + F5 http://i.imgur.com/vzO8d70.png

我已经尝试了几乎所有我能想到的东西,并用Google搜索了所想到的一切,但无济于事。任何帮助将不胜感激!另外,这是我在这里的第一篇文章,所以我为任何错误道歉!

2 个答案:

答案 0 :(得分:1)

以下是一些评论 -

你的观点毫无意义。如果您使用类似HotTowel模板的东西,那么在那里有很多额外的标记,考虑到您最有可能使用Durandal.js进行合成,而额外的标记可能会伤害到您。

如果您确实或多或少地加载了“子视图”,那么它应该是这样的 -

<select id="entitySelect" class ="entitySelect" name="first" data-bind="options: models, value: selectedModel"></select>
<select id="propertySelect" class ="propertySelect" data-bind='options:modelProperties'></select>

接下来,如果您使用级联下拉列表,我之前已经提到过此方法,我强烈建议所有人使用。使用ko.computed让你的第二个依赖于你的第一个。

var models = ko.observableArray();
var modelProperties = ko.computed(function () {
    var modelArr = ko.observableArray();
    if (!selectedModel()) { return modelArr; }
    datacontext.getModelProperties(modelArr, selectedModel().then(function() { return modelArr(); });
});

现在,在你选择一个模型之前,modelProperties将为null,然后它会出去并获得该模型的属性。

理解您正在使用的函数声明之间的区别也很重要。 var myFunc = function(){};是一个构造函数,将在视图模型实例化时立即进行评估。 function myFunc(){}是一个标准函数,在评估之前会一直等到调用。

答案 1 :(得分:0)

我对这个问题有点迟了,但这就是我如何能够完成级联下拉菜单。我希望这可以帮助任何一直在努力解决这个问题的人。

视图模型

        define(['durandal/system', 'durandal/app', 'jquery', 'knockout', 'services/projectdetailmanager'],
function (system, app, $, ko, pdm) {

        var projectValues = ko.observableArray();
        var taskValues = ko.observableArray();

        activate = function () {
         return pdm.getAllContracts(projectValues);
        }


        selectedProject.subscribe(function () {
        pdm.getSelectedTasks(taskValues, selectedProject().iD()).then(function () {
            return taskValues;
        });
    });

         return {
        activate: activate,            
        projectValues: projectValues,
        selectedProject: selectedProject,
        taskValues: taskValues,
        selectedTask: selectedTask
    };
  });

HTML

<div>
    <table>
        <thead>
            <tr>
                <td style="font-weight:bold;">Projects</td>
                <td style="font-weight:bold;">Tasks</td>                
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>
                    <select data-bind='options: projectValues, optionsText: "name", optionsCaption: "Select...", value: selectedProject'> </select>
                </td>
                <td>
                    <select data-bind='options: taskValues, optionsText: "name", optionsCaption: "Select...", value: selectedTask, event: { change: yourChangeEvent}'> </select>
                </td>
            </tr>
        </tbody>
    </table>        
</div>

的DataContext /服务

        function getAllContracts(projectValues) {
        var query = breeze.EntityQuery
        .from("Contract");

        return manager.executeQuery(query)
        .then(querySucceeded)
        .fail(queryFailed);

        function querySucceeded(data) {
            system.log("Query succeeded");
            system.log(data);

            if (projectValues) {
                projectValues(data.results);
            }
        }
        function queryFailed(data) {
            system.log("Query failed");
        }

    };

    function getSelectedTasks(taskValuesArr, projectID) {
        var query = breeze.EntityQuery
        .from("Task")
        .where("contractID", "==", projectID);

        system.log("Within getSelectedTask; projectID = " + projectID);

        return manager.executeQuery(query)
        .then(querySucceeded)
        .fail(queryFailed);

        function querySucceeded(data) {
            system.log("Query succeeded");
            system.log(data);

            if (taskValuesArr) {
                taskValuesArr(data.results);
            }
        }
        function queryFailed(data) {
            system.log("Query failed");
        }

    };