这是一个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”的模型时,它会重新绑定。
答案 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