Skip to content
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

feature request: Advice on using factory pattern in services #143

Open
sobafuchs opened this issue Dec 9, 2016 · 0 comments
Open

feature request: Advice on using factory pattern in services #143

sobafuchs opened this issue Dec 9, 2016 · 0 comments

Comments

@sobafuchs
Copy link

sobafuchs commented Dec 9, 2016

So it seems that the factory pattern isn't used much in Angular 2, and this styleguide advises against using .factory() to create dependencies. There seems to be little info here (and elsewhere) on how to create transient dependencies (dependencies that don't share state between components, which is effectively what factories are).

The example in the styleguide gives little explanation on what to do to recreate the factory pattern when migrating to Angular 2 and only pertains to stateFUL components. But if we want to use the factory pattern to create stateLESS services in a way that makes migration to Angular 2 easy, there's not much advice out there.

A great use case would be a TabulationService that maintains the state of which tab a user is viewing on a dashboard. This state shouldn't be shared between that component and any other component (although the service itself could be used in any component).

Using .service() is disadvantageous here because you have to manually clear the state of your service with the $onDestroy() lifecycle hook (or `$scope.$on('$destroy, () => ...) if you're using < ng 1.5). But this is the only feasible way to create a stateless component with access to Dependency Injection. Otherwise, you would have to create your class this way (and this way loses DI functionality):

tab-manager.service.ts:

import { TabManager } from './tab-manager.class';

export class TabService {
  manager;

  public initialize(tabs: string[], defaultTab: string) {
    return new TabManager(tabs, defaultTab);
  }
}

tab-manager.class.ts:

import { includes } from 'lodash';

const mandatory = (param) => { throw new Error(`${ param } is a required field in Tab Manager!`) };
export class TabManager {
  tab: string;

  constructor(public tabs: string[] = mandatory(`tabs`), public defaultTab: string = mandatory('defaultTab')) { 
    this.checkTab(defaultTab);
    this.tab = defaultTab;
  }

  public switchTab(tab) {
    const self = this;

    self.checkTab(tab);
    self.tab = tab;
  }

  private checkTab(tab: string) {
    const self = this;
    if (!includes(self.tabs, tab)) {
      throw new Error(`{ tab } is not a valid tab. Available tabs are ${ self.tabs.join(',') }`);
    }
  }
}

This way has the advantage of not requiring the user to manually clear the state (because this service is effectively a factory because it calls new on a Constructor function). But, this service is more difficult to use than the service created by the first method because you cannot inject dependencies into the constructor function that the service calls from tab-manager.class.ts, unless you pass them to the constructor like regular function parameters instead of dependencies. And DI is so great precisely because you don't have to do that.

In Angular 2, you can pass a service to a component's providers array and it will know to reinstantiate the service for that component, but that option doesn't exist in Angular 1.5.8, so I'm curious how you would advise using the factory pattern in Angular 1 to recreate that functionality?

If that's not possible, is it only possible to create the factory pattern functionality WITHOUT es2015 classes? What's the best way to garner typescript's type hinting advantages with the factory pattern (since most of its benefits seem to come from using classes)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant