Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dart:js_interop should provide a Function.toJS call that automatically binds zones #54507

Open
insinfo opened this issue Jan 3, 2024 · 9 comments
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-js-interop Issues that impact all js interop

Comments

@insinfo
Copy link

insinfo commented Jan 3, 2024

I'm currently building a small web application with AngularDart and Fabric.js, and I have many fabric event callbaks that I need to pass Dart functions that will be called by these events and within these functions I change variables of the component class, and these variables are linked to the html elements of the template, but changes to variables are not being reflected in the elements

 void initFabric() {
    canvas = Canvas(canvasEl);
    stage = Rect(
      jsify({
        'left':
            (canvas.width / 2) - ((currentWidth * (stage?.scaleX ?? 1)) / 2),
        'top': 50,
        'width': currentWidth,
        'height': currentHeight,
        'fill': '#fff',
        'lockMovementY': true,
        'lockMovementX': true,
        'selectable': false,
        'hoverCursor': 'default',
      }),
    );

    canvas.add(stage);

    num zoom = 1;
    canvas.on('mouse:wheel', allowInterop((opt) {
      final deltaY = opt.e.deltaY;   
      final mousePoint = canvas.getPointer(opt.e, true);
      zoom = canvas.getZoom();
      zoom *= pow(0.999, deltaY);
      if (zoom > 20) zoom = 20;
      if (zoom < 0.01) zoom = 0.01;    
      canvas.zoomToPoint(Point(mousePoint.x, mousePoint.y), zoom);
      opt.e.preventDefault();
      opt.e.stopPropagation();
    }));

    canvas.on('selection:created', allowInterop((obj) {
  //change detection doesn't work
      onSelectObject(obj);
    }));
    canvas.on('selection:updated', allowInterop((obj) {
  //change detection doesn't work
      onSelectObject(obj);
    }));

    canvas.on('selection:cleared', allowInterop((event) {
      //change detection doesn't work
      onUnSelectObject(event);
    }));
   
  }

  void onUnSelectObject(event) {
    //change current width of stage (valid drawing area)
 //change detection doesn't work
    currentWidth = stage!.getScaledWidth();
    currentHeight = stage!.getScaledHeight();
  }

  void onSelectObject(event) {
 //change detection doesn't work
    final activeObj = canvas.getActiveObject();
    final scaledWidth = activeObj.getScaledWidth();
    final scaledHeight = activeObj.getScaledHeight();

    currentWidth = scaledWidth;
    currentHeight = scaledHeight;

  }

angulardart-community/angular#69

Dart SDK version: 3.2.1 (stable) (Wed Nov 22 08:59:13 2023 +0000) on "windows_x64"

@insinfo
Copy link
Author

insinfo commented Jan 3, 2024

Maybe it didn't work because Angular detects changes based on zones?, and when you put a function in AllowInterop, my suspicion is that anything that runs inside it will escape its current zone?

@mit-mit mit-mit added the area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. label Jan 3, 2024
@sigmundch sigmundch added the web-js-interop Issues that impact all js interop label Jan 3, 2024
@natebosch
Copy link
Member

my suspicion is that anything that runs inside it will escape its current zone?

I don't think allowInterop itself should cause any problem with zones. Invoking a callback from JS external to the Dart code can cause that callback to run outside any Dart zone. You can bind the callback to the zone with bind or store the zone when creating the callback and use run within the callback to ensure it runs in the expected zone.

@srujzs
Copy link
Contributor

srujzs commented Jan 4, 2024

Yeah, you'll likely need to manage the zones manually here. dart:html has some code to automatically do this, but interop does not. allowInterop doesn't make any copies of variables.

@insinfo
Copy link
Author

insinfo commented Jan 5, 2024

@natebosch
How to use zone bind with allowInterop callback ?

@natebosch
Copy link
Member

The specifics will depend on how many arguments your function takes. For instance if it takes no arguments:

void Function() theCallback;
final zoneBound = Zone.current.bindCallback(theCallback);
final jsCallable = allowInterop(zoneBound);

If there is 1 or 2 arguments, you can use https://api.dart.dev/stable/3.2.4/dart-async/Zone/bindUnaryCallback.html or https://api.dart.dev/stable/3.2.4/dart-async/Zone/bindBinaryCallback.html

The other option is to store the current zone and wrap in a lambda that uses zone.run.

final currentZone = Zone.current;
final jsCallable = allowInterop((arg1, arg2, arg3) {
  return currentZone.run(() {
    return theCallback(arg1, arg2, arg3);
  });
});

@lrhn
Copy link
Member

lrhn commented Jan 11, 2024

outside any Dart zone

For the record, there is no such thing as Dart code running outside of any Dart zone. If it's running Dart code, then Zone.current will have some value - it's non-nullable!
Maybe not the value you hoped for, but definitely some zone.

Most likely it will be in whichever zone was current when control last entered the native JS code. If that happened from the event loop, maybe it'll be the root zone. Maybe.

Using the bind functions is what I'd recommend too.

@insinfo
Copy link
Author

insinfo commented Jan 16, 2024

perhaps it would be interesting in the future if allowInterop had a second boolean argument to enable capturing the current zone of the calling site and using this zone to execute the callback, just like dart:html already manages this altomatically

@insinfo
Copy link
Author

insinfo commented Jan 16, 2024

I just saw that there are some inconsistencies in the dart2js and ddc compilers, if you try to call a function or property that you know exists in the event object, this function is normally called in ddc, but it is not called in dart2js, several errors occur, in addition If you compile the code with dart2js -o0 the application is completely broken

I was trying to debug my application with dart2js -o0 and I started getting a lot of bugs

canvas.on('selection:cleared', allowInterop((event) {
    currentWidth = stage!.getScaledWidth();
    currentHeight = stage!.getScaledHeight();
 }));

@srujzs
Copy link
Contributor

srujzs commented Jan 16, 2024

perhaps it would be interesting in the future if allowInterop had a second boolean argument to enable capturing the current zone of the calling site and using this zone to execute the callback, just like dart:html already manages this altomatically

Indeed, this came up in our discussion when we talked about moving to package:web (as that support is missing at the moment in that package). One proposal was to have a Function.toJSBindCurrentZone in dart:js_interop that does the zone wrapping for you, similar to the allowInterop modification you propose. We'll likely have something available here. I don't think we have a canonical issue here, so I'll make this the canonical issue.

if you try to call a function or property that you know exists in the event object, this function is normally called in ddc, but it is not called in dart2js, several errors occur, in addition If you compile the code with dart2js -o0 the application is completely broken

Can you file a separate issue for this with a minimal repro? There's an ongoing issue in dart2js with certain compiler flags due to precedence that may be related to it breaking: #54534.

@srujzs srujzs changed the title does allowInterop make copies of variables captured in the scope? 'dart:js_interop' should provide a Function.toJS call that automatically binds zones Jan 16, 2024
@srujzs srujzs changed the title 'dart:js_interop' should provide a Function.toJS call that automatically binds zones dart:js_interop should provide a Function.toJS call that automatically binds zones Jan 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-js-interop Issues that impact all js interop
Projects
Status: No status
Development

No branches or pull requests

6 participants