2014-07-21 20 views
1

这里是在我的预期用途getStateful()的道场沙箱:http://dojo-sandbox.net/public/7917e/1DojoX中/ MVC/getStateful支持层次

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

我也查看过newStatefulModel,但文档指出getStateful是继承者,应该使用。

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

编辑:它看起来像我的问题是不与getStateful方法,但与ModelRefController.set方法,或更具体的_Controller.set方法。

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

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

我可绕了错误的方式,但我想有一个知道所有关于它能够显示等领域的具体的模板,并有只关心那些属性窗口小部件(控制器)在控件(控制器)中驱动逻辑的模型。

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

这里还有一个道场沙箱:http://dojo-sandbox.net/public/e6946/0

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

回答

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> 

希望这有助于。

Best,-Akira

+0

我希望mvc/at能够保留答案,并且我不需要用Stateful.Watch来获得这个密码。我需要花一些时间考虑如何将这个结合到我的解决方案中,因为它的一部分是生成的。再次感谢您对这个问题的及时和全面的回答。 – rmiles

1

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

我在http://dojo-sandbox.net/public/7917e/1看到的是这个;正如它试图,注意dojo/Stateful UI层次需要dojox/mvc/Group(或类似的东西)与正确的target。不过,它需要在每个等级的层次上完成。这意味着如果您有dojox/mvc/Group注意model.nested,您会看到_watchCallbacks设置为nested。下面是一个例子,如何申报在UI侧hierarchcal手表(重点dojox/mvc/Group使用):

<!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> 

最佳,-Akira

+0

Hi Akira,谢谢你的回复。 我最初走下了这条路线,将所有的小部件都包装在mvc/Group中,以建立绑定的上下文。它正在工作。 但是,我需要的插件绑定到两个上下文,一个是价值,另一个是得到其它的属性像类的,需要的残疾人,根据页面作者在另一个模型中定义和包含表达式的计算。 这导致我在页面级建立mvc/Group上下文,并在at()声明中使用'rel:path.to.property'语法,该模式在切换模型时不起作用。 – rmiles

+0

我需要更具体的“两个上下文”的例子来提供如何实现,但你需要创建一个包含“两个上下文”的“视图模型”。 – asudoh

+0

我用你的例子,包括一个状态模型,并克隆你的用户界面,并修改了dojo断言,因为我期望他们能够使用'rel:path.to.model'语法。 [两个上下文示例](http://dojo-sandbox.net/public/ef38d/1) – rmiles