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

TypeScript enums #88

Closed
RomkeVdMeulen opened this Issue Mar 29, 2016 · 8 comments

Comments

Projects
None yet
5 participants
@RomkeVdMeulen

RomkeVdMeulen commented Mar 29, 2016

I'm looking at using a TypeScript enum for error states, like this:

export enum ERRORS {
  INVALID
}

export class Mycomponent {
  public error = ERRORS.INVALID;
}

This compiles to something like:

define(["require", "exports"], function (require, exports) {
    "use strict";
    (function (ERRORS) {
        ERRORS[ERRORS["INVALID"] = 0] = "INVALID";
    })(exports.ERRORS || (exports.ERRORS = {}));
    var ERRORS = exports.ERRORS;
    var Mycomponent = (function () {
        function Mycomponent() {
            this.error = ERRORS.INVALID;
        }
        return Mycomponent;
    }());
    exports.Mycomponent = Mycomponent;
});

I tried simply doing <p if.bind="error = ERRORS.INVALID">Invalid!</p> but of course the enum isn't automatically available in the binding. Is there something I can do to make the enum available for comparisons?

@EisenbergEffect

This comment has been minimized.

Show comment
Hide comment
@EisenbergEffect

EisenbergEffect Mar 29, 2016

Member

There is, if you have the latest. We recently added a way to extend the binding context using view engine hooks. Here's an example that shows how to add an array of countries.

import {viewEngineHooks} from './view-engine-hooks';

let countries = [
  ...list of contries...
];

@viewEngineHooks()
export class CountryBinder {
  beforeBind(view) {
    view.overrideContext.countries = countries;
  }
}

This plugs into the beforeBind hook and adds the countries to the overrideContext of the view that this data is required into. To make this work, you also need to implement a resource decorator:

import {resource} from 'aurelia-framework';

export function viewEngineHooks() {
  return resource({
    initialize(container, target) {
      this.target = target;
    },
    load() {},
    register(registry, name) {
      registry.registerViewEngineHooks(new this.target());
    }
  });
}

We will have the viewEngineHooks decorator in the framework itself in a future release. For now, you can just add it to your project. Once this is in place, to use the countries, you simply require the countries module in your view:

<template>
  <require from="./data/countries"></require>

  <ul>
    <li repeat.for="country of countries">${country}</li>
  </ul>
</template>

For your scenario, you might want to create a single module that simply adds all your enums onto the overrideContext.

Member

EisenbergEffect commented Mar 29, 2016

There is, if you have the latest. We recently added a way to extend the binding context using view engine hooks. Here's an example that shows how to add an array of countries.

import {viewEngineHooks} from './view-engine-hooks';

let countries = [
  ...list of contries...
];

@viewEngineHooks()
export class CountryBinder {
  beforeBind(view) {
    view.overrideContext.countries = countries;
  }
}

This plugs into the beforeBind hook and adds the countries to the overrideContext of the view that this data is required into. To make this work, you also need to implement a resource decorator:

import {resource} from 'aurelia-framework';

export function viewEngineHooks() {
  return resource({
    initialize(container, target) {
      this.target = target;
    },
    load() {},
    register(registry, name) {
      registry.registerViewEngineHooks(new this.target());
    }
  });
}

We will have the viewEngineHooks decorator in the framework itself in a future release. For now, you can just add it to your project. Once this is in place, to use the countries, you simply require the countries module in your view:

<template>
  <require from="./data/countries"></require>

  <ul>
    <li repeat.for="country of countries">${country}</li>
  </ul>
</template>

For your scenario, you might want to create a single module that simply adds all your enums onto the overrideContext.

@davismj

This comment has been minimized.

Show comment
Hide comment
@davismj

davismj Jun 2, 2016

Member

Rather than creating our own decorator, is it possible to register ViewEngineHooks with a naming convention?

export class EnumViewEngineHooks {
  beforeBind(view) {
    view.overrideContext.countries = countries;
  }
}
Member

davismj commented Jun 2, 2016

Rather than creating our own decorator, is it possible to register ViewEngineHooks with a naming convention?

export class EnumViewEngineHooks {
  beforeBind(view) {
    view.overrideContext.countries = countries;
  }
}
@EisenbergEffect

This comment has been minimized.

Show comment
Hide comment
@EisenbergEffect

EisenbergEffect Jun 2, 2016

Member

Not currently...but if you want to submit a PR for that, it seems like a reasonable addition :)
Code would be added in the ModuleAnalyzer. You will see the other similar code there.

Member

EisenbergEffect commented Jun 2, 2016

Not currently...but if you want to submit a PR for that, it seems like a reasonable addition :)
Code would be added in the ModuleAnalyzer. You will see the other similar code there.

