1

I have a class User that does not have any NG2 metadata, etc.. But I would like to have it access Http from "@angular/http". What is the best way to bring this class into the NG DI provider/injector system so that I can access Http?

I'm going for something like the following:

import {Http, Response} from "@angular/http"

export class User {
  constructor(private _email:string){}

  public reload(){
    this.http.get("http://www.example.com")
      .subscribe(...)
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Michael Pell
  • 1,416
  • 1
  • 14
  • 17
  • Looks like you need to rethink this design. It's hard to hard to help with that, as we don't have more context. Like where are you using this class? Where would it be called from. Can you show some example that will paint a more complete picture? – Paul Samsotha Dec 18 '16 at 16:10
  • @peeskillet, I want a User class that can represent a user in a SessionService. I want it to be responsible for exposing a `reload()` function that pings the DB for any underlying data changes. I am going to try a different route with a `UserService` that I believe will better conform to the intended patterns. – Michael Pell Dec 18 '16 at 16:17

2 Answers2

3

I don't think this is a good idea, but anyhow, see below an approach how it could be done:

Http has quite some dependencies, therefore the easiest way in my opinion is to create an injector with the providers specified in the HttpModule and then let the injector create an instance:

constructor() {   
  let injector = ReflectiveInjector.resolveAndCreate([
    {provide: Http, useFactory: httpFactory, deps: [XHRBackend, RequestOptions]},
    BrowserXhr,
    {provide: RequestOptions, useClass: BaseRequestOptions},
    {provide: ResponseOptions, useClass: BaseResponseOptions},
    XHRBackend,
    {provide: XSRFStrategy, useFactory: _createDefaultCookieXSRFStrategy},
  ]);
  this.http = injector.get(Http);
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    I don't think the creation of the injector should happen in the constructor; I'm also quite new to angular 2 but my understanding is that you're trying to replicate that module here. What if the module spec changes? Are you going to maintain this code? – Sebas Dec 18 '16 at 16:03
  • This seems like it would work, but I get the sense that I am "doing it wrong." If I have a class that is meant to behave similar to a model in an MVC architecture, how should that be implemented? – Michael Pell Dec 18 '16 at 16:07
  • 1
    @Sebas Actually I don't think it should be necessary to use `Http` in a class that is not a service (or perhaps a component, directive, or pipe) at all. I just tried to make a concise example that demonstrates a possible approach. The question IMHO doesn't provide enough information to consider all possible architectural implications. You are right, if the module implementation changes, the code needs to be updated manually. – Günter Zöchbauer Dec 18 '16 at 16:08
  • 1
    @MichaelPell see my comment to @Sebas. I don't think it's good idea to do that, but I don't know what you actually try to accomplish or how the `User` class is related to MVC. I think the controller (component or service) should have a reference to `Http` injected using DI (standard way) and provide a method that allows to fetch or update a `User` instance. – Günter Zöchbauer Dec 18 '16 at 16:10
  • 1
    @GünterZöchbauer, That makes sense. Can you add the "I don't think its a good idea... it isn't a correct Ng2 pattern" disclaimer at the top of your answer and then I will accept it, please? – Michael Pell Dec 18 '16 at 16:14
0

Assuming your reason for using the Http service remains unchallenged, I suppose this would work as an alternative to Gunter's answer:

If you import HttpModule at application level:

import { HttpModule } from '@angular/http';

@NgModule({
  imports:      [ ..., HttpModule, ...],
  declarations: [ ... ],
  bootstrap:    [ ... ]
})
export class AppModule { }

Then I think the automatic injector will work in your user class:

import {Http, Response} from "@angular/http"

export class User {
  constructor(private http: Http, private _email:string){}

  public reload(){
    this.http.get("http://www.example.com")
      .subscribe(...)
  }
}

It feels safer than trying to build a new injector on the fly.

Sebas
  • 21,192
  • 9
  • 55
  • 109
  • The problem here is that my session service looks something like: ``` export class SessionService { private _currentUser:User = new User("") ``` which is to say I am instantiating a new user outside of the Provider/Injector framework. Which leads to `Http` being undefined. – Michael Pell Dec 18 '16 at 16:21
  • I assumed "from Plain Ol' TypeScript Class" means a class not instantiated by DI. – Günter Zöchbauer Dec 18 '16 at 16:21
  • 1
    @MichaelPell can't you then get the http from inside the sessionservice, and provide it manually to the user class? – Sebas Dec 18 '16 at 16:24
  • @Sebas, yes, but I don't feel good about it ;) . I might roll with that, or I'll make a UserService and try to get it into my User class. I am all ears if someone knows a better way to do this. – Michael Pell Dec 18 '16 at 16:28