viewmodel.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. var Compiler = require('./compiler')
  2. /*
  3. * ViewModel exposed to the user that holds data,
  4. * computed properties, event handlers
  5. * and a few reserved methods
  6. */
  7. function ViewModel (options) {
  8. // just compile. options are passed directly to compiler
  9. new Compiler(this, options)
  10. }
  11. var VMProto = ViewModel.prototype
  12. /*
  13. * Convenience function to set an actual nested value
  14. * from a flat key string. Used in directives.
  15. */
  16. VMProto.$set = function (key, value) {
  17. var path = key.split('.'),
  18. obj = getTargetVM(this, path)
  19. if (!obj) return
  20. for (var d = 0, l = path.length - 1; d < l; d++) {
  21. obj = obj[path[d]]
  22. }
  23. obj[path[d]] = value
  24. }
  25. /*
  26. * The function for getting a key
  27. * which will go up along the prototype chain of the bindings
  28. * Used in exp-parser.
  29. */
  30. VMProto.$get = function (key) {
  31. var path = key.split('.'),
  32. obj = getTargetVM(this, path),
  33. vm = obj
  34. if (!obj) return
  35. for (var d = 0, l = path.length; d < l; d++) {
  36. obj = obj[path[d]]
  37. }
  38. if (typeof obj === 'function') obj = obj.bind(vm)
  39. return obj
  40. }
  41. /*
  42. * watch a key on the viewmodel for changes
  43. * fire callback with new value
  44. */
  45. VMProto.$watch = function (key, callback) {
  46. this.$compiler.observer.on('change:' + key, callback)
  47. }
  48. /*
  49. * unwatch a key
  50. */
  51. VMProto.$unwatch = function (key, callback) {
  52. // workaround here
  53. // since the emitter module checks callback existence
  54. // by checking the length of arguments
  55. var args = ['change:' + key],
  56. ob = this.$compiler.observer
  57. if (callback) args.push(callback)
  58. ob.off.apply(ob, args)
  59. }
  60. /*
  61. * unbind everything, remove everything
  62. */
  63. VMProto.$destroy = function () {
  64. this.$compiler.destroy()
  65. this.$compiler = null
  66. }
  67. /*
  68. * broadcast an event to all child VMs recursively.
  69. */
  70. VMProto.$broadcast = function () {
  71. var children = this.$compiler.childCompilers,
  72. i = children.length,
  73. child
  74. while (i--) {
  75. child = children[i]
  76. child.emitter.emit.apply(child.emitter, arguments)
  77. child.vm.$broadcast.apply(child.vm, arguments)
  78. }
  79. }
  80. /*
  81. * emit an event that propagates all the way up to parent VMs.
  82. */
  83. VMProto.$emit = function () {
  84. var parent = this.$compiler.parentCompiler
  85. if (parent) {
  86. parent.emitter.emit.apply(parent.emitter, arguments)
  87. parent.vm.$emit.apply(parent.vm, arguments)
  88. }
  89. }
  90. /*
  91. * listen for a broadcasted/emitted event
  92. */
  93. VMProto.$on = function () {
  94. var emitter = this.$compiler.emitter
  95. emitter.on.apply(emitter, arguments)
  96. }
  97. /*
  98. * stop listening
  99. */
  100. VMProto.$off = function () {
  101. var emitter = this.$compiler.emitter
  102. emitter.off.apply(emitter, arguments)
  103. }
  104. /*
  105. * If a VM doesn't contain a path, go up the prototype chain
  106. * to locate the ancestor that has it.
  107. */
  108. function getTargetVM (vm, path) {
  109. var baseKey = path[0],
  110. binding = vm.$compiler.bindings[baseKey]
  111. return binding
  112. ? binding.compiler.vm
  113. : null
  114. }
  115. module.exports = ViewModel