BindingEngine in a nodejs application

I have a need to run the JavaScript portion of one of my plugins on the server side. Ultimately it will be a .net core app executing a nodejs app that consumes my plugin.

I just have a simple wrapper in place where I’m trying to get dependency injection working. If I eliminate the injection of BindingEngine in the plugin my nodejs wrapper will inject the rest of the dependencies with no issues. I looked at the aurelia-validation plugin for assistance at configuring, but it was no help.

I know binding engine is for sure an issue, will event aggregator be as well. I know it actually got injected when I run without binding engine.

My wrapper class on the nodejs side looks like this

import { initialize } from "aurelia-pal-nodejs";
import "aurelia-polyfills";
import { Container, autoinject } from "aurelia-dependency-injection";
import { ControlFactory } from "custom-controls";
import { configure as configureBindingLanguage } from "aurelia-templating-binding";
import { configure as configureValidation } from "aurelia-validation";

@autoinject
export class ControlFactoryWrapper {
  constructor(
    private customControlFactory: ControlFactory,
    private container: Container
  ) {
    initialize();
    configureBindingLanguage({ container });
    configureValidation({ container });
  }

  procesJson() {
    console.log("cfw class", this.customControlFactory);
    return this.customControlFactory;
  }
}

The console output

C:\source\node_apps\hello_world\node_modules\aurelia-dependency-injection\dist\commonjs\aurelia-dependency-injection.js:549
            throw new aureliaPal.AggregateError("Error invoking " + fn.name + ". Check the inner error for details.", e, true);
            ^

Error: Error invoking SVGAnalyzer. Check the inner error for details.
------------------------------------------------
Inner Error:
Message: _aureliaPal.DOM.createElement is not a function
Inner Error Stack:
TypeError: _aureliaPal.DOM.createElement is not a function
    at createElement (C:\source\node_apps\hello_world\node_modules\custom-controls\node_modules\aurelia-binding\dist\commonjs\aurelia-binding.js:4722:31)
    at new SVGAnalyzer (C:\source\node_apps\hello_world\node_modules\custom-controls\node_modules\aurelia-binding\dist\commonjs\aurelia-binding.js:4731:11)
    at Object.invoke (C:\source\node_apps\hello_world\node_modules\aurelia-dependency-injection\dist\commonjs\aurelia-dependency-injection.js:387:24)
    at InvocationHandler.invoke (C:\source\node_apps\hello_world\node_modules\aurelia-dependency-injection\dist\commonjs\aurelia-dependency-injection.js:360:28)
    at Container.invoke (C:\source\node_apps\hello_world\node_modules\aurelia-dependency-injection\dist\commonjs\aurelia-dependency-injection.js:546:28)
    at StrategyResolver.get (C:\source\node_apps\hello_world\node_modules\aurelia-dependency-injection\dist\commonjs\aurelia-dependency-injection.js:104:39)
    at Container.get (C:\source\node_apps\hello_world\node_modules\aurelia-dependency-injection\dist\commonjs\aurelia-dependency-injection.js:493:47)
    at C:\source\node_apps\hello_world\node_modules\aurelia-dependency-injection\dist\commonjs\aurelia-dependency-injection.js:386:68
    at Array.map (<anonymous>)
    at Object.invoke (C:\source\node_apps\hello_world\node_modules\aurelia-dependency-injection\dist\commonjs\aurelia-dependency-injection.js:386:30)
