dart-lang / web

Lightweight browser API bindings built around JS static interop.
https://pub.dev/packages/web
BSD 3-Clause "New" or "Revised" License
134 stars 23 forks source link

`Element.replaceChildren(node1, node2, node3, ...nodes)` / how to use `Function.apply` ? #292

Open jonasfj opened 2 months ago

jonasfj commented 2 months ago

In JS we can do:

containerForValues.replaceChildren(...values.map((value) => {
  const element = document.createElement('div');
  element.innerHTML = value;
  return element;
}));

In Dart we I tried using:

containerForValues.replaceChildren(
  values
      .map(
        (value) => HTMLDivElement()
          ..setHTMLUnsafe(value),
      )
      .toList()
      .toJS,
);

But this doesn't work, because the first argument can't be a list. So the list is converted to a String. Do my containerForValues ends up showing:

[object HTMLDivElement],[object HTMLDivElement],[object HTMLDivElement]

:D

ykmnkmi commented 2 months ago

Using dart:js_interop_unsafe:

import 'dart:js_interop';
import 'dart:js_interop_unsafe';

import 'package:web/web.dart';

void main() {
  var container = document.querySelector('body') as Element;
  container.callMethodVarArgs('replaceChildren'.toJS, [/* ... */]);
}

Without:

import 'dart:js_interop';

import 'package:web/web.dart';

void main() {
  var container = document.querySelector('body') as Element;
  container.jsReplaceChildren.apply(container, <JSAny?>[/* */].toJS);
}

extension on Element {
  @JS('replaceChildren')
  external JSFunction get jsReplaceChildren;
}

extension on JSFunction {
  external R apply<R extends JSAny?>(JSAny? thisArgument, JSArray<JSAny?> arguments);
}
srujzs commented 2 months ago

@ykmnkmi nailed it. callMethodVarArgs is ultimately a JS Function.apply call, so the end result is the same.