live.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. /**
  2. * @license
  3. * Copyright 2020 Google LLC
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. import { noChange, nothing } from '../lit-html.js';
  7. import { directive, Directive, PartType, } from '../directive.js';
  8. import { isSingleExpression, setCommittedValue } from '../directive-helpers.js';
  9. class LiveDirective extends Directive {
  10. constructor(partInfo) {
  11. super(partInfo);
  12. if (!(partInfo.type === PartType.PROPERTY ||
  13. partInfo.type === PartType.ATTRIBUTE ||
  14. partInfo.type === PartType.BOOLEAN_ATTRIBUTE)) {
  15. throw new Error('The `live` directive is not allowed on child or event bindings');
  16. }
  17. if (!isSingleExpression(partInfo)) {
  18. throw new Error('`live` bindings can only contain a single expression');
  19. }
  20. }
  21. render(value) {
  22. return value;
  23. }
  24. update(part, [value]) {
  25. if (value === noChange || value === nothing) {
  26. return value;
  27. }
  28. const element = part.element;
  29. const name = part.name;
  30. if (part.type === PartType.PROPERTY) {
  31. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  32. if (value === element[name]) {
  33. return noChange;
  34. }
  35. }
  36. else if (part.type === PartType.BOOLEAN_ATTRIBUTE) {
  37. if (!!value === element.hasAttribute(name)) {
  38. return noChange;
  39. }
  40. }
  41. else if (part.type === PartType.ATTRIBUTE) {
  42. if (element.getAttribute(name) === String(value)) {
  43. return noChange;
  44. }
  45. }
  46. // Resets the part's value, causing its dirty-check to fail so that it
  47. // always sets the value.
  48. setCommittedValue(part);
  49. return value;
  50. }
  51. }
  52. /**
  53. * Checks binding values against live DOM values, instead of previously bound
  54. * values, when determining whether to update the value.
  55. *
  56. * This is useful for cases where the DOM value may change from outside of
  57. * lit-html, such as with a binding to an `<input>` element's `value` property,
  58. * a content editable elements text, or to a custom element that changes it's
  59. * own properties or attributes.
  60. *
  61. * In these cases if the DOM value changes, but the value set through lit-html
  62. * bindings hasn't, lit-html won't know to update the DOM value and will leave
  63. * it alone. If this is not what you want--if you want to overwrite the DOM
  64. * value with the bound value no matter what--use the `live()` directive:
  65. *
  66. * ```js
  67. * html`<input .value=${live(x)}>`
  68. * ```
  69. *
  70. * `live()` performs a strict equality check agains the live DOM value, and if
  71. * the new value is equal to the live value, does nothing. This means that
  72. * `live()` should not be used when the binding will cause a type conversion. If
  73. * you use `live()` with an attribute binding, make sure that only strings are
  74. * passed in, or the binding will update every render.
  75. */
  76. export const live = directive(LiveDirective);
  77. //# sourceMappingURL=live.js.map