Repeat.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. define("dojox/mvc/Repeat", [
  2. "dojo/_base/declare",
  3. "dojo/dom",
  4. "./_Container"
  5. ], function(declare, dom, _Container){
  6. /*=====
  7. declare = dojo.declare;
  8. dom = dojo.dom;
  9. _Container = dojox.mvc._Container;
  10. =====*/
  11. return declare("dojox.mvc.Repeat", [_Container], {
  12. // summary:
  13. // A model-bound container which binds to a collection within a data model
  14. // and produces a repeating user-interface from a template for each
  15. // iteration within the collection.
  16. //
  17. // description:
  18. // A repeat is bound to an intermediate dojo.Stateful node corresponding
  19. // to an array in the data model. Child dijits or custom view components
  20. // inside it inherit their parent data binding context from it.
  21. // index: Integer
  22. // An index used to track the current iteration when the repeating UI is
  23. // produced. This may be used to parameterize the content in the repeat
  24. // template for the current iteration.
  25. //
  26. // For example, consider a collection of search or query results where
  27. // each item contains a "Name" property used to prime the "Results" data
  28. // model. Then, the following CRUD-style UI displays all the names in
  29. // the search results in text boxes where they may be updated or such.
  30. //
  31. // | <div dojoType="dojox.mvc.Repeat" ref="Results">
  32. // | <div class="row" dojoType="dojox.mvc.Group" ref="${this.index}">
  33. // | <label for="nameInput${this.index}">Name:</label>
  34. // | <input dojoType="dijit.form.TextBox" id="nameInput${this.index}" ref="'Name'"></input>
  35. // | </div>
  36. // | </div>
  37. index : 0,
  38. // summary:
  39. // Override and save template from body.
  40. postscript: function(params, srcNodeRef){
  41. this.srcNodeRef = dom.byId(srcNodeRef);
  42. if(this.srcNodeRef){
  43. if(this.templateString == ""){ // only overwrite templateString if it has not been set
  44. this.templateString = this.srcNodeRef.innerHTML;
  45. }
  46. this.srcNodeRef.innerHTML = "";
  47. }
  48. this.inherited(arguments);
  49. },
  50. ////////////////////// PRIVATE METHODS ////////////////////////
  51. _updateBinding: function(name, old, current){
  52. // summary:
  53. // Rebuild repeating UI if data binding changes.
  54. // tags:
  55. // private
  56. this.inherited(arguments);
  57. this._buildContained();
  58. },
  59. _buildContained: function(){
  60. // summary:
  61. // Destroy any existing contained view, recreate the repeating UI
  62. // markup and parse the new contents.
  63. // tags:
  64. // private
  65. // TODO: Potential optimization: only create new widgets for insert, only destroy for delete.
  66. this._destroyBody();
  67. this._updateAddRemoveWatch();
  68. var insert = "";
  69. for(this.index = 0; this.get("binding").get(this.index); this.index++){
  70. insert += this._exprRepl(this.templateString);
  71. }
  72. var repeatNode = this.srcNodeRef || this.domNode;
  73. repeatNode.innerHTML = insert;
  74. // srcNodeRef is used in _createBody, so in the programmatic create case where repeatNode was set
  75. // from this.domNode we need to set srcNodeRef from repeatNode
  76. this.srcNodeRef = repeatNode;
  77. this._createBody();
  78. },
  79. _updateAddRemoveWatch: function(){
  80. // summary:
  81. // Updates the watch handle when binding changes.
  82. // tags:
  83. // private
  84. if(this._addRemoveWatch){
  85. this._addRemoveWatch.unwatch();
  86. }
  87. var pThis = this;
  88. this._addRemoveWatch = this.get("binding").watch(function(name,old,current){
  89. if(/^[0-9]+$/.test(name.toString())){
  90. if(!old || !current){
  91. pThis._buildContained();
  92. } // else not an insert or delete, will get updated in above
  93. }
  94. });
  95. }
  96. });
  97. });