Angular2 and TypeScript enums - dos and don'ts - enums

I have a bunch of enums in my Angular2 app and for each enum I've created a corresponding utils class that provides some additional functionality. This simply goes around the TypeScript limitation that I can't add functions to an enum the same way I can do it in Java.
Here's an example of my country enum and the corresponding utils class:
import {Injectable} from "#angular/core";
export enum Country {
ANDORRA = <any>"ANDORRA",
UNITED_ARAB_EMIRATES = <any>"UNITED_ARAB_EMIRATES",
AFGHANISTAN = <any>"AFGHANISTAN",
// ...
// more countries skipped for brevity
// ...
ZAMBIA = <any>"ZAMBIA",
ZIMBABWE = <any>"ZIMBABWE"
}
#Injectable()
export class CountryUtils {
private _emptyEntry: Array<string> = ["", "", ""];
private countryData: any = {
ANDORRA: ["Andorra", "AD", "AND"],
UNITED_ARAB_EMIRATES: ["United Arab Emirates", "AE", "ARE"],
AFGHANISTAN: ["Afghanistan", "AF", "AFG"],
// ...
// more countries skipped for brevity
// ...
ZAMBIA: ["Zambia", "ZM", "ZMB"],
ZIMBABWE: ["Zimbabwe", "ZW", "ZWE"]
}
getData(country: Country): any {
if (!country) {
return this._emptyEntry;
}
return this.countryData[Country[country]];
}
getName(country: Country): any {
return this.getData(country)[0];
}
getCode2(country: Country): any {
return this.getData(country)[1];
}
getCode3(country: Country): any {
return this.getData(country)[2];
}
}
Now, as you can see I've marked the utils class as Injectable so that I can use it with DI where I need it.
The problem I'm facing is that these enums are also used in my core TS/JS model classes that are not Angular2 dependent so I can't use DI to inject an instance of my utils classes (like the one above) inside the core model classes.
The only work around that I see is to drop the Injectable() approach and to mark the methods in the utils classes as static. So this way I can just import each utils class together with the enum and use it anywhere I want.
My question is, how bad of a design decision would that be? Is it acceptable to do something like this in Angular2 or is using statics a complete no-no? I can't see anything particularly harmful other that it's like an eye sore compared to the regular DI approach.
Any advice would be very much appreciated. Thanks in advance!

I don't see a static class as a problem. Also, you can use Declaration Merging to add your util functionality to your enum. No need of extra class. Check below.
enum Country {
ANDORRA = <any>"ANDORRA",
UNITED_ARAB_EMIRATES = <any>"UNITED_ARAB_EMIRATES",
AFGHANISTAN = <any>"AFGHANISTAN",
// ...
// more countries skipped for brevity
// ...
ZAMBIA = <any>"ZAMBIA",
ZIMBABWE = <any>"ZIMBABWE"
}
namespace Country {
const _emptyEntry: Array<string> = ["", "", ""];
const countryData: any = {
ANDORRA: ["Andorra", "AD", "AND"],
UNITED_ARAB_EMIRATES: ["United Arab Emirates", "AE", "ARE"],
AFGHANISTAN: ["Afghanistan", "AF", "AFG"],
// ...
// more countries skipped for brevity
// ...
ZAMBIA: ["Zambia", "ZM", "ZMB"],
ZIMBABWE: ["Zimbabwe", "ZW", "ZWE"]
};
export function getData(country: Country): any {
if (!country) {
return this._emptyEntry;
}
return this.countryData[Country[country]];
}
export function getName(country: Country): any {
return this.getData(country)[0];
}
export function getCode2(country: Country): any {
return this.getData(country)[1];
}
export function getCode3(country: Country): any {
return this.getData(country)[2];
}
}
Country.getCode2(Country.AFGHANISTAN);

Related

How to create custom floating filter component in ag-grid that uses "inRange" filter type

