3

I am trying to build a generic repository using:

  • Typescript
  • ES6
  • Angular 1.x

But I can't figure out how I should inject the Entity and then get its module name.

The reason why i want to get the name: Is because i follow a naming convention where a file called order-count.ts should render the URL '/order/count'

Is this solvable with Typescript/Javascript?

Here is what i have:

order-module.ts

import {App} from '../../App';
import {OrderService} from './order-service';

const module: ng.IModule = App.module('app.order', []);

module.service('orderService', OrderService);

order-service.ts

import {CrudService} from '../../shared/services/crud-service'
import {OrderCount} from '../order/entities/order-count';

export class OrderService {
    // @ngInject
    constructor(private crudService: CrudService<OrderCount>) {
        this.crudService = crudService;
    }

    getOrders() {
        var promise = this.crudService.getAll();

        promise.then(response => {
            console.log(response, 'success');
        }, error => {
            console.log(error, 'failed');
        });
    }
}

order-count.ts

import {Entity} from '../../../shared/models/entity';

export class OrderCount extends Entity {
    storeId: string;
    storeName: string;
}

entity.ts

export interface IEntity {
    id: number;
}

entity.ts

import {IEntity} from '../../module/contracts/entities/entity';

export class Entity implements IEntity {
    new() { }
    id: number;
}

crud-service.ts

'use strict';
import { Entity } from '../models/entity';
import { EndpointService } from './endpointService';

export class CrudService<TEntity extends Entity> {
    private baseCallPath: string;
    private entity: { new (): Entity };

    // @ngInject
    constructor(private endpointService: EndpointService, private $http: ng.IHttpService) {
        this.baseCallPath = new this.entity().constructor.name.replace('-', '/');
    }

    getAll(): ng.IHttpPromise<any> {
        return this.handleResponse(
            this.$http.get(this.endpointService.getUrl(this.baseCallPath)),
            'getAll'
        );
    }

    handleResponse(promise: ng.IHttpPromise<any>, callerMethodName: string): ng.IHttpPromise<any> {
        return promise.success((data: any) => {
            Array.prototype.push.apply(this.baseCallPath, data);
        }).error((reason: any) => {
            console.log(this.baseCallPath + callerMethodName, 'ERROR', reason);
        });
    }
}

endpoint-service.ts

export class EndpointService {
    private baseUri: string = 'http://localhost:3000/api/';

    getUrl(moduleName: string): string {
        return this.baseUri + moduleName;
    }
}
  • Entity is not defined as Angular service, this means that it can't be injected via Angular DI. It is not clear what 'ES6 module name' may refer to, but if you want to figure out ''../../../shared/models/entity' string in the app, then no, it is not possible. – Estus Flask Feb 16 '16 at 17:24
  • @estus I know that i didn't define the Entity as a Angular service. The problem is that I will have multiple classes that extends the Entity class. So can this be solved without inject using angular? Well about the ES6 module name, that's what i meant but as you say, I think it may be impossible. Is there any chance that i can use the Class name instead? Will be able to parse that to to a URL. –  Feb 16 '16 at 19:11

2 Answers2

1

This link may be helpful in order to implement a generic repository with Typescript

Community
  • 1
  • 1
aog
  • 444
  • 3
  • 14
0

Regarding the usage of class name as a value you may check this relevant question.

The good thing it can be retrieved and used as Foo.name or this.constructor.name. The bad thing is that it isn't available in every browser and should be polyfilled. Another bad thing is that minified function won't save its original name.

Wouldn't it be great to annotate function with Foo.name = 'Foo' on its definition and stick to pre-made property? Not really. Function.name is originally non-configurable, so it is read-only in a plethora of browsers.

If you don't plan to avoid minimization at all, or you're not too fond of configuring minifier to preserve class names (a solution faulty by design), don't use Function.name for anything like that.

The typical case for extendable ES6/TS class in Angular is

export class Foo {
  static _name = 'Foo';
}

export default angular.module('app.foo', [])
  .factory('Foo', Foo)
  // if DRY is a must,
  // .factory(Foo._name, Foo)
  .name;

import { Foo } from './foo';

export class Bar extends Foo {
  static _name = 'Bar';
}

export default angular.module('app.bar', []).factory('Bar', Bar).name;

import moduleFoo from './foo';
import moduleBar from './bar';

angular.module('app', [moduleFoo, moduleBar]);

So exports for Angular modules and classes should go hand in hand, they are not interchangeable.

Community
  • 1
  • 1
Estus Flask
  • 150,909
  • 47
  • 291
  • 441