2014-02-17 3 views
2

Я пытаюсь чисто написать Угловое расширение пользовательских $resource как завод как класс машинопись с использованием DefinatelyTyped (IResource, IResourceClass и друзей).

По Misko Hevery ресурсам просто constructor функции, поэтому я ожидал, чтобы быть в состоянии определить мой $resource как обычный класс с некоторыми типизированными интерфейсами (INamedEntityResource или INamedEntity) и подмешать определение сервиса, но я не могу показаться, чтобы получить стандартные методы на моем прототипе NamedEntityResource, чтобы закончить на заводских экземплярах.

Есть ли способ сделать это с помощью функции constructor() или я должен отказаться и просто определить службу в простом JavaScript?

declare module EntityTypes { 
    interface INamedEntity { } 
} 

module Services { 

    export interface INamedEntitySvc { 
     Name(params: {}, successCallback: (data: any, headers: any) => void, errorCallback: (data: any, headers: any) => void): EntityTypes.INamedEntity; 
     Clear(params: {}, value: EntityTypes.INamedEntity, successCallback: (data: any, headers: any) => void, errorCallback: (data: any, headers: any) => void): EntityTypes.INamedEntity; 
    } 

    // WILL have correct interface definition for the resource 
    export interface INamedEntityResource extends NamedEntityResource, INamedEntitySvc { } 

    export class NamedEntityResource { 

     // #1 DOESN'T WORK - These are on NamedEntityResource.prototype but don't end up on svc 
     public someMethod() { } 
     public someOtherMethod() { } 

     constructor($resource) { 
      var paramDefaults = { 
      }; 

      var svc: INamedEntitySvc = $resource(getUrl(), paramDefaults, { 
       Name: <any>{ method: "GET", params: { action: "Name" } }, 
       Clear: <any>{ method: "PATCH", params: { action: "Clear" }, headers: { 'Content-Type': 'application/json' } }, 
      }); 

      // THIS WORKS - but it's not a NamedEntityResource 
      svc["prototype"].someMethod = function() { } 
      svc["prototype"].someOtherMethod = function() { } 
      return <any>svc; 

      // #1 DOESN'T WORK THOUGH 
      return; // doesn't pick up methods on prototype 

      // #2 THIS DOESN'T WORK EITHER 
      NamedEntityResource["prototype"] = angular.extend(this["prototype"] || {}, svc["prototype"]); 
      return this; 
     } 
    } 

    // Registration 
    var servicesModule: ng.IModule = angular.module('npApp.services'); 
    servicesModule.factory('NamedEntityResource', NamedEntityResource); 
} 

Далее

Так Целью этого является, чтобы позволить мне написать класс ресурса {} с методами, которые будут аннотациями на каждом ресурсе загружаю через HTTP. В этом случае мои INamedEntity s.

Это самое близкое решение, которое я получил до сих пор, что, похоже, работает, но оно действительно неприятно.

module Services { 

    export interface INamedEntitySvc { 
     Name(params: {}, successCallback: (data: any, headers: any) => void, errorCallback: (data: any, headers: any) => void): EntityTypes.INamedEntity; 
     Clear(params: {}, value: EntityTypes.INamedEntity, successCallback: (data: any, headers: any) => void, errorCallback: (data: any, headers: any) => void): EntityTypes.INamedEntity; 
    } 

    // WILL have correct interface definition for the resource 
    export interface INamedEntityResource extends NamedEntityResource, INamedEntitySvc { } 

    export class NamedEntityResourceBase { 
     public someMethod() { } 
     public someOtherMethod() { } 
    } 

    // extend our resource implementation so that INamedEntityResource will have all the relevant intelisense 
    export class NamedEntityResource extends NamedEntityResourceBase { 

     constructor($resource) { 
      super(); // kind of superfluous since we're not actually using this instance but the compiler requires it 

      var svc: INamedEntitySvc = $resource(getUrl(), { }, { 
       Name: <any>{ method: "GET", params: { action: "Name" } }, 
       Clear: <any>{ method: "PATCH", params: { action: "Clear" }, headers: { 'Content-Type': 'application/json' } }, 
      }); 

      // Mixin svc definition to ourself - we have to use a hoisted base class because this.prototype isn't setup yet 
      angular.extend(svc["prototype"], NamedEntityResourceBase["prototype"]); 

      // Return Angular's service (NOT this instance) mixed in with the methods we want from the base class 
      return <any>svc; 
     } 

     thisWontWork() { 
      // since we never actually get a NamedEntityResource instance, this method cannot be applied to anything. 
      // any methods you want have to go in the base prototype 
     } 
    } 

    // Registration 
    var servicesModule: ng.IModule = angular.module('npApp.services'); 
    servicesModule.factory('NamedEntityResource', NamedEntityResource); 
} 

