dojox / mvc / getStateful支持层次结构

时间:2014-07-21 19:04:15

标签: dojo

这是一个dojo沙箱,显示了我对getStateful()的使用:http://dojo-sandbox.net/public/7917e/1

似乎getStateful()最初为模型的每个级别创建了watchCallbacks,但是当在按钮中再次调用时,单击getStateful()会在根级别创建watchCallbacks,但不会在我的模型的嵌套级别创建。

我也查看了newStatefulModel,但是文档表明getStateful是后继者,应该使用它。

如果有选项我应该传递给getStateful()来实现这一点,那么它最初是如何工作的呢?

编辑:看起来我的问题不在于getStateful方法,而在于使用ModelRefController.set方法,或者更具体地说是_Controller.set方法。

我在ModelRefController中抛出了一个层次结构,它接受整个层次结构作为新的“模型”值,但只在“模型”(根)上定义了watchCallbacks。

我原本希望它接受提供的对象并在传入的值内的所有级别执行连接,而不必将层次结构中的每个单独对象都设置为ModelRefController。

我可能会采用错误的方式,但我希望有一个模板知道它能够显示的字段的所有细节,并让小部件(控制器)只关注那些属性。在小部件(控制器)中驱动逻辑的模型。

我正在从页面定义生成UI,并且在运行时在UI中提供关于模型属性的元数据的附加装饰。我可以轻松地生成对ModelRefController的必要调用,以将其内容与从后端接收的新数据同步,只是不认为它需要这么多代码。

这是另一个Dojo沙箱:http://dojo-sandbox.net/public/e6946/0

模型的初始值为“Foo”。当新数据被推入包含“Bar”的模型时,它会重新绑定。

2 个答案:

答案 0 :(得分:2)

http://dojo-sandbox.net/public/ef38d/1中的新示例确认应用程序需要“视图模型”,这是UI组件所看到的模型,以包含两个模型以使其工作。

此外,原始问题中的更新意味着期望dojox/mvc/ModelRefController支持“递归路径监视”的概念,尽管它没有。我还有一种印象,dojox/mvc/at支持递归路径监视最有助于http://dojo-sandbox.net/public/ef38d/1以及http://dojo-sandbox.net/public/e6946/0,尽管它不受支持。这种印象特别来自http://dojo-sandbox.net/public/ef38d/1似乎想要关注dataModel.model.nextLevel.title路径(虽然代码没有)。

虽然实现可能不是理想的,但我能想到的最好的方法是让样本工作在这里:

<!DOCTYPE html>
<html>
    <head>
        <title>dojo/Stateful tree with dojox/mvc/getStateful</title>
        <script type="text/javascript"
            src="//ajax.googleapis.com/ajax/libs/dojo/1.10.0/dojo/dojo.js"
            data-dojo-config="parseOnLoad: 0, async: 1, mvc: {debugBindings: 1}"></script>
        <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/dojo/1.10.0/dojo/resources/dojo.css">
        <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/dojo/1.10.0/dijit/themes/claro/claro.css">
        <script type="text/javascript">
            require([
                "dojo/_base/declare",
                "dojo/Stateful",
                "dojo/parser",
                "dijit/Destroyable",
                "dojox/mvc/getStateful",
                "dojox/mvc/parserExtension",
                "dojo/domReady!"
            ], function (declare, Stateful, parser, Destroyable, getStateful) {
                var watchPath = (function () {
                    function getPathComps(path) {
                        return path === "" ? [] : typeof path.splice !== "function" ? path.split(".") : path;
                    }
                    function getObjectPath(o, path) {
                        for (var comps = getPathComps(path), i = 0, l = comps.length; i < l; ++i) {
                            var comp = comps[i];
                            o = o == null ? o : o[comp];
                        }
                        return o;
                    }
                    return function (model, path, callback) {
                        if (model && typeof model.watch === "function") {
                            var comps = getPathComps(path),
                                prop = comps.shift(),
                                remainder = comps,
                                observer = {
                                    prop: prop,
                                    remainder: remainder,
                                    hProp: model.watch(prop, function (name, old, current) {
                                        var hasRemainder = observer.remainder.length > 0;
                                        if (old !== current) {
                                            if (observer.hRemainder) {
                                                observer.hRemainder.remove();
                                                observer.hRemainder = null;
                                            }
                                            observer.hRemainder = watchPath(model[prop], remainder.slice(), callback);
                                        }
                                        callback(hasRemainder ? getObjectPath(old, observer.remainder) : old,
                                            hasRemainder ? getObjectPath(current, observer.remainder) : current);
                                    }),
                                    hRemainder: watchPath(model[prop], remainder.slice(), callback),
                                    remove: function () {
                                        if (this.hRemainder) {
                                            this.hRemainder.remove();
                                            this.hRemainder = null;
                                        }
                                        if (this.hProp) {
                                            this.hProp.remove();
                                            this.hProp = null;
                                        }
                                    }
                                };
                            return observer;
                        }
                    };
                })();

                var States = declare([Stateful, Destroyable], {
                        constructor: function (model) {
                            var self = this;
                        }
                    }),
                    App = declare(Stateful, {
                        firstDisabled: false,
                        secondDisabled: false,
                        model: null,
                        constructor: function () {
                            this.switchModel();
                        },
                        createModel: function () {
                            var model = getStateful({
                                    title: "Foo",
                                    nextLevel: {
                                        title: "Bar",
                                        nextLevel: {
                                            title: "Baz"
                                        }
                                    }
                                }),
                                states = new Stateful({
                                    firstDisabled: model.nextLevel.title === "Foo",
                                    secondDisabled: model.nextLevel.nextLevel.title === "Foo"
                                }),
                                h0 = watchPath(model, "nextLevel.title", function (old, current) {
                                    states.set("firstDisabled", current === "Foo");
                                }),
                                h1 = watchPath(model, "nextLevel.nextLevel.title", function (old, current) {
                                    states.set("secondDisabled", current === "Foo");
                                });
                            model.set("states", states);
                            model.nextLevel.set("states", states);
                            model.nextLevel.nextLevel.set("states", states);
                            model.destroy = function () {
                                if (h0) {
                                    h0.remove();
                                    h0 = null;
                                }
                                if (h1) {
                                    h1.remove();
                                    h1 = null;
                                }
                            }
                            return model;
                        },
                        switchModel: function () {
                            var oldModel = this.get("model"),
                                model = this.createModel();
                            if (oldModel) {
                                oldModel.destroy();
                            }
                            this.set("model", model);
                        }
                    });

                window.app = new App();
                parser.parse();
            });
        </script>
    </head>
    <body class="claro">
        <script type="dojo/require">at: "dojox/mvc/at"</script>
        <div data-dojo-type="dojox/mvc/Group" data-dojo-props="target: at(app, 'model')">
            Selected:
            <span data-mvc-bindings="innerText: at('rel:', 'title')"></span>
            <select type="combo" data-dojo-type="dijit/form/Select"
                    data-dojo-props="value: at('rel:', 'title'), disabled: at('rel:states', 'firstDisabled')">
                <option value="Foo">Foo</option>
                <option value="Bar">Bar</option>
                <option value="Baz">Baz</option>
            </select>

            <div data-dojo-type="dojox/mvc/Group" data-dojo-props="target: at('rel:', 'nextLevel')">
                Selected:
                <span data-mvc-bindings="innerText: at('rel:', 'title')"></span>
                <select type="combo" data-dojo-type="dijit/form/Select"
                        data-dojo-props="value: at('rel:', 'title'), disabled: at('rel:states', 'secondDisabled')">
                    <option value="Foo">Foo</option>
                    <option value="Bar">Bar</option>
                    <option value="Baz">Baz</option>
                </select>

                <div data-dojo-type="dojox/mvc/Group" data-dojo-props="target: at('rel:', 'nextLevel')">
                    Selected:
                    <span data-mvc-bindings="innerText: at('rel:', 'title')"></span>
                    <select type="combo" data-dojo-type="dijit/form/Select"
                            data-dojo-props="value: at('rel:', 'title')">
                        <option value="Foo">Foo</option>
                        <option value="Bar">Bar</option>
                        <option value="Baz">Baz</option>
                    </select>
                </div>
            </div>
        </div>
        <div data-dojo-type="dijit/form/Button">Switch model
            <script type="dojo/on" data-dojo-event="click" data-dojo-args="evt">
                app.switchModel();
            </script>
        </div>
    </body>