@davismj

This comment has been minimized.

Show comment
Hide comment
@davismj

davismj Jun 2, 2016

Member

That's a good idea, I'll look into that now.

Edit: Just needed to require it in the view.

However, I couldn't get the above code to work. Code for reference. Anything seem wrong here?

export enum ConnectorDirection {
    Input,
    Output,
    TwoWay
}

@viewEngineHooks()
export class ConnectorDirectionBinder {
    beforeBind(view) {
        view.overrideContext.ConnectorDirection = ConnectorDirection;
    }
}

export function viewEngineHooks() {
    return resource({
        initialize(container, target) {
            this.target = target;
        },
        load() { },
        register(registry, name) {
            registry.registerViewEngineHooks(new this.target());
        }
    });
}
Member

davismj commented Jun 2, 2016

That's a good idea, I'll look into that now.

Edit: Just needed to require it in the view.

However, I couldn't get the above code to work. Code for reference. Anything seem wrong here?

export enum ConnectorDirection {
    Input,
    Output,
    TwoWay
}

@viewEngineHooks()
export class ConnectorDirectionBinder {
    beforeBind(view) {
        view.overrideContext.ConnectorDirection = ConnectorDirection;
    }
}

export function viewEngineHooks() {
    return resource({
        initialize(container, target) {
            this.target = target;
        },
        load() { },
        register(registry, name) {
            registry.registerViewEngineHooks(new this.target());
        }
    });
}
@EisenbergEffect

This comment has been minimized.

Show comment
Hide comment
@EisenbergEffect

EisenbergEffect Jun 2, 2016

Member

My guess is that it has something to do with the way that TypeScript handles enums

Member

EisenbergEffect commented Jun 2, 2016

My guess is that it has something to do with the way that TypeScript handles enums

@davismj

This comment has been minimized.

Show comment
Hide comment
@davismj

davismj Jun 2, 2016

Member

Pending aurelia/binding#423, you can now achieve this behavior using either of the following:

import { ViewEngineHooks } from 'aurelia-framework';
import { viewEngineHooks } from 'aurelia-binding';

// by convention
export class CountryViewEngineHooks implements ViewEngineHooks {
  beforeBind(view) {
    view.overrideContext.countries = countries;
  }
}

// by decoration
@viewEngineHooks()
export class CountryBinder implements ViewEngineHooks {
  beforeBind(view) {
    view.overrideContext.countries = countries;
  }
}
Member

davismj commented Jun 2, 2016

Pending aurelia/binding#423, you can now achieve this behavior using either of the following:

import { ViewEngineHooks } from 'aurelia-framework';
import { viewEngineHooks } from 'aurelia-binding';

// by convention
export class CountryViewEngineHooks implements ViewEngineHooks {
  beforeBind(view) {
    view.overrideContext.countries = countries;
  }
}

// by decoration
@viewEngineHooks()
export class CountryBinder implements ViewEngineHooks {
  beforeBind(view) {
    view.overrideContext.countries = countries;
  }
}
@larvanitis

This comment has been minimized.

Show comment
Hide comment
@larvanitis

larvanitis May 12, 2017

Sorry for the necrobump of a closed issue but in case somebody else sees this, you can simply expose the enum from your view model like this:

In your ViewModel:

import {ERRORS} from 'some/module';
// or...
export enum ERRORS {
  INVALID
}

export class MyViewModel {
  private ERRORS = ERRORS;
  private error: ERRORS = ERRORS.INVALID;
  // ...
}

In your template:

<template>
    <p if.bind="error === ERRORS.INVALID">Invalid!</p>
    <!--The OP had an error in his example. Comparison requires `==` or `===`-->
</template>

larvanitis commented May 12, 2017

Sorry for the necrobump of a closed issue but in case somebody else sees this, you can simply expose the enum from your view model like this:

In your ViewModel:

import {ERRORS} from 'some/module';
// or...
export enum ERRORS {
  INVALID
}

export class MyViewModel {
  private ERRORS = ERRORS;
  private error: ERRORS = ERRORS.INVALID;
  // ...
}

In your template:

<template>
    <p if.bind="error === ERRORS.INVALID">Invalid!</p>
    <!--The OP had an error in his example. Comparison requires `==` or `===`-->
</template>
@niemyjski

This comment has been minimized.

Show comment
Hide comment
@niemyjski

niemyjski Jul 6, 2017

@larvanitis I tried this but couldn't get it to work and no errors are thrown.

niemyjski commented Jul 6, 2017

@larvanitis I tried this but couldn't get it to work and no errors are thrown.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment