binder.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /**
  2. * Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
  3. * Available via the MIT license.
  4. * see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
  5. */
  6. /**
  7. * The binder joins an object instance and a DOM element tree by applying databinding and/or invoking binding lifecycle callbacks (binding and bindingComplete).
  8. * @module binder
  9. * @requires system
  10. * @requires knockout
  11. */
  12. define(['durandal/system', 'knockout'], function (system, ko) {
  13. var binder,
  14. insufficientInfoMessage = 'Insufficient Information to Bind',
  15. unexpectedViewMessage = 'Unexpected View Type',
  16. bindingInstructionKey = 'durandal-binding-instruction',
  17. koBindingContextKey = '__ko_bindingContext__';
  18. function normalizeBindingInstruction(result){
  19. if(result === undefined){
  20. return { applyBindings: true };
  21. }
  22. if(system.isBoolean(result)){
  23. return { applyBindings:result };
  24. }
  25. if(result.applyBindings === undefined){
  26. result.applyBindings = true;
  27. }
  28. return result;
  29. }
  30. function doBind(obj, view, bindingTarget, data){
  31. if (!view || !bindingTarget) {
  32. if (binder.throwOnErrors) {
  33. system.error(insufficientInfoMessage);
  34. } else {
  35. system.log(insufficientInfoMessage, view, data);
  36. }
  37. return;
  38. }
  39. if (!view.getAttribute) {
  40. if (binder.throwOnErrors) {
  41. system.error(unexpectedViewMessage);
  42. } else {
  43. system.log(unexpectedViewMessage, view, data);
  44. }
  45. return;
  46. }
  47. var viewName = view.getAttribute('data-view');
  48. try {
  49. var instruction;
  50. if (obj && obj.binding) {
  51. instruction = obj.binding(view);
  52. }
  53. instruction = normalizeBindingInstruction(instruction);
  54. binder.binding(data, view, instruction);
  55. if(instruction.applyBindings){
  56. system.log('Binding', viewName, data);
  57. ko.applyBindings(bindingTarget, view);
  58. }else if(obj){
  59. ko.utils.domData.set(view, koBindingContextKey, { $data:obj });
  60. }
  61. binder.bindingComplete(data, view, instruction);
  62. if (obj && obj.bindingComplete) {
  63. obj.bindingComplete(view);
  64. }
  65. ko.utils.domData.set(view, bindingInstructionKey, instruction);
  66. return instruction;
  67. } catch (e) {
  68. e.message = e.message + ';\nView: ' + viewName + ";\nModuleId: " + system.getModuleId(data);
  69. if (binder.throwOnErrors) {
  70. system.error(e);
  71. } else {
  72. system.log(e.message);
  73. }
  74. }
  75. }
  76. /**
  77. * @class BinderModule
  78. * @static
  79. */
  80. return binder = {
  81. /**
  82. * Called before every binding operation. Does nothing by default.
  83. * @method binding
  84. * @param {object} data The data that is about to be bound.
  85. * @param {DOMElement} view The view that is about to be bound.
  86. * @param {object} instruction The object that carries the binding instructions.
  87. */
  88. binding: system.noop,
  89. /**
  90. * Called after every binding operation. Does nothing by default.
  91. * @method bindingComplete
  92. * @param {object} data The data that has just been bound.
  93. * @param {DOMElement} view The view that has just been bound.
  94. * @param {object} instruction The object that carries the binding instructions.
  95. */
  96. bindingComplete: system.noop,
  97. /**
  98. * Indicates whether or not the binding system should throw errors or not.
  99. * @property {boolean} throwOnErrors
  100. * @default false The binding system will not throw errors by default. Instead it will log them.
  101. */
  102. throwOnErrors: false,
  103. /**
  104. * Gets the binding instruction that was associated with a view when it was bound.
  105. * @method getBindingInstruction
  106. * @param {DOMElement} view The view that was previously bound.
  107. * @return {object} The object that carries the binding instructions.
  108. */
  109. getBindingInstruction:function(view){
  110. return ko.utils.domData.get(view, bindingInstructionKey);
  111. },
  112. /**
  113. * Binds the view, preserving the existing binding context. Optionally, a new context can be created, parented to the previous context.
  114. * @method bindContext
  115. * @param {KnockoutBindingContext} bindingContext The current binding context.
  116. * @param {DOMElement} view The view to bind.
  117. * @param {object} [obj] The data to bind to, causing the creation of a child binding context if present.
  118. * @param {string} [dataAlias] An alias for $data if present.
  119. */
  120. bindContext: function(bindingContext, view, obj, dataAlias) {
  121. if (obj && bindingContext) {
  122. bindingContext = bindingContext.createChildContext(obj, typeof(dataAlias) === 'string' ? dataAlias : null);
  123. }
  124. return doBind(obj, view, bindingContext, obj || (bindingContext ? bindingContext.$data : null));
  125. },
  126. /**
  127. * Binds the view, preserving the existing binding context. Optionally, a new context can be created, parented to the previous context.
  128. * @method bind
  129. * @param {object} obj The data to bind to.
  130. * @param {DOMElement} view The view to bind.
  131. */
  132. bind: function(obj, view) {
  133. return doBind(obj, view, obj, obj);
  134. }
  135. };
  136. });