</html>

希望这有帮助。

最好,-Akira

答案 1 :(得分:1)

dojox/mvc/getStateful从给定对象创建dojo/Stateful树。 _watchCallbacks,顾名思义,是dojo/Stateful的私有财产,当一个或多个人开始关注其属性的变化时设置。_watchCalbacks因此,target不存在并不一定意味着dojox/mvc/getStateful存在任何问题;也不是http://dojo-sandbox.net/public/7917e/1

我在http://dojo-sandbox.net/public/7917e/1看到的是这个;在尝试时,在UI端观察dojo/Stateful层次结构需要dojox/mvc/Group(或类似的东西)与右model.nested。但是,它需要在每个层次结构中完成。这意味着,如果您dojox/mvc/Group正在关注_watchCallbacks,则会看到nested设置为<!DOCTYPE html> <html> <head> <title>dojo/Stateful tree with dojox/mvc/getStateful</title> <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.10.0/dojo/dojo.js" data-dojo-config="parseOnLoad: 0, async: 1, mvc: {debugBindings: 1}"></script> <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/dojo/1.10.0/dojo/resources/dojo.css"> <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/dojo/1.10.0/dijit/themes/claro/claro.css"> <script type="text/javascript"> require([ "dojo/_base/declare", "dojo/Stateful", "dojo/parser", "dojox/mvc/getStateful", "dojox/mvc/parserExtension", "dojo/domReady!" ], function (declare, Stateful, parser, getStateful) { var App = declare(Stateful, { model: null, constructor: function () { this.switchModel(); }, createModel: function () { return getStateful({ title: "Foo", deeper: { title: "Bar" } }); }, switchModel: function () { this.set("model", this.createModel()); } }); window.app = new App(); parser.parse(); }); </script> </head> <body class="claro"> <script type="dojo/require">at: "dojox/mvc/at"</script> <div data-dojo-type="dojox/mvc/Group" data-dojo-props="target: at(app, 'model')"> Selected: <span data-mvc-bindings="innerText: at('rel:', 'title')"></span> <select type="combo" data-dojo-type="dijit/form/Select" data-dojo-props="value: at('rel:', 'title')"> <option value="Foo">Foo</option> <option value="Bar">Bar</option> <option value="Baz">Baz</option> </select> <div data-dojo-type="dojox/mvc/Group" data-dojo-props="target: at('rel:', 'deeper')"> Selected: <span data-mvc-bindings="innerText: at('rel:', 'title')"></span> <select type="combo" data-dojo-type="dijit/form/Select" data-dojo-props="value: at('rel:', 'title')"> <option value="Foo">Foo</option> <option value="Bar">Bar</option> <option value="Baz">Baz</option> </select> </div> </div> <div data-dojo-type="dijit/form/Button">Switch model <script type="dojo/on" data-dojo-event="click" data-dojo-args="evt"> app.switchModel(); </script> </div> </body> </html> 。这是一个如何在UI端声明hierarchycal watch的示例(专注于dojox/mvc/Group用法):

{{1}}

最好,-Akira