Search code examples
javascriptangularnativescriptangular2-servicesangular2-nativescript

NativeScript: Difference between a class and a service?


I'm trying to get into Nativescript + Angular2, and I read the following in the tutorial:

We’ll build this functionality as an Angular service, which is Angular’s mechanism for reusable classes that operate on data.

What they then do is to create a simple class, like this:

import { Injectable } from "@angular/core";

import { User } from "./user";

@Injectable()
export class UserService {
  register(user: User) {
    alert("About to register: " + user.email);
  }
}

Now, I can't really see the difference between a normal class and a service - this is a very normal class definition.

So, why is it called an "Angular service"?

This creates a basic Angular service with a single method that takes an instance of the User object you created in the previous section.

Also, when using this "service" in the tutorial, it isn't clear to me when this class is instantiated - when is the construction executed? Is the object saved in memory for later use? The only call to the "userservice" in the tutorial is like this:

import { Page } from "ui/page";
import { Component, ElementRef, OnInit, ViewChild } from "@angular/core";
import { User } from "../../shared/user/user";
import { UserService } from "../../shared/user/user.service";
import { Router } from "@angular/router";
import { Color } from "color";
import { View } from "ui/core/view";


@Component({
  selector: "my-app",
  providers: [UserService],
  templateUrl: "./pages/login/login.html",
  styleUrls: ["./pages/login/login-common.css", "./pages/login/login.css"]
})
export class LoginComponent implements OnInit {
  user: User;
  isLoggingIn = true;
  @ViewChild("container") container: ElementRef;

  constructor(private router: Router, private userService: UserService, private page: Page) {
    this.user = new User();
    this.user.email = "[email protected]";
    this.user.password = "1234";
  }
  //.... methods and stuff...
}


Solution

  • A class, in that context, is a regular class as in any other OO language: a "prototype" of objects which you can create instances simply using:

    let myInstance = new MyClass(<arguments...>);
    

    So, actually, an Angular service is also a class.

    But consider services a special kind of class. The main difference between regular classes and service classes is their lifecycle, specially who creates their instance (who calls new).

    Instances of a service are created - and managed (disposed) - by the Angular "container" (angular injector, actually).

    You can also "inject" instances of service classes in constructors of other service classes (or other managed components).

    A good resource in the capabilites of services is Angular's Dependency Injection Guide.

    When is the construction executed?

    The injector executes the construction. When? See below.

    Is the object saved in memory for later use?

    It could be. Depends on where you registered the service.

    Before anything, know that Angular DI is a hierarchical injection system.

    If you register the service with an Angular Module, the service will be created by the application's root injector. So everyone below it (aka everyone in that module) will receive the same instance of the service. In other words, Angular (will call the injector only once and) will create only one instance of the service class and pass that same instance to whoever asks for that service. And that instance will live as long as that module lives.

    Now, if you register the service with a component, then the service will be registered with that component's injector. So when such component requests an instance of the service, angular will call the injector and create an instance. If any child of that component asks for an instance of such service, angular will provide the same instance. No one else, only children of the component, will receive that same instance. When that component dies, the service instance dies as well.

    How does a "regular class" differ? It lacks the Injector?

    The difference is not only the lack of an injector.

    Angular aside, just JavaScript: you create an instance of a "regular class" by calling let instance = new MyRegularClass() somewhere in your code, right?

    This instance has no "magical effects", it does nothing more than any class would (just regular JavaScript methods and properties). Example: if you need instances of other classes as arguments in the constructor, no one will "magically" create you those instances and pass them. You will have to create them manually, when calling new (e.g. new MyClass(new SomeOtherClassIDependOn(), ...)). If you want to instantiate SomeOtherClassIDependOn only once and reuse the same instance everywhere it is needed, you will have to save that instance and pass it wherever it is neeed yourself.

    As services, though, angular can take some of that burden off your shoulders.

    Now, before anything: since every service, deep down, is a class, someone has to call new MyServiceClass(). The difference is that someone is not you anymore. There is no new UserService() in your code. So, who is it? This someone is the Injector.

    When Angular notices someone asks for a service, it calls for the injector to instantiate that service. The injector then calls let serviceInstance = new MyServiceClass(<dependencies>) and adds some "magic" to it (e.g. it can pass - inject - instances of other services to the constructor of a service), and make it available (save it) for anyone that requests that service in the scope you registered it.

    Note: You can call new UserService(...) yourself, as it UserService is a class. But this instance is a regular object, not managed by angular, there is no magic (no constructor arguments will be injected, no instance is saved and reused).