Трюк должен был;

  1. Поднять методы, которые я хочу на обслуживание, в базовый класс, потому что этот метод не инициализируется к тому моменту, когда вызывается моя функция constructor().
  2. svc, который является угловым сервисом от конструктора, который вы можете сделать в JavaScript, конечно, но это похоже на действительно грязную утиную печать в TypeScript.
  3. Чтобы получить методы в svc.prototype, я распространяю это непосредственно из моего базового класса. Это особенно неприятно, так как это означает создание прототипа каждый раз, когда создается экземпляр.
  4. Последним острым ароматом этого сэндвича sh ** я должен вызвать super() для конструктора для экземпляра, который я выбрасываю, чтобы заставить его скомпилировать.

Однако, в конце всего этого, я могу добавить методы к NamedEntityResourceBase, и они появятся в прототипе всех объектов, загруженных из моего HTTP-ресурса.

ответ

0

Регистрация классов с service вместо factory:

servicesModule.service('NamedEntityResource', NamedEntityResource); 

Отказ от ответственности: мое видео о дополнительной информации вы можете найти полезную о регистрации услуги в angularjs + машинопись: http://www.youtube.com/watch?v=Yis8m3BdnEM&hd=1

+0

Спасибо, но я не понимаю, как это помогает мне расширить ресурс $. У вас есть пример? – cirrus

0

вот как я делаю я используя здесь $ http

module portal{ 

    var app =angular.module('portal',[]); 
    app.service(services); 
} 

module portal.services { 


export class apiService { 


    public getData<T>(url?:string): ng.IPromise<T> { 

     var def = this.$q.defer(); 
     this.$http.get(this.config.apiBaseUrl + url).then((successResponse) => { 

      if(successResponse) 
       def.resolve(successResponse.data); 
      else 
       def.reject('server error'); 

     }, (errorRes) => { 

      def.reject(errorRes.statusText); 
     }); 

     return def.promise; 
    } 

    public postData<T>(formData: any, url?:string,contentType?:string): ng.IPromise<T>{ 

     var def = this.$q.defer(); 

     this.$http({ 
      url: this.config.apiBaseUrl + url, 
      method: 'POST', 
      data:formData, 
      withCredentials: true, 
      headers: { 
       'Content-Type':contentType || 'application/json' 
      } 
     }).then((successResponse)=>{ 
      def.resolve(successResponse.data); 
     },(errorRes)=>{ 
      def.reject(errorRes); 
     }); 

     return def.promise; 

    } 

    static $inject = ['$q','$http', 'config']; 

    constructor(public $q:ng.IQService,public $http:ng.IHttpService, public config:interfaces.IPortalConfig) { 


    } 

} 



} 
3

Я искал ответ на это некоторое время. И это было в документации по машинописному документу. Интерфейс может расширить класс.Решение добавления методов к экземпляру ресурса ниже:

class Project { 
    id: number; 
    title: string; 

    someMethod(): boolean { 
     return true; 
    } 
} 

export interface IProject extends ng.resource.IResource<IProject>, Project { 
    // here you add any method interface generated by the $resource 
    // $thumb(): angular.IPromise<IProject>; 
    // $thumb(params?: Object, success?: Function, error?: Function): angular.IPromise<IProject>; 
    // $thumb(success: Function, error?: Function): angular.IPromise<IProject>; 
} 

export interface IProjectResourceClass extends ng.resource.IResourceClass<IProject> { } 

function projectFactory($resource: ng.resource.IResourceService): IProjectResourceClass { 
    var Resource = $resource<IProject>('/api/projects/:id/', { id: '@id' }); 

    // the key, for this to actually work when compiled to javascript 
    angular.extend(Resource.prototype, Project.prototype); 
    return Resource; 
} 
module projectFactory { 
    export var $inject: string[] = ['$resource']; 
} 

я не полностью протестирован, но я испытал немного и работу.

+2

Способы экземпляра ресурса, такие как $ save, удаляются, если вы перезаписываете прототип. Вы можете исправить это, используя angular.extend (Resource.prototype, Project.prototype); вместо. – Micke

+0

Это потрясающе и работает для меня. Вы знаете, как это сделать для типа ошибки? В Typcript тип ошибки $ resource является 'angular.IHttpPromiseCallbackArg ', но я не уверен, где в 'IProject' (или в другом месте) мы будем делать эквивалентный' angular.extend() 'для добавления методов в $ тип ошибки ресурса. – rinogo

+0

Это добавляет дополнительные свойства к ресурсу 'instance'? Похоже, что свойства будут частью класса ресурсов ... Возможно, то же самое касается экземпляра ресурса. – Abdul23

Смежные вопросы