updateElement method

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

Implementation

@override
void updateElement(String tag, String? id, String? classes, Map<String, String>? styles,
    Map<String, String>? attributes, Map<String, EventCallback>? events) {
  late Set<String> attributesToRemove;
  late web.Element elem;

  var namespace = xmlns[tag];
  if (namespace == null && (parent?.node?.instanceOfString("Element") ?? false)) {
    namespace = (parent?.node as web.Element).namespaceURI;
  }

  diff:
  if (node == null) {
    if (parent!.toHydrate.isNotEmpty) {
      for (final e in parent!.toHydrate) {
        if (e.instanceOfString('Element') && (e as web.Element).tagName.toLowerCase() == tag) {
          if (kVerboseMode) {
            print("Hydrate html node: $e");
          }
          elem = node = e;
          attributesToRemove = {};
          for (var i = 0; i < elem.attributes.length; i++) {
            attributesToRemove.add(elem.attributes.item(i)!.name);
          }
          parent!.toHydrate.remove(e);
          toHydrate = e.childNodes.toIterable().toList();
          break diff;
        }
      }
    }

    elem = node = _createElement(tag, namespace);
    attributesToRemove = {};
    if (kVerboseMode) {
      web.console.log("Create html node: $elem".toJS);
    }
  } else {
    if (!node.instanceOfString('Element') || (node as web.Element).tagName.toLowerCase() != tag) {
      elem = _createElement(tag, namespace);
      final old = node!;
      node!.parentNode!.replaceChild(elem, old);
      node = elem;
      if (old.childNodes.length > 0) {
        for (final child in old.childNodes.toIterable()) {
          elem.append(child as dynamic);
        }
      }
      attributesToRemove = {};
      if (kVerboseMode) {
        print("Replace html node: $elem for $old");
      }
    } else {
      elem = node as web.Element;
      attributesToRemove = {};
      for (var i = 0; i < elem.attributes.length; i++) {
        attributesToRemove.add(elem.attributes.item(i)!.name);
      }
    }
  }

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

  if (attributes != null && attributes.isNotEmpty) {
    for (final attr in attributes.entries) {
      if (attr.key == 'value' &&
          elem.instanceOfString('HTMLInputElement') &&
          (elem as web.HTMLInputElement).value != attr.value) {
        if (kVerboseMode) {
          print("Set input value: ${attr.value}");
        }
        elem.value = attr.value;
        continue;
      }
      elem.clearOrSetAttribute(attr.key, attr.value);
    }
  }

  attributesToRemove.removeAll(['id', 'class', 'style', ...?attributes?.keys]);
  if (attributesToRemove.isNotEmpty) {
    for (final name in attributesToRemove) {
      elem.removeAttribute(name);
      if (kVerboseMode) {
        print("Remove attribute: $name");
      }
    }
  }

  if (events != null && events.isNotEmpty) {
    final prevEventTypes = this.events?.keys.toSet();
    this.events ??= <String, EventBinding>{};
    final dataEvents = this.events!;
    events.forEach((type, fn) {
      prevEventTypes?.remove(type);
      final currentBinding = dataEvents[type];
      if (currentBinding != null) {
        currentBinding.fn = fn;
      } else {
        dataEvents[type] = EventBinding(elem, type, fn);
      }
    });
    prevEventTypes?.forEach((type) {
      dataEvents.remove(type)?.clear();
    });
  } else {
    clearEvents();
  }
}