I'm trying to build a custom filter component that takes a range from a text input control (e.g. '3-5') to filter the data. To do so I have modified the example given in the ag-grid documentation (see code below).
When changing the type in onFloatingFilterChanged() to 'equals', 'greaterThan', 'lessThan' etc. everything works fine. But with type 'inRange' no filtering is performed.
Working example can be found on Plunkr: https://plnkr.co/edit/oHWFIaHgWIDXP0P5
import { Component } from '#angular/core';
import {
IFloatingFilter,
IFloatingFilterParams,
NumberFilter,
NumberFilterModel,
} from '#ag-grid-community/all-modules';
import { AgFrameworkComponent } from '#ag-grid-community/angular';
export interface RangeFloatingFilterParams extends IFloatingFilterParams {
value: number;
}
#Component({
template: `
<input
type="text"
[(ngModel)]="currentValue"
(ngModelChange)="valueChanged()"
style="width: 70px;"
/>
`,
})
export class RangeFloatingFilter
implements IFloatingFilter, AgFrameworkComponent<RangeFloatingFilterParams> {
private params: RangeFloatingFilterParams;
public currentValue: string;
agInit(params: RangeFloatingFilterParams): void {
this.params = params;
this.currentValue = '';
}
valueChanged() {
let valueToUse = this.currentValue === 0 ? null : this.currentValue;
this.params.parentFilterInstance(function(instance) {
(<NumberFilter>instance).onFloatingFilterChanged(
'inRange',
valueToUse
);
});
}
onParentModelChanged(parentModel: NumberFilterModel): void {
if (!parentModel) {
this.currentValue = 0;
} else {
// note that the filter could be anything here, but our purposes we're assuming a greater than filter only,
// so just read off the value and use that
this.currentValue = parentModel.filter;
}
}
}
Faced the same issue with custom floating datepicker. I used setModelIntoUi method instead of onFloatingFilterChanged:
instance.setModelIntoUi({
type: 'inRange',
dateFrom: moment(value.min).format('YYYY-MM-DD'), // you have to use exactly this date format in order for it to work
dateTo: moment(value.max).format('YYYY-MM-DD'),
});
And in your case with numbers it'll be:
instance.setModelIntoUi({
type: 'inRange',
filter: value.min,
filterTo: value.max,
});
UPD: Added this line
instance.onUiChanged(true);
after the setModelIntoUi method, because of the bug: filter model wasn't updating on second use.
The code inside instance.onFloatingFilterChanged() only sets the first from value.
Use these lines below to get the correct result, as it is the only way to get inRange working.
instance.setTypeFromFloatingFilter('inRange');
instance.eValueFrom1.setValue(this._input1.value);
instance.eValueTo1.setValue(this._input2.value);
instance.onUiChanged(true);

Hapi Fhir DomainResource, What URL do you use?

