@gogocat/data-bind 1.11.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/.editorconfig +14 -14
  2. package/.vscode/launch.json +12 -12
  3. package/CONFIGURATION.md +294 -0
  4. package/REACTIVE_MODE.md +553 -0
  5. package/README.md +266 -829
  6. package/babel.config.json +30 -0
  7. package/dist/js/_escape.d.ts +14 -0
  8. package/dist/js/_escape.d.ts.map +1 -0
  9. package/dist/js/applyBinding.d.ts +11 -0
  10. package/dist/js/applyBinding.d.ts.map +1 -0
  11. package/dist/js/attrBinding.d.ts +12 -0
  12. package/dist/js/attrBinding.d.ts.map +1 -0
  13. package/dist/js/binder.d.ts +67 -0
  14. package/dist/js/binder.d.ts.map +1 -0
  15. package/dist/js/changeBinding.d.ts +19 -0
  16. package/dist/js/changeBinding.d.ts.map +1 -0
  17. package/dist/js/commentWrapper.d.ts +39 -0
  18. package/dist/js/commentWrapper.d.ts.map +1 -0
  19. package/dist/js/config.d.ts +55 -0
  20. package/dist/js/config.d.ts.map +1 -0
  21. package/dist/js/createBindingOption.d.ts +32 -0
  22. package/dist/js/createBindingOption.d.ts.map +1 -0
  23. package/dist/js/createEventBinding.d.ts +10 -0
  24. package/dist/js/createEventBinding.d.ts.map +1 -0
  25. package/dist/js/cssBinding.d.ts +15 -0
  26. package/dist/js/cssBinding.d.ts.map +1 -0
  27. package/dist/js/dataBind.js +2772 -2519
  28. package/dist/js/dataBind.min.js +8 -1
  29. package/dist/js/dataBind.min.js.map +1 -1
  30. package/dist/js/domWalker.d.ts +9 -0
  31. package/dist/js/domWalker.d.ts.map +1 -0
  32. package/dist/js/forOfBinding.d.ts +12 -0
  33. package/dist/js/forOfBinding.d.ts.map +1 -0
  34. package/dist/js/hoverBinding.d.ts +13 -0
  35. package/dist/js/hoverBinding.d.ts.map +1 -0
  36. package/dist/js/ifBinding.d.ts +12 -0
  37. package/dist/js/ifBinding.d.ts.map +1 -0
  38. package/dist/js/index.d.ts +10 -0
  39. package/dist/js/index.d.ts.map +1 -0
  40. package/dist/js/modelBinding.d.ts +12 -0
  41. package/dist/js/modelBinding.d.ts.map +1 -0
  42. package/dist/js/postProcess.d.ts +3 -0
  43. package/dist/js/postProcess.d.ts.map +1 -0
  44. package/dist/js/pubSub.d.ts +11 -0
  45. package/dist/js/pubSub.d.ts.map +1 -0
  46. package/dist/js/reactiveProxy.d.ts +28 -0
  47. package/dist/js/reactiveProxy.d.ts.map +1 -0
  48. package/dist/js/renderForOfBinding.d.ts +8 -0
  49. package/dist/js/renderForOfBinding.d.ts.map +1 -0
  50. package/dist/js/renderIfBinding.d.ts +22 -0
  51. package/dist/js/renderIfBinding.d.ts.map +1 -0
  52. package/dist/js/renderIteration.d.ts +16 -0
  53. package/dist/js/renderIteration.d.ts.map +1 -0
  54. package/dist/js/renderTemplate.d.ts +14 -0
  55. package/dist/js/renderTemplate.d.ts.map +1 -0
  56. package/dist/js/renderTemplatesBinding.d.ts +19 -0
  57. package/dist/js/renderTemplatesBinding.d.ts.map +1 -0
  58. package/dist/js/showBinding.d.ts +13 -0
  59. package/dist/js/showBinding.d.ts.map +1 -0
  60. package/dist/js/switchBinding.d.ts +13 -0
  61. package/dist/js/switchBinding.d.ts.map +1 -0
  62. package/dist/js/textBinding.d.ts +13 -0
  63. package/dist/js/textBinding.d.ts.map +1 -0
  64. package/dist/js/types/_escape.d.ts +14 -0
  65. package/dist/js/types/_escape.d.ts.map +1 -0
  66. package/dist/js/types/applyBinding.d.ts +11 -0
  67. package/dist/js/types/applyBinding.d.ts.map +1 -0
  68. package/dist/js/types/attrBinding.d.ts +12 -0
  69. package/dist/js/types/attrBinding.d.ts.map +1 -0
  70. package/dist/js/types/binder.d.ts +67 -0
  71. package/dist/js/types/binder.d.ts.map +1 -0
  72. package/dist/js/types/changeBinding.d.ts +19 -0
  73. package/dist/js/types/changeBinding.d.ts.map +1 -0
  74. package/dist/js/types/commentWrapper.d.ts +39 -0
  75. package/dist/js/types/commentWrapper.d.ts.map +1 -0
  76. package/dist/js/types/config.d.ts +55 -0
  77. package/dist/js/types/config.d.ts.map +1 -0
  78. package/dist/js/types/createBindingOption.d.ts +32 -0
  79. package/dist/js/types/createBindingOption.d.ts.map +1 -0
  80. package/dist/js/types/createEventBinding.d.ts +10 -0
  81. package/dist/js/types/createEventBinding.d.ts.map +1 -0
  82. package/dist/js/types/cssBinding.d.ts +15 -0
  83. package/dist/js/types/cssBinding.d.ts.map +1 -0
  84. package/dist/js/types/domWalker.d.ts +9 -0
  85. package/dist/js/types/domWalker.d.ts.map +1 -0
  86. package/dist/js/types/forOfBinding.d.ts +12 -0
  87. package/dist/js/types/forOfBinding.d.ts.map +1 -0
  88. package/dist/js/types/hoverBinding.d.ts +13 -0
  89. package/dist/js/types/hoverBinding.d.ts.map +1 -0
  90. package/dist/js/types/ifBinding.d.ts +12 -0
  91. package/dist/js/types/ifBinding.d.ts.map +1 -0
  92. package/dist/js/types/index.d.ts +10 -0
  93. package/dist/js/types/index.d.ts.map +1 -0
  94. package/dist/js/types/modelBinding.d.ts +12 -0
  95. package/dist/js/types/modelBinding.d.ts.map +1 -0
  96. package/dist/js/types/postProcess.d.ts +3 -0
  97. package/dist/js/types/postProcess.d.ts.map +1 -0
  98. package/dist/js/types/pubSub.d.ts +11 -0
  99. package/dist/js/types/pubSub.d.ts.map +1 -0
  100. package/dist/js/types/reactiveProxy.d.ts +28 -0
  101. package/dist/js/types/reactiveProxy.d.ts.map +1 -0
  102. package/dist/js/types/renderForOfBinding.d.ts +8 -0
  103. package/dist/js/types/renderForOfBinding.d.ts.map +1 -0
  104. package/dist/js/types/renderIfBinding.d.ts +22 -0
  105. package/dist/js/types/renderIfBinding.d.ts.map +1 -0
  106. package/dist/js/types/renderIteration.d.ts +16 -0
  107. package/dist/js/types/renderIteration.d.ts.map +1 -0
  108. package/dist/js/types/renderTemplate.d.ts +14 -0
  109. package/dist/js/types/renderTemplate.d.ts.map +1 -0
  110. package/dist/js/types/renderTemplatesBinding.d.ts +19 -0
  111. package/dist/js/types/renderTemplatesBinding.d.ts.map +1 -0
  112. package/dist/js/types/showBinding.d.ts +13 -0
  113. package/dist/js/types/showBinding.d.ts.map +1 -0
  114. package/dist/js/types/switchBinding.d.ts +13 -0
  115. package/dist/js/types/switchBinding.d.ts.map +1 -0
  116. package/dist/js/types/textBinding.d.ts +13 -0
  117. package/dist/js/types/textBinding.d.ts.map +1 -0
  118. package/dist/js/types/types.d.ts +111 -0
  119. package/dist/js/types/types.d.ts.map +1 -0
  120. package/dist/js/types/util.d.ts +119 -0
  121. package/dist/js/types/util.d.ts.map +1 -0
  122. package/dist/js/types.d.ts +111 -0
  123. package/dist/js/types.d.ts.map +1 -0
  124. package/dist/js/util.d.ts +119 -0
  125. package/dist/js/util.d.ts.map +1 -0
  126. package/eslint.config.js +124 -0
  127. package/examples/DBMONSTER_COMPARISON.md +123 -0
  128. package/examples/afterRenderDemo.html +119 -0
  129. package/examples/bootstrap/css/animate.css +1579 -1579
  130. package/examples/bootstrap/css/bootstrap.min.css +6 -6
  131. package/examples/bootstrap/css/homeservices.css +378 -390
  132. package/examples/bootstrap/css/open-iconic.css +511 -511
  133. package/examples/bootstrap/fonts/open-iconic.svg +543 -543
  134. package/examples/bootstrap/js/compMessageDialog.js +20 -19
  135. package/examples/bootstrap/js/compSearchBar.js +12 -19
  136. package/examples/bootstrap/js/compSearchResults.js +50 -46
  137. package/examples/bootstrap/js/featureAdsResult.json +65 -65
  138. package/examples/bootstrap/js/searchResult.json +57 -57
  139. package/examples/bootstrap.html +343 -332
  140. package/examples/css/baseTodo.css +141 -141
  141. package/examples/css/dbMonsterStyles.css +27 -27
  142. package/examples/css/indexTodo.css +374 -374
  143. package/examples/dbmonsterForOfReactive.html +40 -0
  144. package/examples/dbmonsterReact.html +19 -0
  145. package/examples/forOfBindingSimpleDebug.html +45 -0
  146. package/examples/form.html +20 -4
  147. package/examples/globalConfig.html +131 -0
  148. package/examples/js/afterRenderDemo.js +190 -0
  149. package/examples/js/appTodo.js +46 -46
  150. package/examples/js/attrBindingDemo.js +2 -2
  151. package/examples/js/dbMonApp.js +24 -26
  152. package/examples/js/dbMonAppReact.jsx +79 -0
  153. package/examples/js/dbMonAppReactive.js +28 -0
  154. package/examples/js/fiberDemo.js +4 -4
  155. package/examples/js/filtersDemo.js +8 -8
  156. package/examples/js/forOfDemo.js +7 -9
  157. package/examples/js/forOfDemoComplex.js +44 -17
  158. package/examples/js/form.js +44 -12
  159. package/examples/js/globalConfig.js +117 -0
  160. package/examples/js/ifBindingDemo.js +16 -16
  161. package/examples/js/reactiveDemo.js +119 -0
  162. package/examples/js/switchBindingDemo.js +8 -8
  163. package/examples/react-dbmonster/dist/bundle.js +43 -0
  164. package/examples/react-dbmonster/package-lock.json +537 -0
  165. package/examples/react-dbmonster/package.json +16 -0
  166. package/examples/react-dbmonster/src/index.jsx +80 -0
  167. package/examples/reactiveDemo.html +127 -0
  168. package/examples/refreshRateTest.html +75 -75
  169. package/index.html +841 -0
  170. package/package.json +31 -34
  171. package/rollup.config.js +79 -36
  172. package/src/{_escape.js → _escape.ts} +19 -17
  173. package/src/applyBinding.ts +179 -0
  174. package/src/{attrBinding.js → attrBinding.ts} +14 -13
  175. package/src/binder.ts +289 -0
  176. package/src/changeBinding.ts +93 -0
  177. package/src/{commentWrapper.js → commentWrapper.ts} +33 -30
  178. package/src/config.ts +107 -0
  179. package/src/createBindingOption.ts +91 -0
  180. package/src/createEventBinding.ts +88 -0
  181. package/src/{cssBinding.js → cssBinding.ts} +13 -11
  182. package/src/{domWalker.js → domWalker.ts} +44 -30
  183. package/src/{forOfBinding.js → forOfBinding.ts} +4 -3
  184. package/src/hoverBinding.ts +84 -0
  185. package/src/{ifBinding.js → ifBinding.ts} +14 -12
  186. package/src/index.ts +53 -0
  187. package/src/{modelBinding.js → modelBinding.ts} +11 -9
  188. package/src/postProcess.ts +22 -0
  189. package/src/{pubSub.js → pubSub.ts} +24 -15
  190. package/src/reactiveProxy.ts +285 -0
  191. package/src/{renderForOfBinding.js → renderForOfBinding.ts} +55 -33
  192. package/src/{renderIfBinding.js → renderIfBinding.ts} +45 -20
  193. package/src/renderIteration.ts +53 -0
  194. package/src/renderTemplate.ts +165 -0
  195. package/src/renderTemplatesBinding.ts +73 -0
  196. package/src/{showBinding.js → showBinding.ts} +4 -3
  197. package/src/{switchBinding.js → switchBinding.ts} +18 -15
  198. package/src/{textBinding.js → textBinding.ts} +5 -4
  199. package/src/types.ts +124 -0
  200. package/src/util.ts +810 -0
  201. package/test/css/reporter.css +9 -9
  202. package/test/fixtures/dataBindBootstrap.html +2 -2
  203. package/test/fixtures/formBindings.html +9 -1
  204. package/test/globals.d.ts +19 -0
  205. package/test/helpers/testHelper.js +46 -11
  206. package/test/mocks/featureAdsResult.json +65 -65
  207. package/test/mocks/searchResult.json +57 -57
  208. package/test/specs/{attrBinding.spec.js → attrBinding.spec.ts} +103 -106
  209. package/test/specs/{binder.spec.js → binder.spec.ts} +29 -27
  210. package/test/specs/blurBinding.spec.ts +60 -0
  211. package/test/specs/chainableUse.spec.ts +125 -0
  212. package/test/specs/clickBinding.spec.ts +194 -0
  213. package/test/specs/{cssBinding.spec.js → cssBinding.spec.ts} +72 -79
  214. package/test/specs/{dataBindBootstrap.spec.js → dataBindBootstrap.spec.ts} +332 -313
  215. package/test/specs/{filter.spec.js → filter.spec.ts} +75 -76
  216. package/test/specs/{forOfBinding.spec.js → forOfBinding.spec.ts} +208 -219
  217. package/test/specs/formBinding.spec.ts +272 -0
  218. package/test/specs/ifBinding.spec.ts +165 -0
  219. package/test/specs/{nestedComponent.spec.js → nestedComponent.spec.ts} +88 -88
  220. package/test/specs/reactiveProxy.spec.ts +465 -0
  221. package/test/specs/{showBinding.spec.js → showBinding.spec.ts} +148 -149
  222. package/test/specs/{switchBinding.spec.js → switchBinding.spec.ts} +172 -173
  223. package/test/specs/templateBinding.spec.ts +273 -0
  224. package/test/specs/{textBinding.spec.js → textBinding.spec.ts} +47 -48
  225. package/test/tsconfig.json +31 -0
  226. package/test-output.txt +200 -0
  227. package/test-reactive.html +224 -0
  228. package/tsconfig.json +28 -0
  229. package/vendors/lodash.custom.js +4577 -4577
  230. package/vendors/lodash.custom.min.js +45 -45
  231. package/vitest.config.js +27 -0
  232. package/.eslintrc.js +0 -1
  233. package/.grunt/grunt-contrib-jasmine/boot.js +0 -161
  234. package/.grunt/grunt-contrib-jasmine/dist/js/dataBind.js +0 -9
  235. package/.grunt/grunt-contrib-jasmine/grunt-template-jasmine-istanbul/reporter.js +0 -23
  236. package/.grunt/grunt-contrib-jasmine/jasmine-html.js +0 -853
  237. package/.grunt/grunt-contrib-jasmine/jasmine.css +0 -271
  238. package/.grunt/grunt-contrib-jasmine/jasmine.js +0 -9761
  239. package/.grunt/grunt-contrib-jasmine/jasmine_favicon.png +0 -0
  240. package/.grunt/grunt-contrib-jasmine/json2.js +0 -489
  241. package/.grunt/grunt-contrib-jasmine/reporter.js +0 -107
  242. package/coverage/coverage.json +0 -1
  243. package/coverage/lcov/lcov-report/base.css +0 -213
  244. package/coverage/lcov/lcov-report/index.html +0 -93
  245. package/coverage/lcov/lcov-report/js/dataBind.js.html +0 -6596
  246. package/coverage/lcov/lcov-report/js/index.html +0 -93
  247. package/coverage/lcov/lcov-report/prettify.css +0 -1
  248. package/coverage/lcov/lcov-report/prettify.js +0 -1
  249. package/coverage/lcov/lcov-report/sort-arrow-sprite.png +0 -0
  250. package/coverage/lcov/lcov-report/sorter.js +0 -158
  251. package/coverage/lcov/lcov.info +0 -1991
  252. package/eslintrc.json +0 -40
  253. package/examples/bootstrap/js/bootstrap.min.js +0 -6
  254. package/examples/bootstrap/js/popper.min.js +0 -5
  255. package/examples/bootstrap/js/searchSuggestion.js +0 -58
  256. package/examples/bootstrap/js/typeahead.jquery.js +0 -1538
  257. package/gruntfile.js +0 -92
  258. package/gulpfile.js +0 -32
  259. package/src/binder.js +0 -422
  260. package/src/changeBinding.js +0 -57
  261. package/src/config.js +0 -65
  262. package/src/createBindingOption.js +0 -66
  263. package/src/createEventBinding.js +0 -46
  264. package/src/eventSystem.js +0 -46
  265. package/src/hoverBinding.js +0 -57
  266. package/src/index.js +0 -26
  267. package/src/renderTemplate.js +0 -128
  268. package/src/util.js +0 -648
  269. package/test/specs/blurBinding.spec.js +0 -57
  270. package/test/specs/formBinding.spec.js +0 -292
  271. package/test/specs/ifBinding.spec.js +0 -169
  272. package/test/specs/templateBinding.spec.js +0 -117
  273. package/vendors/jasmine-jquery.js +0 -841
  274. package/vendors/jquery-3.2.1.min.js +0 -4
package/README.md CHANGED
@@ -3,973 +3,410 @@
3
3
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/e754785d29d946bf9a0ab7146869caec)](https://www.codacy.com/app/gogocat/dataBind?utm_source=github.com&utm_medium=referral&utm_content=gogocat/dataBind&utm_campaign=Badge_Grade)
4
4
  ![GitHub](https://img.shields.io/github/license/gogocat/dataBind.svg)
5
5
 
6
-
6
+ # dataBind.js
7
7
 
8
- ## What is dataBind?
8
+ > Simple, fast, reactive data binding for modern browsers. No build tools required.
9
9
 
10
-
10
+ ## Why dataBind?
11
11
 
12
- dataBind is a light weight javaScript [MV* framework](http://www.techbloginterview.com/what-is-a-mv-framework/) aim for update DOM easier and in better managed way.
12
+ **dataBind.js is not another front-end UI framework.** It's a lightweight, pragmatic solution for adding reactive data binding to your existing HTML, without the complexity of modern frameworks.
13
13
 
14
-
14
+ ### Key Features
15
15
 
16
- * **Declarative:** dataBind simpliy bind view data to the HTML, wire events, and provides two way or one way data binding
16
+ **Simple** - Just HTML + JavaScript. No JSX, no virtual DOM, no build pipeline
17
+ ⚡ **Fast** - Extremely small footprint (~15KB min+gzip) and high performance ([see benchmarks](https://gogocat.github.io/dataBind/examples/dbmonsterForOf.html))
18
+ 🔄 **Reactive** - Automatic UI updates when data changes (like Vue 3, but simpler)
19
+ 🎯 **Focused** - View + ViewModel pattern. No router, no state management, no opinions
20
+ 🛠️ **Zero Setup** - Drop in a `<script>` tag and go. Works with any backend or framework
21
+ 📦 **Tiny** - No dependencies, no build tools, no configuration
17
22
 
18
- * **High performance:** dataBind is very fast. Please do try the famous [**dbmonster** example](https://gogocat.github.io/dataBind/examples/dbmonsterForOf.html), locate in `examples/dbmonsterForOf.html` and [**fiber**](https://gogocat.github.io/dataBind/examples/fiber-demo.html) `/examples/fiber-demo.html` compare with [other frameworks](http://mathieuancelin.github.io/js-repaint-perfs/)
23
+ ## Quick Start
19
24
 
20
- * **DOM is the source of truth:** There is no vitrual DOM or complex reactive observables to worry about
21
-
22
- * **Isolated scope:** Each component only works with its own viewModel scope. No complex props pass up and down
23
-
24
- * **zero setup:** There is no need to run any build tool for development or production
25
-
26
- * **framework agnostic :** dataBind can work with any other framework. There is no need to rebuild everything in order to use it. It is design to leverage and modernise what is already working
27
-
28
-
29
-
30
-
31
- ## How to use it?
32
-
33
- For web load via script tag
34
-
35
- <script src="dist/js/dataBind.min.js"></script>
36
-
37
- Or node_module
38
-
39
- npm install @gogocat/data-bind
40
-
41
- then
42
-
43
- import dataBind from '@gogocat/data-bind';
44
-
45
- **Usage**
46
-
47
- The following is a very simple example shows text binding.
48
-
49
-
50
-
51
- Most of the component logic will be in the viewModel(plain old JavaScript object).
52
-
53
-
54
-
55
- `dataBind.init` will return an instance of `Binder`(this is the bound dataBind object).
56
-
57
- Then just call `render` to start render to the page.
58
-
59
-
60
-
61
- **HTML**
25
+ ### Installation
62
26
 
27
+ **Via CDN:**
63
28
  ```html
64
-
65
- <section data-bind-comp="simpleComponent">
66
- <div>
67
- <h5 data-bind-text="heading"></h5>
68
- <p data-bind-text="description"></p>
69
- </div>
70
- </section>
71
-
29
+ <script src="https://unpkg.com/@gogocat/data-bind/dist/js/dataBind.min.js"></script>
72
30
  ```
73
31
 
74
- **Js**
75
-
76
- ```javascript
77
-
78
- const simpleComponentViewModel = {
79
- heading: 'Test heading',
80
- description: 'This is my test description',
81
- };
82
-
83
- // init data bind with view
84
- const simpleComponent = dataBind.init(
85
- document.querySelector('[data-bind-comp="simpleComponent"]'),
86
- simpleComponentViewModel
87
- );
88
-
89
-
90
- // trigger render and log after render
91
- simpleComponent
92
- .render()
93
- .then(function() {
94
- // for debug
95
- console.log(simpleComponent);
96
- });
97
-
32
+ **Via NPM:**
33
+ ```bash
34
+ npm install @gogocat/data-bind
98
35
  ```
99
36
 
100
- To make change, just update the data in viewModel and then call `render()`.
101
-
102
37
  ```javascript
103
-
104
- simpleComponentViewModel.heading='new heading';
105
-
106
- simpleComponent.render();
107
-
38
+ import dataBind from '@gogocat/data-bind';
108
39
  ```
109
40
 
110
- `render` function is an asynchronous, debounced operation. So it will consolidate changes and render only once.
111
-
112
-
113
-
114
- > :bulb: *All declarative bindings accept value or function that returns value from the viewModel*.
115
-
116
-
117
-
118
- Example: `heading` in the viewModel can be a value or function that returns value.
119
-
120
-
121
-
122
- The binding can also pass-in parameters.
41
+ ### Basic Example
123
42
 
43
+ **HTML:**
124
44
  ```html
125
-
126
- <h5 data-bind-text="heading($data)"></h5>
127
-
128
- ```
129
-
130
- The following parameters are helpers reference `$index` or `$data` or `$root`. More details below
131
-
132
-
133
-
134
-
135
- For more advance example. Please check [**examples/bootstrap.html**](https://gogocat.github.io/dataBind/examples/bootstrap.html).
136
-
137
-
138
-
139
- > *bootstrap example shows how to use multiple, nested components and services together. Please run this example from a local server*.
140
-
141
-
142
-
143
- ----
144
-
145
-
146
-
147
- ### The init and render functions
148
-
149
- ```javascript
150
-
151
- ...
152
-
153
- // DOM ready bind viewModel with target DOM element
154
- const simpleComponent = dataBind.init(
155
- document.querySelector('[data-bind-comp="simpleComponent"]'),
156
- simpleComponentViewModel
157
- );
158
-
159
-
160
-
161
- // trigger render, then console log for debug
162
- simpleComponent
163
- .render()
164
- .then(function(ctx) {
165
- // for debug
166
- console.log(simpleComponent === ctx);
167
- });
168
-
169
-
170
- ```
171
-
172
- In this simple example. First we call `.init` to initialise the component with the viewModle:
173
-
174
- ```javascript
175
-
176
- const simpleComponent = dataBind.init([targetDOMElement], [viewModel]);
177
-
45
+ <div id="app">
46
+ <h1 data-bind-text="greeting"></h1>
47
+ <button data-bind-click="changeGreeting">Change</button>
48
+ </div>
178
49
  ```
179
50
 
180
- The returned value of `dataBind.init` is a instance of `Binder`, which is the bound component. Behind the scene, dataBind will parse the target DOM element and cache elements that has binding attributes and wire up with the viewModel. At this stage it doesn't make any change to the DOM.
181
-
182
-
183
-
184
- The next call of `render` function is to render value from viewModel to the DOM (if there are difference). It returns a `promise` object for logic that can be trigger after the component fully rendered.
185
-
186
-
187
-
188
- The resolver callback will receive a `context` object; because inside the resolver function `this` is refer to window.
189
-
190
- `context` object is the same object as `simpleComponent` in this example.
191
-
192
-
193
-
194
- To re-render the component, just call `render`. As mentioned, this function is an asynchronous and debounced operation. This mean, doesn't matter how many times it get call it will only make change to DOM once. Minimise browser repaint/reflow.
195
-
196
-
197
-
198
- For edge case; pass an optional setting object when calling `render` to control what binding should be render or not.
199
-
51
+ **JavaScript:**
200
52
  ```javascript
201
-
202
- simpleComponent.render({
203
- templateBinding: true,
204
- textBinding: true,
205
- cssBinding: true,
206
- ifBinding: true,
207
- showBinding: true,
208
- modelBinding: true,
209
- attrBinding: true,
210
- forOfBinding: true,
211
- switchBinding: true,
212
- changeBinding: true,
213
- clickBinding: true,
214
- dblclickBinding: true,
215
- blurBinding: true,
216
- focusBinding: true,
217
- hoverBinding: true,
218
- submitBinding: true,
53
+ const app = dataBind.init(document.getElementById('app'), {
54
+ greeting: 'Hello, World!',
55
+ changeGreeting() {
56
+ this.greeting = 'Hello, dataBind!';
57
+ // That's it! UI updates automatically in reactive mode
58
+ }
219
59
  });
220
60
 
61
+ app.render();
221
62
  ```
222
63
 
223
- **Overwrite 'data-bind-x` namespace**
64
+ That's it! No JSX, no compilation, no complex setup.
224
65
 
225
- ```javascript
66
+ ## Reactive State (Default)
226
67
 
227
- // global dataBind settings
68
+ By default, dataBind uses **reactive mode** - changes to data automatically update the UI:
228
69
 
229
- dataBind.use({
230
- bindingAttrs: {
231
- comp: 'data-xy-comp',
232
- tmp: 'data-xy-tmp',
233
- text: 'data-xy-text',
234
- click: 'data-xy-click',
235
- dblclick: 'data-xy-dblclick',
236
- blur: 'data-xy-blur',
237
- focus: 'data-xy-focus',
238
- hover: 'data-xy-hover',
239
- change: 'data-xy-change',
240
- submit: 'data-xy-submit',
241
- model: 'data-xy-model',
242
- show: 'data-xy-show',
243
- css: 'data-xy-css',
244
- attr: 'data-xy-attr',
245
- forOf: 'data-xy-for',
246
- if: 'data-xy-if',
247
- switch: 'data-xy-switch',
248
- case: 'data-xy-case',
249
- default: 'data-xy-default'
70
+ ```javascript
71
+ const app = dataBind.init(element, {
72
+ counter: 0,
73
+ items: [],
74
+ increment() {
75
+ this.counter++; // UI updates automatically!
250
76
  },
77
+ addItem() {
78
+ this.items.push({ text: 'New Item' }); // UI updates automatically!
79
+ }
251
80
  });
252
81
 
253
-
254
-
255
- // init
256
- const simpleComponent = dataBind.init(
257
- document.querySelector('[data-bind-comp="simpleComponent"]'),
258
- simpleComponentViewModel
259
- );
260
-
261
- // render
262
- simpleComponent.render();
263
-
264
- ```
265
-
266
- dataBind `use` method can be use to set global setting of binding attribute namespace. It accept an option object showing in above example.
267
-
268
-
269
-
270
- ## Visual bindings
271
-
272
- The following bindings produce visual changes
273
-
274
-
275
-
276
- ### Template binding
277
-
278
- ```html
279
-
280
- <section
281
- data-bind-comp="simpleComponent"
282
- data-bind-tmp="{id: 'exampleTemplate', data: '$root'}"
283
- ></section>
284
-
285
-
286
- <template id="exampleTemplate">
287
- <h1 data-bind-text="heading"></h1>
288
- </template>
289
-
290
- ```
291
-
292
- The attribute `data-bind-tmp` accept a JSON like object. `id` is reference to the `template` element id. `data` is reference to the data object within the bound viewModel. In this example `$root` means the root of the viewModel itself.
293
-
294
- If there a 3rd option as `append: true` or `prepend: true`, the content will then append or preprend to the target container (the section tag in this example). This make building infinity scroll content very easy and efficient.
295
-
296
-
297
-
298
-
299
- ### Text binding
300
-
301
- ```html
302
-
303
- <h1 data-bind-text="heading"></h1>
304
-
305
- <h1 data-bind-text="fullName | uppercase"></h1>
306
-
82
+ app.render();
307
83
  ```
308
84
 
309
- The attribute `data-bind-text` is refernce to the viewModel's property '**heading**'. All binding can handle deep object path reference eg. `data-bind-text="childObj.myArray[1].heading"`
310
-
311
-
312
-
313
- The 2nd example shows usage of **filter** ' | '. The value from viewModel's property `fullName` will pass on to the viewModel's `uppercase` function that returns value to be display. Filters can be chain together one after the other. more detail below.
314
-
315
- ### css binding
316
-
317
- ```html
85
+ ### How It Works
318
86
 
319
- <h1 data-bind-css="mycCss"></h1>
87
+ dataBind uses JavaScript Proxies to detect data changes:
320
88
 
89
+ ```javascript
90
+ // After init, use component.viewModel for reactive updates
91
+ app.viewModel.counter++; // ✅ Triggers automatic render
92
+ app.viewModel.items.push({...}); // ✅ Triggers automatic render
93
+ app.viewModel.user.name = 'Jane'; // ✅ Deep reactivity works!
321
94
  ```
322
95
 
323
- The attribute `data-bind-css` is refernce to the viewModel's property '**mycCss**'. This property can be a string of css class name, an object represend mutilple css class toggle eg. `{css1: true, css2: false}` or a function that returns either string or the object.
324
-
325
-
96
+ ### Manual Mode (Optional)
326
97
 
327
- ### if binding
98
+ For maximum performance control, disable reactive mode:
328
99
 
329
- ```html
330
- // conditional render the H1 element
331
- <h1 data-bind-if="myCondition">
332
- <span>Hello</span>
333
- </h1>
334
-
335
- // conditditional render the DIV element and its template binding
336
- <div
337
- data-bind-if="!myCondition"
338
- data-bind-tmp="{id: 'someTemplateId', data: 'someData'}"
339
- ></div>
100
+ ```javascript
101
+ const app = dataBind.use({ reactive: false }).init(element, viewModel);
340
102
 
103
+ // In manual mode, call render() explicitly
104
+ viewModel.counter++;
105
+ app.render(); // Manual render call
341
106
  ```
342
107
 
343
- The attribute `data-bind-if` is refernce to the viewModel's property '**myCondition**'. This property can be a boolean or a function that returns boolean.
344
-
345
-
346
-
347
- If `myCondition` is false. the children elements will be removed from DOM. When later `myCondition` is set to true. The elements will then render back.
348
-
349
-
350
-
351
- With negate expression(second example above), when the expression `!myCondition` evaluate to true. The template binding `data-bind-tmp` will execute and render accordingly.
352
-
353
-
354
-
355
- [example](https://gogocat.github.io/dataBind/examples/ifBinding.html)
356
-
357
-
358
-
359
- ### show binding
108
+ ## Core Bindings
360
109
 
110
+ ### Text Binding
361
111
  ```html
362
- // conditional display the H1 element
363
- <h1 data-bind-show="isShow">
364
- <span>Hello</span>
365
- </h1>
366
-
112
+ <h1 data-bind-text="title"></h1>
113
+ <p data-bind-text="user.name"></p> <!-- Deep paths supported -->
367
114
  ```
368
115
 
369
- The attribute `data-bind-show` is refernce to the viewModel's property '**isShow**'. This property can be a boolean or a function that returns boolean. If `isShow` is `true` the element will be display, otherwise it will be hidden. It also can handle negate expression eg `!isShow`.
370
-
371
-
372
-
373
- ### model binding
374
-
116
+ ### Event Binding
375
117
  ```html
376
-
377
- <input
378
- id="userName"
379
- name="userName"
380
- type="text"
381
- data-bind-model="personalDetails.userName"
382
- data-bind-change="onInputChange"
383
- required
384
- >
385
-
118
+ <button data-bind-click="handleClick">Click Me</button>
119
+ <input data-bind-change="handleChange" data-bind-model="username">
120
+ <form data-bind-submit="handleSubmit">...</form>
386
121
  ```
387
122
 
388
- The attribute `data-bind-model` is refernce to the viewModel's property '**personalDetails.userName**'. This property can be a string or a function that returns string. Model binding is a one-way binding operation that populate the input field `value` attribute with value come from the viewModel.
389
-
390
-
391
-
392
- **data-bind-model**
393
-
394
- > viewModel -> DOM
395
-
396
-
397
-
398
- For two-way data binding; use together with `data-bind-change`. It will update the viewModel if the value has changed and then trigger the event handler `onInputChange`. More detail below.
399
-
400
-
401
-
402
- **data-bind-change**
403
-
404
- > DOM -> viewModel
405
-
406
-
407
-
408
- [example](https://gogocat.github.io/dataBind/examples/todomvc.html)
409
-
410
-
411
-
412
- ### attribute binding
413
-
414
123
  ```javascript
415
-
416
- <img data-bind-attr="getImgAttr">
417
-
418
-
419
- // js
420
124
  const viewModel = {
421
- getImgAttr: function(oldAttrObj, $el) {
422
- return {
423
- src: '/someImage.png',
424
- alt: 'some image',
425
- };
125
+ handleClick(event, element) {
126
+ console.log('Clicked!', event, element);
127
+ },
128
+ handleChange(event, element, newValue, oldValue) {
129
+ console.log('Changed from', oldValue, 'to', newValue);
426
130
  }
427
131
  };
428
-
429
- ```
430
-
431
- The attribute `data-bind-attr` is refernce to the viewModel's property '**getImgAttr**'. This property can be a object or a function that returns object with `key:value`. The key is the attribute name and value is the value of that attribute.
432
-
433
-
434
-
435
- attribute binding is useful for more complex usage together with `data-bind-for` binding.
436
-
437
- Please see the `<select>` elements in this [example](https://gogocat.github.io/dataBind/examples/forOfBindingComplex.html)
438
-
439
-
440
-
441
- ### forOf binding
442
-
443
-
444
-
445
- ```javascript
446
-
447
- <p
448
- data-bind-for="result of results"
449
- data-bind-text="result.content"
450
- ></p>
451
-
452
-
453
- // js
454
- const viewModel = {
455
- results: [
456
- {
457
- content: '1'
458
- },
459
- {
460
- content: '2'
461
- },
462
- {
463
- content: '3'
464
- }
465
- ]
466
- };
467
-
468
132
  ```
469
133
 
470
- The attribute `data-bind-for` is refernce to the viewModel's property '**results**'. It will then loop throught the data and repeat the element. The express also accept 'for-in' syntax eg `result in results`.
471
-
472
-
473
-
474
- The result will looks like this:
475
-
134
+ ### List Rendering
476
135
  ```html
477
-
478
- <!--data-forOf_result_of_results-->
479
- <p data-bind-text="result.content">1</p>
480
- <p data-bind-text="result.content">2</p>
481
- <p data-bind-text="result.content">3</p>
482
- <!--data-forOf_result_of_results_end-->
483
-
136
+ <div data-bind-for="item in items">
137
+ <p data-bind-text="item.name"></p>
138
+ <button data-bind-click="$root.deleteItem($index)">Delete</button>
139
+ </div>
484
140
  ```
485
141
 
486
- [example](https://gogocat.github.io/dataBind/examples/forOfBinding.html)
487
-
488
-
489
-
490
- ### switch binding
491
-
492
142
  ```javascript
493
-
494
- <div data-bind-switch="selectedStory">
495
- <div data-bind-case="s1">
496
- <h2>Case 1</h2>
497
- </div>
498
- <div data-bind-case="s2">
499
- <h2>Case 2</h2>
500
- </div>
501
- <div data-bind-case="s3">
502
- <h2>Case 3</h2>
503
- </div>
504
- <div data-bind-default="">
505
- <p>No story found...</p>
506
- </div>
507
- </div>
508
-
509
-
510
- // js
511
143
  const viewModel = {
512
- selectedStory: 's1'
144
+ items: [
145
+ { name: 'Item 1' },
146
+ { name: 'Item 2' }
147
+ ],
148
+ deleteItem(index) {
149
+ this.items.splice(index, 1); // Reactive update!
150
+ }
513
151
  };
514
-
515
152
  ```
516
153
 
517
- Switch binding is a specail binding that the bound element must be parent of `data-bind-case` or `data-bind-default` binding elements, and each `data-bind-case` or `data-bind-default` must be siblings.
518
-
519
-
520
-
521
- The attribute `data-bind-switch` is refernce to the viewModel's property '**selectedStory**'. This property can be a string or a function that returns a string.
522
-
523
-
524
-
525
- In this example the result will looks like this, since selectedStory` match `data-bind-case="s1"`.
526
-
154
+ ### Conditional Rendering
527
155
  ```html
156
+ <!-- Removes from DOM when false -->
157
+ <div data-bind-if="isLoggedIn">
158
+ <p data-bind-text="user.name"></p>
159
+ </div>
528
160
 
529
- <div data-bind-switch="selectedStory">
530
- <div data-bind-case="s1">
531
- <h2>Case 1</h2>
532
- </div>
161
+ <!-- Hides with CSS when false -->
162
+ <div data-bind-show="isVisible">
163
+ <p>Visible content</p>
533
164
  </div>
534
165
 
166
+ <!-- Switch statement for multiple conditions -->
167
+ <div data-bind-switch="currentState">
168
+ <div data-bind-case="loading">Loading...</div>
169
+ <div data-bind-case="error">An error occurred</div>
170
+ <div data-bind-case="success">Data loaded successfully!</div>
171
+ <div data-bind-default>Please wait...</div>
172
+ </div>
535
173
  ```
536
174
 
537
- [example](https://gogocat.github.io/dataBind/examples/switchBinding.html)
538
-
539
-
540
-
541
- ## Event bindings
542
-
543
- The following binding produce interactivities
544
-
545
-
546
-
547
- ### change binding
548
-
549
- ```javascript
175
+ ### CSS Binding
176
+ ```html
177
+ <div data-bind-css="{ active: isActive, disabled: !isEnabled }"></div>
178
+ <div data-bind-css="dynamicClass"></div>
179
+ ```
550
180
 
551
- <input
552
- id="new-todo"
181
+ ### Two-Way Data Binding
182
+ ```html
183
+ <input
553
184
  type="text"
554
- data-bind-change="onAddTask"
555
- placeholder="What needs to be done?"
556
- autofocus
557
- >
558
-
559
-
560
- // js
561
- const viewModel = {
562
- onAddTask: function(e, $el, newValue, oldValue) {
563
- // do something...
564
- },
565
- }
566
-
185
+ data-bind-model="username"
186
+ data-bind-change="onUsernameChange">
567
187
  ```
568
188
 
569
- `data-bind-change` binding is use form input elements(input, checkbox, select..etc) on change event. The bound viewModel handler `onAddTask` will receive the `event object`, `bound DOM element `, `new value` and the `old value`.
189
+ The `data-bind-model` populates the input value from viewModel, while `data-bind-change` updates the viewModel when the input changes.
570
190
 
571
-
191
+ ## Advanced Features
572
192
 
573
- To make things more flexible. `data-bind-change` is one way binding (Data flows from DOM to viewModel).
193
+ ### Templates
194
+ ```html
195
+ <div data-bind-tmp="{id: 'userCard', data: 'user'}"></div>
574
196
 
575
- For 2 way binding, please use Model binding together. Which does data flow from viewModel to DOM.
197
+ <template id="userCard">
198
+ <div class="card">
199
+ <h2 data-bind-text="name"></h2>
200
+ <p data-bind-text="email"></p>
201
+ </div>
202
+ </template>
203
+ ```
576
204
 
577
-
205
+ ### Filters
206
+ ```html
207
+ <p data-bind-text="price | toDiscount | addGst"></p>
208
+ ```
578
209
 
579
210
  ```javascript
580
-
581
- <div data-bind-comp="todoComponent">
582
- <input
583
- id="new-todo"
584
- type="text"
585
- data-bind-change="onAddTask"
586
- data-bind-model="currentTask"
587
- placeholder="What needs to be done?"
588
- autofocus
589
- >
590
- </div>
591
-
592
-
593
- // js
594
211
  const viewModel = {
595
- currentTask = '',
596
- onAddTask: function(e, $el, newValue, oldValue) {
597
- e.preventDefault();
598
- this.currentTask = newValue;
599
- // re-render
600
- this.APP.render();
212
+ price: 100,
213
+ toDiscount(value) {
214
+ return value * 0.9; // 10% discount
215
+ },
216
+ addGst(value) {
217
+ return value * 1.1; // Add 10% GST
601
218
  }
602
- }
603
-
604
-
605
- // init data bind with view
606
- const toDoApp = dataBind.init(
607
- document.querySelector('[data-bind-comp="todoComponent"]'),
608
- viewModel
609
- );
610
-
611
- // trigger render
612
- toDoApp.render();
613
-
614
-
219
+ };
615
220
  ```
616
221
 
617
- In this example, we update `currentTask` data whenever `onAddTask` get called(on change) then calls `this.APP.render()`.
618
-
619
-
620
-
621
- > Once the viewModel bound with `dataBind.init` call, the viewModel will be extended. `APP` property is the bound dataBind object.
622
-
623
-
624
-
625
- ### click binding
626
-
222
+ ### Component Communication (Pub/Sub)
627
223
  ```javascript
224
+ // Component A: Subscribe to events
225
+ componentA.subscribe('USER_UPDATED', (userData) => {
226
+ console.log('User updated:', userData);
227
+ });
628
228
 
629
- <button
630
- id="clear-completed"
631
- data-bind-click="onClearAllCompleted"
632
- >
633
- Clear completed
634
- </button>
635
-
636
-
637
- // js
638
- const viewModel = {
639
- onClearAllCompleted: function(e, $el) {
640
- // do something...
641
- }
642
- }
643
-
229
+ // Component B: Publish events
230
+ componentB.publish('USER_UPDATED', { name: 'John', email: 'john@example.com' });
644
231
  ```
645
232
 
646
- `data-bind-click` binding is an event handler binding for 'click' event. The handler will receive ` event object ` and the `DOM element`.
647
-
648
-
649
-
650
- ### dblclick binding
651
-
233
+ ### AfterRender Callback
652
234
  ```javascript
653
-
654
- <button
655
- id="clear-completed"
656
- data-bind-dblclick="onDoubleClicked"
657
- >
658
- Clear completed
659
- </button>
660
-
661
- // js
662
- const viewModel = {
663
- onDoubleClicked: function(e, $el) {
664
- // do something...
665
- }
666
- }
667
-
235
+ app.afterRender(() => {
236
+ console.log('Render completed!');
237
+ // Perform DOM operations, analytics, etc.
238
+ });
668
239
  ```
669
240
 
670
- `data-bind-dblclick` binding is an event handler binding for double click event. The handler will receive ` event object ` and the `DOM element`.
671
-
672
-
673
-
674
- ### blur binding
675
-
241
+ ### Global Configuration
676
242
  ```javascript
243
+ // Set global defaults for all components
244
+ dataBind.use({
245
+ reactive: true, // Enable reactive mode globally
246
+ trackChanges: false // Track individual property changes
247
+ });
677
248
 
678
- <input name="firstName" type="text" data-bind-blur="onBlur">
679
-
680
- // js
681
- const viewModel = {
682
- onBlur: function(e, $el) {
683
- // do something...
684
- }
685
- }
686
-
249
+ // Or use chainable API
250
+ const app = dataBind
251
+ .use({ reactive: false })
252
+ .init(element, viewModel);
687
253
  ```
688
254
 
689
- `data-bind-blur` binding is an event handler binding for 'blur' event. The handler will receive ` event object ` and the `DOM element`.
255
+ ## Performance
690
256
 
691
-
257
+ dataBind is **extremely fast**. Try our benchmarks:
692
258
 
693
- ### focus binding
259
+ - [**DBMonster - dataBind** (1000+ updates/sec)](https://gogocat.github.io/dataBind/examples/dbmonsterForOf.html)
260
+ - [**DBMonster - React** (comparison)](https://gogocat.github.io/dataBind/examples/dbmonsterReact.html)
261
+ - [**Fiber** (Complex nested updates)](https://gogocat.github.io/dataBind/examples/fiber-demo.html)
694
262
 
695
- ```javascript
263
+ Compare with [other frameworks](http://mathieuancelin.github.io/js-repaint-perfs/).
696
264
 
697
- <input name="firstName" type="text" data-bind-focus="onFocus">
265
+ ### Why So Fast?
698
266
 
699
- // js
700
- const viewModel = {
701
- onFocus: function(e, $el) {
702
- // do something...
703
- }
704
- }
267
+ - **No Virtual DOM** - Direct DOM updates with minimal overhead
268
+ - **Efficient Diffing** - Only updates changed elements
269
+ - **Debounced Rendering** - Batches multiple changes via requestAnimationFrame
270
+ - **Tiny Size** - ~15KB min+gzip (vs React 40KB+, Vue 33KB+)
705
271
 
706
- ```
272
+ ## Real-World Examples
707
273
 
708
- `data-bind-focus` binding is an event handler binding for 'focus' event. The handler will receive ` event object ` and the `DOM element`.
274
+ - [**TodoMVC**](https://gogocat.github.io/dataBind/examples/todomvc.html) - Classic todo app
275
+ - [**Bootstrap Integration**](https://gogocat.github.io/dataBind/examples/bootstrap.html) - Multi-component app
276
+ - [**Complex Lists**](https://gogocat.github.io/dataBind/examples/forOfBindingComplex.html) - Nested templates
277
+ - [**Reactive Demo**](https://gogocat.github.io/dataBind/examples/reactiveDemo.html) - Reactive state examples
709
278
 
710
- ### hover binding
279
+ ## Use Cases
711
280
 
712
- ```javascript
281
+ **Perfect For:**
713
282
 
714
- <div data-bind-hover="onHover">Hi</div>
283
+ ✅ Adding interactivity to server-rendered pages (PHP, .NET, Rails, etc.)
715
284
 
716
-
285
+ ✅ Progressive enhancement of existing sites
717
286
 
718
- // js
719
- const viewModel = {
720
- onHover: {
721
- in: function(e, $el) {
722
- // do something when mouse in
723
- },
724
- out: function(e, $el) {
725
- // do something when mouse out
726
- }
727
- }
728
- }
287
+ Rapid prototyping without build setup
729
288
 
730
- ```
289
+ ✅ Small to medium web applications
731
290
 
732
- `data-bind-hover` binding is an special event handler binding for 'mouseenter' and 'mouseleave' events. The binding property must be a object with `in` and `out` functions. Each function will receive ` event object ` and the `DOM element`.
291
+ Projects where bundle size matters (eg Interactive Ad / widget on 3rd party web site)
733
292
 
734
-
293
+ ✅ Teams that prefer vanilla JavaScript
735
294
 
736
- ### submit binding
737
295
 
738
- ```javascript
296
+ **Not Ideal For:**
739
297
 
740
- <form id="my-form" data-bind-submit="onSubmit">
298
+ ❌ Large single-page applications (consider Vue, React, Angular)
741
299
 
742
- ...
300
+ ❌ Projects requiring full framework ecosystem (routing, state management, etc.)
743
301
 
744
- </form>
302
+ ❌ Micro-components smaller than a section/widget
745
303
 
746
-
747
304
 
748
- // js
749
- const viewModel = {
750
- onSubmit: function(e, $el, formData) {
751
- // do something...
752
- }
753
- }
754
-
755
- ```
305
+ ## Philosophy
756
306
 
757
- `data-bind-focus` binding is an event handler binding for 'submit' event. The handler will receive ` event object ` and the `DOM element` and a JSON object represent the form data.
307
+ dataBind follows these principles:
758
308
 
759
-
309
+ 1. **Simplicity** - HTML is the template, JavaScript is the logic. No new syntax to learn.
310
+ 2. **Pragmatism** - Leverage existing infrastructure. Work with what you have.
311
+ 3. **Performance** - Small, fast, and efficient. No bloat.
312
+ 4. **Zero Dependencies** - No build tools, no framework lock-in.
313
+ 5. **Progressive Enhancement** - Add reactivity where needed, keep it simple where possible.
760
314
 
761
- ### Filter
315
+ ## API Overview
762
316
 
317
+ ### Initialization
763
318
  ```javascript
764
-
765
- <p>Price: <span data-bind-text="story.price | toDiscount | addGst"></span></p>
766
-
767
-
768
-
769
- // js
770
- const viewModel = {
771
- gstRate: 1.1,
772
- discountRate: 10,
773
- story: {
774
- price: 100
775
- },
776
- toDiscount: function(value) {
777
- return Number(value) * this.discountRate;
778
- },
779
- addGst: function(value) {
780
- return Number(value) * this.gstRate;
781
- },
782
- }
783
-
319
+ dataBind.init(element, viewModel, options?)
784
320
  ```
321
+ - `element`: Root DOM element
322
+ - `viewModel`: Plain JavaScript object
323
+ - `options`: `{ reactive: boolean, trackChanges: boolean }`
785
324
 
786
- Filter is a convenient way to carry a value and run through series of functions. In this example `data-bind-text` binding refernce to the viewModel property `story.price`. With the ` | ` filter annotation, the value `100` will then pass to `toDiscount` method, and then `addGst` methods. The last fitler's value will then use for display.
787
-
788
- 'Filter' is just simple function that recevie a value and return a value.
789
-
790
-
791
-
792
- ### $data, $root and $index
793
-
325
+ ### Rendering
794
326
  ```javascript
795
-
796
- <div data-bind-for="question of questions">
797
- <label
798
- data-bind-text="question.title"
799
- data-bind-attr="getQuestionLabelAttr($data, $index)"
800
- data-bind-css="$root.labelCss"
801
- >
802
- </label>
803
- <input type="text" data-bind-attr="getQuestionInputAttr($data, $index)">
804
- </div>
805
-
806
-
807
-
808
- // js
809
- const viewModel = {
810
- labelCss: 'form-label',
811
- questions: [{
812
- title: 'How are you?',
813
- fieldName: 'howAreYou',
814
- }],
815
- getQuestionLabelAttr: function(data, index, oldAttr, $el) {
816
- return {
817
- 'for': `${data.fieldName}-${index}`,
818
- };
819
- },
820
- getQuestionInputAttr: function(data, index, oldAttr, $el) {
821
- return {
822
- 'name': `${data.fieldName}-${index}`,
823
- 'id': `${data.fieldName}-${index}`,
824
- };
825
- },
826
- }
827
-
327
+ app.render(options?) // Returns Promise
828
328
  ```
829
329
 
830
- When using `data-bind-for` binding, `$data` is refer to the current data in the loop. `$index` is refer to the current loop index
831
-
832
- `$root` is refer to the viewModel root level.
833
-
834
-
835
-
836
- ### One time binding
837
-
330
+ ### Reactive Updates
838
331
  ```javascript
839
-
840
- <div data-bind-if="renderIntro | once">
841
- <h1>Introduction</h1>
842
- </div>
843
-
844
-
845
-
846
- // js
847
- const viewModel = {
848
- renderIntro: false
849
- }
850
-
332
+ app.viewModel.property = value; // Automatic render in reactive mode
851
333
  ```
852
334
 
853
- `once` is a reserved word in Filter logic, which does one time only binding. In this example because `renderIntro` is false. `data-bind-if` will not render the bound element, and because it has filter of `once`. It will not re-render the element anymore even later `renderIntro` is set to `true`. dataBind actually unbind the element after first render.
854
-
855
-
856
-
857
- ### Communicate between components
858
-
859
- dataBind use pub/sub pattern to cross comminicate between components. In the [**bootstrap examples**](https://gogocat.github.io/dataBind/examples/bootstrap.html)
860
-
335
+ ### Lifecycle Hooks
861
336
  ```javascript
862
-
863
- const compSearchBar = dataBind.init(
864
- document.querySelector('[data-bind-comp="search-bar"]'),
865
- viewModel
866
- );
867
-
868
- compSearchBar
869
- .render()
870
- .then(function(comp) {
871
- let self = comp;
872
- compSearchBar.subscribe('SEARCH-COMPLETED', self.viewModel.onSearchCompleted);
873
- });
874
-
875
-
876
-
877
- \\ compSearchResults.js
878
-
879
- ...
880
-
881
- compSearchResults.publish('SEARCH-COMPLETED', data);
882
-
883
- ..
884
-
337
+ app.afterRender(callback) // Called after each render
338
+ app.removeAfterRender(callback) // Remove specific callback
339
+ app.clearAfterRender() // Remove all callbacks
885
340
  ```
886
341
 
887
- Search bar component subscribed ` SEARCH-COMPLETED` event with `onSearchCompleted` as handler after the initial `render` call.
888
-
889
-
890
-
891
- Late on, `compSearchResults` component **publish** `SEARCH-COMPLETED` event with data. Which will then trigger **compSearchBar** component's `onSearchCompleted` handler.
892
-
893
-
894
-
895
- > Notice the event publisher and the event subscriber are the individual component. There is no central pub/sub channel. So multiple components can subscribe a same event and can be unsubscribe individually.
896
-
897
-
898
-
899
- Supported events are
900
-
901
- - **subscribe** - component subscribe an event
902
-
903
- - **subscribeOnce** - component subscribe an event only once
904
-
905
- - **unsubscribe** - component unsubscribe an event
906
-
907
- - **unsubscribeAll** - component unsubscribe all events
908
-
909
- - **publish** - component publish an event
910
-
911
-
912
-
913
- ### Server side rendering and rehydration
914
-
915
- dataBind respect any server sider rendering technology. Just mark the component with `data-server-rendered` attribute.
916
-
917
- ```html
918
-
919
- <div data-bind-comp="search-bar" data-server-rendered>
920
- ...
921
- </div>
922
-
342
+ ### Events
343
+ ```javascript
344
+ app.subscribe(event, handler)
345
+ app.subscribeOnce(event, handler)
346
+ app.publish(event, data)
347
+ app.unsubscribe(event)
348
+ app.unsubscribeAll()
349
+ ```
350
+
351
+ ## Complete Binding Reference
352
+
353
+ | Binding | Purpose | Example |
354
+ |---------|---------|---------|
355
+ | `data-bind-text` | Display text content | `<p data-bind-text="message"></p>` |
356
+ | `data-bind-click` | Click event | `<button data-bind-click="handleClick"></button>` |
357
+ | `data-bind-change` | Change event (inputs) | `<input data-bind-change="onChange">` |
358
+ | `data-bind-model` | Two-way binding | `<input data-bind-model="username">` |
359
+ | `data-bind-if` | Conditional render | `<div data-bind-if="isVisible">` |
360
+ | `data-bind-show` | Conditional display | `<div data-bind-show="isVisible">` |
361
+ | `data-bind-for` | List rendering | `<li data-bind-for="item in items">` |
362
+ | `data-bind-css` | Dynamic classes | `<div data-bind-css="{ active: isActive }">` |
363
+ | `data-bind-attr` | Dynamic attributes | `<img data-bind-attr="getImageAttrs">` |
364
+ | `data-bind-tmp` | Template rendering | `<div data-bind-tmp="{id: 'tpl', data: 'user'}">` |
365
+ | `data-bind-switch` | Switch statement | `<div data-bind-switch="state">` |
366
+ | `data-bind-submit` | Form submit | `<form data-bind-submit="onSubmit">` |
367
+ | `data-bind-blur` | Blur event | `<input data-bind-blur="onBlur">` |
368
+ | `data-bind-focus` | Focus event | `<input data-bind-focus="onFocus">` |
369
+ | `data-bind-dblclick` | Double-click | `<div data-bind-dblclick="onDblClick">` |
370
+ | `data-bind-hover` | Hover in/out | `<div data-bind-hover="onHover">` |
371
+
372
+ ## Browser Support
373
+
374
+ - Chrome (latest)
375
+ - Firefox (latest)
376
+ - Safari (latest)
377
+ - Edge (latest)
378
+
379
+ **Note:** Reactive mode requires Proxy support (IE11 not supported for reactive mode, but manual mode works).
380
+
381
+ ## Documentation
382
+
383
+ - [Configuration Guide](./CONFIGURATION.md) - Global settings and options
384
+ - [Examples](./examples/) - Live examples and demos
385
+ - [API Reference](./docs/) - Complete API documentation
386
+
387
+ ## Migration from Manual to Reactive Mode
388
+
389
+ **Before (Manual Mode):**
390
+ ```javascript
391
+ viewModel.counter++;
392
+ app.render(); // Manual render call
923
393
  ```
924
394
 
925
- **Rehydration** -
926
-
927
- When dataBind parse a component that has `data-server-rendered` attribute. dataBind will not render on the initial call of `render`, but will parse all the bindings.
928
-
929
-
930
-
931
- Next time calling `render` method will then update the view according to the viewModel.
932
-
933
-
934
-
935
- > The viewModel should has exact same data as the server side rendered version. So when later on calls `render` the content will update correctly.
936
-
937
-
938
-
939
- *Currently rehydration for **if, forOf and switch** bindings are still work in progress.*
940
-
941
-
942
-
943
- ## What dataBind is good for
944
-
945
- dataBind is designed for leaverage existing infrastructure.
946
-
947
- It is good fit for web sites that is:
948
-
949
- - has exisitng server side render technology eg. PHP, .Net, JSP etc
950
-
951
- - quickly build something to test the market but maintainable and easy to unit test
952
-
953
-
954
-
955
- ### what not
956
-
957
- - new project - Angular, Aurelia or React... may be a better choice
958
-
959
- - dataBind is not an full stack soultion
960
-
961
- - micro component base - dataBind's component concept is not aim to be as small as a `<p>` tag seen in some library
395
+ **After (Reactive Mode - Default):**
396
+ ```javascript
397
+ app.viewModel.counter++; // Automatic render!
398
+ ```
962
399
 
963
-
400
+ See [CONFIGURATION.md](./CONFIGURATION.md) for complete migration guide.
964
401
 
965
- ## What's next?
402
+ ## Contributing
966
403
 
967
- - The next major version, already on the way, will implement dataBind with native [web component](https://developer.mozilla.org/en-US/docs/Web/Web_Components). This will make micro component concept super easy, truely portable.
404
+ Contributions welcome! Please read our [contributing guidelines](./CONTRIBUTING.md) first.
968
405
 
969
-
406
+ ## License
970
407
 
971
- ----
408
+ [MIT](./LICENSE.txt)
972
409
 
973
- ## LICENSE
410
+ ---
974
411
 
975
- [MIT](https://gogocat.github.io/dataBind/LICENSE.txt).
412
+ **Made with ❤️ by developers who love simplicity**