Conditional.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import { directive } from "../../../model/Directive";
  2. import { evaluateLater } from "../../../model/Evaluator";
  3. import { walk } from "../../../model/NodeWalker";
  4. import { effect } from "../../../model/Reactivity";
  5. import { PupperNode } from "../Node";
  6. import Debugger from "../../../util/Debugger";
  7. const debug = Debugger.extend("vdom:directives:conditional");
  8. /**
  9. * @directive x-if
  10. * @description Conditionally renders a tag's children nodes if the condition is met.
  11. */
  12. directive("if", async (node, { expression, scope }) => {
  13. const evaluate = evaluateLater(expression);
  14. // Save and remove the children
  15. const children = node.children;
  16. node = node.replaceWithComment();
  17. node.setIgnored();
  18. node.setRenderable(false);
  19. let clones: PupperNode[] = [];
  20. let lastValue: boolean = null;
  21. await effect(async () => {
  22. try {
  23. const value = await evaluate(scope);
  24. if (lastValue === value) {
  25. return;
  26. }
  27. lastValue = value;
  28. debug("%s evaluated to %O", expression, value);
  29. // If already rendered the clones
  30. if (clones.length) {
  31. clones.forEach((clone) => clone.delete());
  32. clones = [];
  33. }
  34. // If the conditional matched
  35. if (value) {
  36. // Clone them into the DOM
  37. clones = await walk(children.map((child) => child.clone().setParent(node.parent)), scope);
  38. node.insertBefore(...clones);
  39. }
  40. node.parent.setDirty();
  41. } catch(e) {
  42. console.warn("[pupper.js] failed to evaluate conditional:");
  43. console.error(e);
  44. }
  45. });
  46. });