http://hapifhir.io/doc_custom_structures.html
this article discusses a DomainResource.
There are situations however when you might want to create an entirely
custom resource type. This feature should be used only if there is no
other option, since it means you are creating a resource type that
will not be interoperable with other FHIR implementations.
I've implemented the code verbatum. (I show the classes below (with no "guts" just for brevity) (full code at the url))
/**
* This is an example of a custom resource that also uses a custom
* datatype.
*
* Note that we are extensing DomainResource for an STU3
* resource. For DSTU2 it would be BaseResource.
*/
#ResourceDef(name = "CustomResource", profile = "http://hl7.org/fhir/profiles/custom-resource")
public class CustomResource extends DomainResource {
}
and
/**
* This is an example of a custom datatype.
*
* This is an STU3 example so it extends Type and implements ICompositeType. For
* DSTU2 it would extend BaseIdentifiableElement and implement ICompositeDatatype.
*/
#DatatypeDef(name="CustomDatatype")
public class CustomDatatype extends Type implements ICompositeType {
}
And I've "registered it" in my code base:
if (null != this.fhirContext)
{
this.fhirContext.registerCustomType(CustomResource.class);
this.fhirContext.registerCustomType(CustomDatatype.class);
}
(~trying to follow the instructions from the URL above)
// Create a context. Note that we declare the custom types we'll be using
// on the context before actually using them
FhirContext ctx = FhirContext.forDstu3();
ctx.registerCustomType(CustomResource.class);
ctx.registerCustomType(CustomDatatype.class);
// Now let's create an instance of our custom resource type
// and populate it with some data
CustomResource res = new CustomResource();
// Add some values, including our custom datatype
DateType value0 = new DateType("2015-01-01");
res.getTelevision().add(value0);
CustomDatatype value1 = new CustomDatatype();
value1.setDate(new DateTimeType(new Date()));
value1.setKittens(new StringType("FOO"));
res.getTelevision().add(value1);
res.setDogs(new StringType("Some Dogs"));
// Now let's serialize our instance
String output = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res);
System.out.println(output);
But that looks like a console-app usage of two objects...not how to wire it into the fhir-server.
I've been trying for 3 hours now to figure out what URL to use.
some things I've tried:
http://127.0.0.1:8080/fhir/CustomResource
http://127.0.0.1:8080/fhir/profiles/custom-resource
http://127.0.0.1:8080/fhir/custom-resource
to no avail...
What is the URL?
And how do I populate the values for it?
Ok.
So the CustomResource still needs its own IResourceProvider. (thanks to daniels in the comments of the original question)
Here is a basic working example.
You'll do everything I listed in the original question AND you'll make and register an IResourceProvider for the new customresource.
new IResourceProvider
package mystuff.resourceproviders;
import org.hl7.fhir.dstu3.model.DateType;
import org.hl7.fhir.dstu3.model.IdType;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.server.IResourceProvider;
import mystuff.CustomDatatype;
import mystuff.CustomResource;
import org.hl7.fhir.dstu3.model.DateTimeType;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.util.Date;
public class CustomResourceProvider implements IResourceProvider {
#Override
public Class<? extends IBaseResource> getResourceType() {
return CustomResource.class;
}
/* the IdType (datatype) will be different based on STU2 or STU3. STU3 version below */
#Read()
public CustomResource getResourceById(#IdParam IdType theId) {
// Now let's create an instance of our custom resource type
// and populate it with some data
CustomResource res = new CustomResource();
res.setId(theId);
// Add some values, including our custom datatype
DateType value0 = new DateType("2015-01-01");
res.getTelevision().add(value0);
CustomDatatype value1 = new CustomDatatype();
value1.setDate(new DateTimeType(new Date()));
value1.setKittens(new StringType("FOO"));
res.getTelevision().add(value1);
res.setDogs(new StringType("Some Dogs"));
return res;
}
}
then you'll register this (as documented here):
http://hapifhir.io/doc_rest_server.html#_toc_create_a_server
instead of this:
#Override
protected void initialize() throws ServletException {
/*
* The servlet defines any number of resource providers, and
* configures itself to use them by calling
* setResourceProviders()
*/
List<IResourceProvider> resourceProviders = new ArrayList<IResourceProvider>();
resourceProviders.add(new RestfulPatientResourceProvider());
resourceProviders.add(new RestfulObservationResourceProvider());
setResourceProviders(resourceProviders);
}
you'll have something like this
#Override
protected void initialize() throws ServletException {
/*
* The servlet defines any number of resource providers, and
* configures itself to use them by calling
* setResourceProviders()
*/
List<IResourceProvider> resourceProviders = new ArrayList<IResourceProvider>();
resourceProviders.add(new CustomResourceProvider());
setResourceProviders(resourceProviders);
}
URL for testing this (most probable local development url that is)
http://127.0.0.1:8080/fhir/CustomResource/12345
and you'll get back this JSON response.
{
"resourceType": "CustomResource",
"id": "12345",
"meta": {
"profile": [
"http://hl7.org/fhir/profiles/custom-resource"
]
},
"televisionDate": [
"2015-01-01"
],
"televisionCustomDatatype": [
{
"date": "2019-01-14T11:49:44-05:00",
"kittens": "FOO"
}
],
"dogs": "Some Dogs"
}

Ajax call in MobX: MobX observer: Store is not available! Make sure it is provided by some Provider

