【问题标题】:Using Knockout and Breeze with Cascading Dropdowns使用带有级联下拉菜单的 Knockout 和 Breeze
【发布时间】:2013-08-10 22:32:00
【问题描述】:

所以我已经来回讨论了很长时间了,所以我会直奔主题。

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

TLDR; 2 选择,第一个选择的选项定义了对第二个选项的查询。查询有效,可观察对象被填充,第一次选择总是被填充,第二次永远不会在第一次启动时,但总是在下面的 ctrl+F5 上。

以下是有关此应用程序的一些 sn-ps: 视图模型:

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

我已经尝试了几乎所有我能想到的东西,并在谷歌上搜索了所有想到的东西,但无济于事。任何帮助将不胜感激!另外,这是我第一次在这里发帖,如有错误,我深表歉意!

【问题讨论】:

    标签: javascript knockout.js breeze


    【解决方案1】:

    这里有几个cmets -

    你的观点毫无意义。如果您使用的是 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 将为空,直到您选择一个模型,然后它会出去并获取该模型的属性。

    了解您使用的函数声明之间的区别也很重要。 var myFunc = 函数 () {};是一个构造函数,将立即评估视图模型实例化。 function myFunc () {} 是一个标准函数,会等到被调用后再计算。

    【讨论】:

    • 非常感谢您的回复!我已经尝试了您的建议,但似乎仍然存在问题(第二个选择现在从未填充)。查询调用更干净!所以我继续订阅(onChange)modelArr 和modelProperties。似乎 modelArr 使用所需的属性进行了更新,但 modelProperties 仍未定义,我再次感到困惑。唯一想到的是计算函数在 modelArr 实际填充之前结束(datacontext 函数太慢,promise 有问题?),但我只是在尝试
    • 哦,还有一个注意事项。当我在 datacontext.getModelProperties 函数之后添加 return(modelArr()) 时,第二个列表确实被填充但 1 记号太晚了(最初为空白,从第一个框中选择另一个项目,然后加载前一个(汽车)属性等等上)。
    • 当然,如果您完全使用我的代码,您不会将名称传递给您的函数,则需要 selectedModel().name() 或其他东西。至于异步检索数据时的时间淘汰更新,不是这样。
    • 糟糕,我们在设置 myArr 的值后从未返回它 - 现在应该可以工作,或者至少需要很少的调整才能让它工作。您是从本地缓存中获取模型属性还是访问服务器?
    • 我想你提到了:datacontext.getModelProperties(modelArr, selectedModel()).then(function() { return modelArr(); }); (在那之前缺少一个“)”):) 实际上, selectedModel() 做得很好(它只是一个绑定到所选值的可观察对象,它正确地将“汽车”传递给查询并且查询完成)。我正在从服务器检索数据。即使添加了 .then,控制台再次显示查询成功,但第二个下拉列表仍未更新 =(
    【解决方案2】:

    我对这个问题有点晚了,但这就是我能够完成级联下拉菜单的方式。我希望这可以帮助任何为此苦苦挣扎的人。

    视图模型

            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>
    

    数据上下文/服务

            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");
            }
    
        };    
    

    【讨论】:

      猜你喜欢
      • 2013-05-04
      • 2014-03-20
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-28
      • 2013-08-06
      • 2020-04-27
      相关资源
      最近更新 更多