Callback Action with parameter

Hi,

I need to call a uno method from UX with a parameter (stored in an JS Observable).
What is the correct syntax for that? (Didn’t find it in the docs).

<CameraStream >
    <CameraVisual ux:Name="myCamera" Facing="Back" >
	<Clicked >
	    <Callback Action="myCamera.singleTap /parameter from JS/" />
	</Clicked>
</CameraVisual>

CameraVisual.uno contains the singleTap method.

Thanks in advance for your support

Hi,

The best way would be to create the event handler in JavaScript. Then create a NativeModule in Uno, requiring that into JS, and calling that from your JS event handler.

Thanks a lot Anders,

Will have a look at that.

Anders Lassen wrote:

Hi,

The best way would be to create the event handler in JavaScript. Then create a NativeModule in Uno, requiring that into JS, and calling that from your JS event handler.

Hi Anders,

So it’s working if I call the uno module from the UX, using embedded Javascript, but I cannot manage to make it work if I put the javascript call in another .js file (the require seems not to be finding the .uno):

Project structure:

- Data
     - Context.js : global js file containing the call to the CameraExtended.uno method

- Preview
     - Camera
         - CameraExtended.uno : contains the method to call
         - other camera panel files
         - CameraStream.unoproj
     - PreviewPage.ux : instanciates a camera preview and calls singleTap through Context.js

- MainView.ux : imports the global Context.js and instanciates a PreviewPage.ux
- MyProject.unoproj : imports CameraStream.unoproj as project

MyProject.unoproj:

{
  "RootNamespace":"",
  "Packages": [
    "Fuse",
    "FuseJS",
    "Fuse.Maps",
    "Fuse.GeoLocation",
    "Fuse.Controls",
    "Android",
    "Fuse.Camera",
    "Uno.Permissions"
  ],
  "Includes": [
    "*",
    "**.js:Bundle",
    "Data/*.js:Bundle"
  ],
  "Projects":[
    "Preview/Camera/CameraStream.unoproj"
  ]
}

CameraExtended.uno:

using Uno;
using Fuse;
using Fuse.Scripting;
using Fuse.Reactive;
using Uno.Threading;
using Uno.IO;
using Uno.UX;

[UXGlobalModule]
public class CameraExtended : NativeModule
{
  public Camera Camera { get; set; }
  public CameraExtended()
  {
   AddMember(new NativeFunction("singleTap", (NativeCallback)this.SingleTap));
  }

  object SingleTap(Context c, object[] args)
  {
    debug_log "single tap JS";
    Camera.SingleTap();
    return null;
  }

CameraStream.unoproj:

{
  "RootNamespace":"",
    "Packages": [
    "Fuse",
    "FuseJS",
    ... other permissions
],
  "Includes": [
    "./*.uno",
    ... other includes
  ]
}

MainView.ux:

...
<JavaScript File="Data/Context.js" />
...
<PreviewPage ... />
...

Context.js:

var cameraExt = require("../Preview/Camera/CameraExtended");
...
function singleTap () {
  cameraExt
     .singleTap()
     .then(function (file) { })
	.catch(function (e) {
		debug_log(e);
	});
}
...singleTap is exported...

PreviewPage.ux:

...
<CameraStream>
     <CameraVisual Camera="cam" Facing="Front" ux:Name="myCam">
	 <Clicked >
	      <Callback Handler="{singleTap}" />
...

Thanks in advance for your help!

Hi!

You don’t require Uno files by path. You have to register a global key for your module, like this:

    [UXGlobalModule]
public sealed class Camera : NativeModule
{
	static readonly Camera _instance;
	public Camera()
	{
		if(_instance != null)return;
		Resource.SetGlobalKey(_instance = this, "FuseJS/Camera");

And then require("FuseJS/Camera")

Thanks Anders, the require is working now, still I’m getting a null pointer exception when, in the JS, I call a method on the object.

The UX is using the camera as follows:

<CameraStream>
   <CameraVisual Camera="cam" Facing="Front">
      <Clicked >
         <Callback Handler="{singleTap}" />
      </Clicked>
   </CameraVisual>
   <Camera ux:Global="cam" />
   <CameraExtended ux:Global="CameraExtended" Camera="cam" /> : This is the file required in JS
</CameraStream>

(CameraStream, CameraVisual and Camera correspond to other uno files from CameraPanel)

In the JS file, I use:

var cameraExt = require("FuseJS/CameraExtended");
...
function singleTap () {
   cameraExt  <<== is null
      .singleTap()
      .then(function (file) { i will use this later on })
      .catch(function (e) { debug_log(e); });
}

I updated the uno file as told:

using Uno;
using Fuse;
using Fuse.Scripting;
using Fuse.Reactive;
using Uno.Threading;
using Uno.IO;
using Uno.UX;

[UXGlobalModule]
public sealed class CameraExtended : NativeModule
{
  public Camera Camera { get; set; }
  static readonly CameraExtended _instance;

  public CameraExtended()
  {
    if(_instance != null)return;
    Resource.SetGlobalKey(_instance = this, "FuseJS/CameraExtended");

    AddMember(new NativeFunction("singleTap", (NativeCallback)this.SingleTap));

  }
  object SingleTap(Context c, object[] args)
  {
    debug_log "single tap JS";
    Camera.SingleTap();
    return null;
  }
}

Thanks!

Camera is never initialized, so its natural that you get a NullReferenceException

Anders do you mean Camera is not initialized in CameraExtended.uno?

In the UX file, Camera is initialized: (?)
from the code above:

<Camera ux:Global="cam" />
<CameraExtended ux:Global="CameraExtended" Camera="cam" />

Well, when you do ux:Global, you’re creating a new instance of the module. To get THAT instance, simply do require("CameraExtended"). The UXGlobalModule instance at require("FuseJS/CameraExtended") however does not have it’s Camera initialized.

I’d reccommend doing:

 Camera _camera = new Camera();

And

_camera.SingleTap();

And ditching those two UX lines, and requiring the UXGlobalModule instead

I see, thanks a lot!
For the record, I have to maintain the two lines in UX and not requiring the global module as those two lines in UX are inside another .uno class, which controls the camera and camera preview, and there the Camera is indeed initialized.