I'm migrating from a traditional React application with the tree-structure to a state management structure with MobX.
Currently, my individual components propagate down data from an Ajax call made by the parent/grandparent, which works fine.
Now I wish to change this so that I don't work in the tree structure anymore due to the change of complexity and dependency of parallel grandchildren/children.
Say I do an axios.get in componentDidMount of a <Parent1/> React class. How do I then access the data using MobX?
What I've tried so far:
Creating a store.jsx that looks as such:
import { observable } from 'mobx';
const axios = require('axios');
class Store {
#observable parentdata;
loadParent = () => {
let that = this;
axios.get("/api/parent").then(function(response){
that.parentdata = response.parentdata;
}).catch(function(error){
// Error handling
})
};
}
export default Store;
My ReactDOM is rendered in container.jsx which contains all parents, meaning also <Parent1/>. In container.jsx we do the following:
import { Provider } from 'mobx-react';
import Store from './store/store.jsx';
let store = new Store();
and
ReactDOM.render(
<Provider store={store}>
<Main />
</Provider>,
document.getElementById('content')
);
.. in the end.
In the render method of container.jsx I don't do anything with <Parent1/> - it simply renders the component as normal(that's the idea here, right?)
In parent1.jsx, I remove the previous axios.get and add these:
import { inject, observer } from 'mobx-react';
#inject('store') #observer
export default class Parent1 extends React.Component {
// .....
componentDidMount () {
this.props.store.loadParent();
After that, the error is provided: MobX observer: Store 'parentdata' is not available! Make sure it is provided by some Provider
Where did I go wrong in binding the data here?
Edit: Removing #inject and only having #observer results in: TypeError: Cannot read property 'loadParent' of undefined
Few things to address:
Assuming you named your parentData store 'store' and not 'Store' like the classname, the Provider looks like it's configured correctly
Here's how I'd change the store itself:
import { observable } from 'mobx';
const axios = require('axios');
class Store {
#observable parentdata;
loadParent = () => {
// There's no need to clone this if you're using arrow functions
axios.get("/api/parent").then((response) => {
this.parentdata = response.parentdata;
}).catch(function(error){
// Error handling
})
};
}
export default Store;
In the component, I might do this:
import { inject, observer } from 'mobx-react';
#inject('store') #observer
export default class Parent1 extends React.Component {
// ... //
componentDidMount () {
this.props.store.loadParent();
}
render() {
if (!this.props.store.parentData) { return (<div>Loading...</div>) }
const { parentData } = this.props.store
return (<pre>{JSON.stringify(parentData, null, 4)}</pre>)
}
}
My suspicion is that your store is case sensitive and mistakenly named.
A nifty tricks to debugging could be to console.log important variables or attach them to a window object to test.
eg:
class Parent1 {
componentDidMount() {
window.Parent1 = this
window.Parent1Props = this.props
window.Store = this.props.store // or `this.props.Store` check case sensitivity!
}
// Open browser console and try to access your now global variables

Aurelia - injecting a service, but its properties remaining undefined

I have a service:
import {eventsData} from 'services/eventsData';
import {singleton} from 'aurelia-framework';
#singleton()
export class DataRepository{
constructor(){
}
getEvents(){
var promise = new Promise((resolve,reject)=>{
if(!this.events){
setTimeout(_=>{
this.events = eventsData;
resolve(this.events);
},2000)
}
else{
resolve(this.events);
}
});
return promise;
}
getEvent(eventId){
return this.events.find(event => event.id == eventId);
}
}
which I am initiating as is in:
import {inject} from 'aurelia-framework';
import {DataRepository} from 'services/datarepository';
#inject(DataRepository)
export class events{
constructor(dataRepository, lazyOfImLazy){
dataRepository.getEvents().then(events => this.events = events);
}
createAndUseLazy(){
console.log("About to use lazy");
this.lazyOfImLazy().doStuff();
}
}
And then in :
import {inject} from 'aurelia-framework';
import{DataRepository} from 'services/dataRepository';
#inject(DataRepository)
export class EventDetail{
constructor(dataRepository){
this.dataRepository = dataRepository;
}
activate(params, routeConfig){
console.log(params.eventId);
console.log(this.dataRepository);
this.event = this.dataRepository.getEvent(1);
}
}
But when calling this.dataRepository.getEvent(1), then in dataRepository return this.events.find(event => event.id == eventId);, the this.events is undefined. I would have thought that by defining it as a singleton it would preserve this.events, when being instantiated in the promise. And the this.events is then populated properly. The view of events is using it.
Am I missing something?
Figured it out: The imports are case sensitive.
import{DataRepository} from 'services/datarepository'; and import{DataRepository} from 'services/dataRepository'; notice the lower cased r in datarepository in the first line and the capital one in dataRepository in the second.
It creates two different instances of the same service, due to the different case sensitivity in the string after from.
For those who ever encounter this, and spent hours trying to figure it out :)

Does Dart support enumerations?

Does Dart support enumerations? For instance:
enum myFruitEnum { Apple, Banana }
A cursory search of the docs suggests no.
Beginning 1.8, you can use enums like this:
enum Fruit {
apple, banana
}
main() {
var a = Fruit.apple;
switch (a) {
case Fruit.apple:
print('it is an apple');
break;
}
// get all the values of the enums
for (List<Fruit> value in Fruit.values) {
print(value);
}
// get the second value
print(Fruit.values[1]);
}
The old approach before 1.8:
class Fruit {
static const APPLE = const Fruit._(0);
static const BANANA = const Fruit._(1);
static get values => [APPLE, BANANA];
final int value;
const Fruit._(this.value);
}
Those static constants within the class are compile time constants, and this class can now be used in, for example, switch statements:
var a = Fruit.APPLE;
switch (a) {
case Fruit.APPLE:
print('Yes!');
break;
}
With r41815 Dart got native Enum support see http://dartbug.com/21416 and can be used like
enum Status {
none,
running,
stopped,
paused
}
void main() {
print(Status.values);
Status.values.forEach((v) => print('value: $v, index: ${v.index}'));
print('running: ${Status.running}, ${Status.running.index}');
print('running index: ${Status.values[1]}');
}
[Status.none, Status.running, Status.stopped, Status.paused]
value: Status.none, index: 0
value: Status.running, index: 1
value: Status.stopped, index: 2
value: Status.paused, index: 3
running: Status.running, 1
running index: Status.running
A limitation is that it is not possibly to set custom values for an enum item, they are automatically numbered.
More details at in this draft https://www.dartlang.org/docs/spec/EnumsTC52draft.pdf
Enumeration should be available in the future. But until Enum has landed you can do something like :
class Fruit {
static final APPLE = new Fruit._();
static final BANANA = new Fruit._();
static get values => [APPLE, BANANA];
Fruit._();
}
This and this may be the answers on your question:
... for the technology preview it was decided to leave it out and just
use static final fields for now. It may be added later.
You can still do something like this:
interface ConnectionState { }
class Connected implements ConnectionState { }
class Connecting implements ConnectionState { }
class Disconnected implements ConnectionState { }
//later
ConnectionState connectionState;
if (connectionState is Connecting) { ... }
wich is in my opinion more clear for use. It's a bit more difficult for programming the application structure, but in some cases, it's better and clear.
how about this approach:
class FruitEnums {
static const String Apple = "Apple";
static const String Banana = "Banana";
}
class EnumUsageExample {
void DoSomething(){
var fruit = FruitEnums.Apple;
String message;
switch(fruit){
case(FruitEnums.Apple):
message = "Now slicing $fruit.";
break;
default:
message = "Now slicing $fruit via default case.";
break;
}
}
}
Yes! Its actually very useful to do Enums in Dart:
enum fruits{
BANANA, APPLE, ORANGE
}
Just use Types Class File.
Dart-Types
easy, fast, more powerful and more helpful.
little problem, it is this class limited to five Different Choice and plus one for acts as null.
In case of anybody still searching for a quick solution for this.
We sometimes need integer value for an enum , sometimes string value. So we implement a quick package for this.
Enum Value Generator and an extension to easly generate necessary codes but this is not mandatory.vscode extension.
It is also capable of use with jsonAnnotation too.
import 'package:mobkit_generator/annotations.dart';
part 'example.g.dart'
#EnumSerializable(String)
enum PersonStr {
#EnumValue('John')
name,
#EnumValue('66')
number,
}
#EnumSerializable(int)
enum PersonInt {
#EnumValue(1)
name,
#EnumValue('66')
number,
}

Resources