update method

  1. @override
void update(
  1. String? id,
  2. String? classes,
  3. Map<String, String>? styles,
  4. Map<String, String>? attributes,
  5. Map<String, EventCallback>? events,
)
override

Implementation

@override
void update(
  String? id,
  String? classes,
  Map<String, String>? styles,
  Map<String, String>? attributes,
  Map<String, EventCallback>? events,
) {
  final Set<String> originalAttributes = {
    for (var i = 0; i < node.attributes.length; i++) node.attributes.item(i)!.name,
  };

  node.clearOrSetAttribute('id', id);
  node.clearOrSetAttribute('class', classes == null || classes.isEmpty ? null : classes);
  node.clearOrSetAttribute(
    'style',
    styles == null || styles.isEmpty ? null : styles.entries.map((e) => '${e.key}: ${e.value}').join('; '),
  );

  if (attributes != null && attributes.isNotEmpty) {
    for (final MapEntry(key: attrName, value: attrValue) in attributes.entries) {
      if (attrName == 'value') {
        if (node.isHtmlSelectElement) {
          final nodeAsSelectElement = node as web.HTMLSelectElement;
          if (nodeAsSelectElement.value != attrValue) {
            if (kVerboseMode) {
              print('Set select value: $attrValue');
            }
            nodeAsSelectElement.value = attrValue;
          }
          continue;
        }

        if (node.isHtmlInputElement) {
          final nodeAsInputElement = node as web.HTMLInputElement;
          if (nodeAsInputElement.value != attrValue) {
            if (kVerboseMode) {
              print('Set input value: $attrValue');
            }
            nodeAsInputElement.value = attrValue;
          }
          continue;
        }
      } else if (attrName == 'checked') {
        if (node.isHtmlInputElement) {
          final nodeAsInputElement = node as web.HTMLInputElement;
          if (nodeAsInputElement.type case 'checkbox' || 'radio') {
            final shouldBeChecked = attrValue == 'true';
            if (nodeAsInputElement.checked != shouldBeChecked) {
              if (kVerboseMode) {
                print('Set input checked: $shouldBeChecked');
              }
              nodeAsInputElement.checked = shouldBeChecked;
              if (!shouldBeChecked && node.hasAttribute('checked')) {
                // Remove the attribute if unchecked to avoid HTML5 validation issues.
                nodeAsInputElement.removeAttribute('checked');
              }
            }
            continue;
          }
        }
      } else if (attrName == 'indeterminate') {
        if (node.isHtmlInputElement) {
          final nodeAsInputElement = node as web.HTMLInputElement;
          if (nodeAsInputElement.type == 'checkbox') {
            final shouldBeIndeterminate = attrValue == 'true';
            if (nodeAsInputElement.indeterminate != shouldBeIndeterminate) {
              if (kVerboseMode) {
                print('Set input indeterminate: $shouldBeIndeterminate');
              }
              nodeAsInputElement.indeterminate = shouldBeIndeterminate;
              if (!shouldBeIndeterminate && node.hasAttribute('indeterminate')) {
                // Remove the attribute if unchecked to avoid HTML5 validation issues.
                nodeAsInputElement.removeAttribute('indeterminate');
              }
            }
            continue;
          }
        }
      }

      node.clearOrSetAttribute(attrName, attrValue);
    }
  }

  final attributesToRemove = originalAttributes.difference({'id', 'class', 'style', ...?attributes?.keys});
  for (final name in attributesToRemove) {
    node.removeAttribute(name);
    if (kVerboseMode) {
      print('Removed attribute: $name');
    }
  }

  if (events != null && events.isNotEmpty) {
    final dataEvents = this.events ??= <String, EventBinding>{};
    final prevEventTypes = dataEvents.keys.toSet();
    events.forEach((type, fn) {
      prevEventTypes.remove(type);
      final currentBinding = dataEvents[type];
      if (currentBinding != null) {
        currentBinding.fn = fn;
      } else {
        dataEvents[type] = EventBinding(node, type, fn);
      }
    });
    for (final type in prevEventTypes) {
      dataEvents.remove(type)?.clear();
    }
  } else {
    if (this.events case final existingEvents?) {
      for (final binding in existingEvents.values) {
        binding.clear();
      }
      this.events = null;
    }
  }
}