End Inner Error Stack
------------------------------------------------

    at new AggregateError (C:\source\node_apps\hello_world\node_modules\e[4maurelia-pale[24m\dist\commonjs\aurelia-pal.js:37:11)
    at Container.invoke (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:549:19)
    at StrategyResolver.get (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:104:39)
    at Container.get (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:493:47)
    at C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:386:68
    at Array.map (<anonymous>)
    at Object.invoke (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:386:30)
    at InvocationHandler.invoke (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:360:28)
    at Container.invoke (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:546:28)
    at StrategyResolver.get (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:104:39) {
  innerError: TypeError: _aureliaPal.DOM.createElement is not a function
      at createElement (C:\source\node_apps\hello_world\node_modules\e[4mcustom-controlse[24m\node_modules\e[4maurelia-bindinge[24m\dist\commonjs\aurelia-binding.js:4722:31)
      at new SVGAnalyzer (C:\source\node_apps\hello_world\node_modules\e[4mcustom-controlse[24m\node_modules\e[4maurelia-bindinge[24m\dist\commonjs\aurelia-binding.js:4731:11)
      at Object.invoke (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:387:24)
      at InvocationHandler.invoke (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:360:28)
      at Container.invoke (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:546:28)
      at StrategyResolver.get (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:104:39)
      at Container.get (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:493:47)
      at C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:386:68
      at Array.map (<anonymous>)
      at Object.invoke (C:\source\node_apps\hello_world\node_modules\e[4maurelia-dependency-injectione[24m\dist\commonjs\aurelia-dependency-injection.js:386:30)
}
1 Like

I got it working here https://codesandbox.io/s/competent-maxwell-k66f7

Can you help enhance it to illustrate where the issue(s) is(are)?

I have to head to work, but that portion works. Thanks

the controlfactory wrapper is the simple entry point into the aurelia end. ControlFactory is where the complexity is and that has BindingEngine as one of the construction depenedencies. As I said above. I can load my ControlFactory as long as I don’t inject BindingEngine. Unfortunately I rely heavily on binding engine

1 Like

I tried to add binding engine and a simple example here https://codesandbox.io/s/competent-maxwell-k66f7

Thanks, I’ll modify your sandbox later to reflect my application more closely. I’m not running in a web server, but I doubt that has anything to do with it. I’ll make a shell of my controlFactory class with just the dependencies (they are mostly aurelia modules)

1 Like

I didn’t commit/push the work I was doing this morning, but I know my controlfactory class takes in

EventAggregator, TaskQueue, ValidationControllerFactory, BindingEngine, and one of my own classes which has no dependencies of its own and no constructor so nothing should be strange. Binding Engine seems to be the only issue just due to trial and error of removing the dep and running

1 Like

I’m battling not having the convenience of typescript here :slight_smile:

2 Likes

We need a little reminder of how things used to be sometimes

2 Likes

I struggled to make progress on making it NOT work with your sample so I created a sample project where it’s broke. BindingEngine is the problem on the wrapper class. If I can’t get this to work with as a nodejs run, I’m going to have to rebuild what I’m trying to wrap without bindingEngine.

just compile the typescript and run: node scripts/app.js

1 Like

You are injecting binding engine too early, before initializing the platform abstraction code. So if you move initialize call out of the constructor, it will work

1 Like

Thanks,

I’m still having issues with my actual class. I’m getting

    Reflect.defineMetadata(metadataKey, metadataValue, target, targetKey);
            ^

TypeError: Reflect.defineMetadata is not a function
    at Object.define (C:\source\node_apps\hello_world\node_modules\e[4mcustom-controlse[24m\node_modules\e[4maurelia-metadatae[24m\dist\commonjs\aurelia-metadata.js:44:13)
    at C:\source\node_apps\hello_world\node_modules\e[4mcustom-controlse[24m\node_modules\e[4maurelia-bindinge[24m\dist\commonjs\aurelia-binding.js:5231:33
    at __decorate (C:\source\node_apps\hello_world\node_modules\e[4mcustom-controlse[24m\node_modules\e[4maurelia-validatione[24m\dist\commonjs\aurelia-validation.js:150:95)
    at C:\source\node_apps\hello_world\node_modules\e[4mcustom-controlse[24m\node_modules\e[4maurelia-validatione[24m\dist\commonjs\aurelia-validation.js:748:31
    at Object.<anonymous> (C:\source\node_apps\hello_world\node_modules\e[4mcustom-controlse[24m\node_modules\e[4maurelia-validatione[24m\dist\commonjs\aurelia-validation.js:752:2)
e[90m    at Module._compile (internal/modules/cjs/loader.js:955:30)e[39m
e[90m    at Object.Module._extensions..js (internal/modules/cjs/loader.js:991:10)e[39m
e[90m    at Module.load (internal/modules/cjs/loader.js:811:32)e[39m
e[90m    at Function.Module._load (internal/modules/cjs/loader.js:723:14)e[39m
e[90m    at Module.require (internal/modules/cjs/loader.js:848:19)e[39m
1 Like

Then i guess the polyfill code is required too late. If needed, just import reflect metadata independently before that module

2 Likes

I’ll try that later today. Thanks for all the help. Sadly what I’m trying to do with NodeJs has been deprecated by Microsoft but as long as the package is still available I see no reason not to use it. I have a lot of custom logic that builds forms built by 3rd parties. I don’t want to maintain a .net version and an aurelia version. Right now we are relying on client side work only, but having this run on the server would be very useful. Worst case scenario I’d have to write my own wrapper class around a node call

1 Like

I’m still having issues. What I’m currently doing in my spare time is starting version 2 of this project that I’m trying to consume. I’ll create the skeleton that causes my issue . I"m fairly close to having that, but I don’t get much free time.

1 Like

Update: Created new topic at Aurelia-validation plugin in NodeJs

It’s been a little while since I worked on this. Practically a year ago. I’m finally revisiting this and I made progress but I’m now getting an error due to the way I’m trying to share code between the web and the server. I’m getting the friendly message ’ Did you forget to add “.plugin(‘aurelia-validation’)” to your main.js?’ How can I make that work in a node project? My code is actually running correctly up to this point if I pass in something that does not require validation.

(node:18088) UnhandledPromiseRejectionWarning: Error: Did you forget to add ".plugin('aurelia-validation')" to your main.js?
    at FluentEnsure.assertInitialized (C:\source\control_set\node_modules\aurelia-validation\dist\commonjs\aurelia-validation.js:1779:15)
    at FluentEnsure.ensure (C:\source\control_set\node_modules\aurelia-validation\dist\commonjs\aurelia-validation.js:1744:14)
    at Function.ValidationRules.ensure (C:\source\control_set\node_modules\aurelia-validation\dist\commonjs\aurelia-validation.js:1812:58)

My rules are defined as such

            ValidationRules.ensure((c: StringControlConfiguration) => c.value)
                .required()
                .when(() => control.validation.required && control.canValidate)
                .withMessage(`${control.label || control.placeholder} is required`)
                .satisfies((value: string) => {
                    return value !== null ? value.indexOf(control.promptChar) === -1 : true;
                })
                .when(() => control.mask !== null && control.promptChar !== null && control.canValidate)
                .withMessage(`${control.label || control.placeholder} does not meet the format: ${control.mask}`)
                .matches(control.validation.regEx)
                .when(() => control.validation.regEx !== null && control.canValidate)
                .withMessage(`${control.label || control.placeholder} is invalid (${control.validation.regEx})`)
                .satisfies(control.isValidRegEx)
                .when(() => control.inputType === 'regularExpression' && control.canValidate)
                .withMessage(`${control.label || control.placeholder} is not a valid regular expression`)
                .maxLength(control.validation.maxLength)
                .when(() => control.validation.maxLength !== null && control.canValidate)
                .withMessage(
                    `${control.label || control.placeholder} must be less than ${
                        control.validation.maxLength
                    } characters`
                )
                .minLength(control.validation.minLength)
                .when(() => control.validation.minLength !== null && control.canValidate)
                .withMessage(
                    `${control.label || control.placeholder} must be greater than ${
                        control.validation.minLength
                    } characters`
                ).satisfies((value: string) => {
                    return value !==null ? !control.validation.restrictedValues.some((x) => x.toLowerCase() === value.toLowerCase()): true
                })
                .when(() => control.validation.restrictedValues !== null)
                .withMessage(`${control.label || control.placeholder || "Input"} cannot contain the current value`)
                .on(control);
1 Like

I may have solved the problem but I need to further test to make sure nothing weird is happening. If I pass the ValidationRules class to my existing code and set that as a property instead of relying on it being static, things seem to be working.

1 Like