binder.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // Cache DOM elements
  2. const inputElements = document.querySelectorAll('[data-model]');
  3. const boundElements = document.querySelectorAll('[data-bind]');
  4. const loopElements = document.querySelectorAll('[data-loop]');
  5. /* --- Bind element --- */
  6. function binder(data) {
  7. let scope = {}
  8. // Add data
  9. if (data) {
  10. for (const propName of Object.getOwnPropertyNames(data)) {
  11. scope[propName] = data[propName];
  12. setBindValue(propName, data[propName]);
  13. }
  14. }
  15. // Loop through input elements
  16. for (let el of inputElements) {
  17. if (el.type === 'text' || el.type === 'hidden') {
  18. // Get property name from each input with an attribute of 'mm-model'
  19. let propName = el.getAttribute('data-model');
  20. // Set property update logic
  21. setPropUpdateLogic(scope, propName);
  22. // Update bound scope property on input change
  23. scope[propName] = el.value;
  24. el.addEventListener('keyup', e => {
  25. scope[propName] = el.value;
  26. });
  27. }
  28. }
  29. return scope;
  30. };
  31. function setPropUpdateLogic(scope, prop) {
  32. if (!scope.hasOwnProperty(prop)) {
  33. let value;
  34. Object.defineProperty(scope, prop, {
  35. // Automatically update bound dom elements when a scope property is set to a new value
  36. set: (newValue) => {
  37. value = newValue;
  38. // Set input elements to new value
  39. for (let el of inputElements) {
  40. if (el.getAttribute('data-model') === prop) {
  41. if (el.type) {
  42. el.value = newValue;
  43. }
  44. }
  45. }
  46. // Set all other bound dom elements to new value
  47. setBindValue(prop, newValue);
  48. },
  49. get: () => {
  50. return value;
  51. },
  52. enumerable: true
  53. })
  54. }
  55. }
  56. function setBindValue(prop, newValue) {
  57. for (let el of boundElements) {
  58. if (el.getAttribute('data-bind') === prop) {
  59. if (!el.type) {
  60. el.innerHTML = newValue;
  61. }
  62. }
  63. }
  64. }
  65. /* --- For each --- */
  66. function looper(scope) {
  67. for (let el of loopElements) {
  68. let propName = el.getAttribute('data-loop');
  69. let data = scope[propName];
  70. let html = [];
  71. // If data is an array (if not do nothing)
  72. if (data && Array.isArray(data)) {
  73. // Add info to replace value
  74. for (let i = 0; i < data.length; i++) {
  75. html.push(el.innerHTML.replace(/data-val="/g, 'data-index="' + i + '" data-val="'));
  76. }
  77. el.innerHTML = html.join("\n");
  78. // Replace value for the current loop
  79. let currentLoopElements = document.querySelectorAll('[data-loop=' + propName + ']');
  80. currentLoopElements = currentLoopElements[0].childNodes;
  81. for (const currentElement of currentLoopElements) {
  82. if (currentElement.nodeName !== "#text" && currentElement.getAttribute('data-index')) {
  83. const val = scope[propName][currentElement.getAttribute('data-index')][currentElement.getAttribute('data-val')];
  84. if (val) {
  85. currentElement.innerHTML = scope[propName][currentElement.getAttribute('data-index')][currentElement.getAttribute('data-val')];
  86. }
  87. }
  88. }
  89. }
  90. }
  91. }