Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use service in class with Angular 2

I would like to use a service in my class (model)

Use Service in my Class

movie-list.component.ts

import { Component, OnInit } from '@angular/core';
import {Movie} from "../../models/movie";
import {MovieService} from "../../services/movie.service";

@Component({
  selector: 'movie-list',
  templateUrl: './movie-list.component.html',
})

export class MovieListComponent implements OnInit {
  public movies = [];
  public movie: Movie;

  constructor(private movieService: MovieService) {
      this.movie = new Movie();
  }

  ngOnInit() {
    console.log(this.movie.getMovies());
    this.movies = movie.getMovies();
  }
}

movie-list.component.html

<div *ngFor="let movie of movies">
    {{ movie.title }}

    <div *ngFor="let actor of movie.actors">
        {{ actor.name }} - {{ actor.getOscar() }}
    </div>
</div>

movie.ts (movie model)

import { Actor } from "./actor";

export class Movie {

    constructor(title: string = '', actors: any = []) {
        this.title = title;
        this.actors = [];
    }

    title: string = '';
    actors: any = [];
    movieService;

    setModel(obj) {
        Object.assign(this, obj);
    }

    addActor(actor) {
        this.actors.push(actor);
    }

    build(data) {
        let movie = new Movie(
            data.title,
            data.actors
        );

        movie.setModel({ actors: []});

        data.actors.forEach((actor) => {
            let new_actor = new Actor(
                actor.firstname,
                actor.lastname
            );

            movie.addActor(new_actor);
        });

        return movie;
    }

    getMovies() {
        let movies: any[];

        this.movieService.getMovies().subscribe(
            data => {
                data.map((result) => {
                    movies.push(this.build(result));
                });

                return movies;
            },
            error => {
                console.error(error);
            }
        )
    }
}

actor.ts (actor model)

export class Actor {

    constructor(firstname: string, lastname: string) {
        this.firstname = firstname;
        this.lastname = lastname;
    }

    firstname: string;
    lastname: string;

    setModel(obj) {
        Object.assign(this, obj);
    }

    getOscar() {
        return '10 oscars';
    };
}

movie.service.ts

import { Injectable } from '@angular/core';
import {Http} from "@angular/http";
import 'rxjs/add/operator/map';

@Injectable()
export class MovieService {
  constructor(private http:Http) { }

    getMovies() {
    return this.http
        .get('data/movies.json')
        .map(res => res.json());
  }

}

movies.json

[
  {
    "title": "title1",
    "actors": [
      {
        "firstname": "firstname10",
        "lastname": "lastname10"
      },
      {
        "firstname": "firstname11",
        "lastname": "lastname11"
      }
    ]
  },
  {
    "title": "title2",
    "actors": [
      {
        "firstname": "firstname20",
        "lastname": "lastname20"
      },
      {
        "firstname": "firstname21",
        "lastname": "lastname21"
      }
    ]
  }
]

I would like to "inject/use" my service in my Class to use this workflow:

  1. Component (call getMovies in my Class)
  2. Class (call getMovies in my service, with response build my object (Movie, Actor) with this.build
  3. Service (call my API, return JSON, without type object (Movie, Actor)

I tried to use @inject in my Class but it doesn't work from this post How to inject Service into class(not component)

I would like to know the best practice to do this.

With this code, I have an error :

enter image description here

Modification

Added this in my component :

constructor(private movieService: MovieService) {
  this.movie = new Movie();
  this.movie.movieService = movieService; // add this line
}

I have an error on this line in my component :

ngOnInit() {
    console.log(this.movie.getMovies());
    this.movies = movie.getMovies(); // error Type 'void' is not assignable to type 'any[]'.
}

I would like to conserve the subscribe in the model to have a clean code in my component

enter image description here

SOLVED

movie-list.component.ts

import { Component, OnInit } from '@angular/core';
import { Movie } from "../../models/movie";
import { MovieService } from "../../services/movie.service";

@Component({
  selector: 'movie-list',
  templateUrl: './movie-list.component.html',
})

export class MovieListComponent implements OnInit {
    public movie: Movie;
    public movies = [];

  constructor(private movieService: MovieService) {
      this.movie = new Movie('', []);
      this.movie.movieService = movieService;
  }

  ngOnInit() {
      this.movies = this.movie.getMovies();
  }
}

movie.ts

import { MovieService } from "../services/movie.service";
import { Actor } from "./actor";

export class Movie {

    constructor(
        private title: string = '',
        private actors: any[] = [],
    ) { }

    public movieService : MovieService;

    setModel(obj) {
        Object.assign(this, obj);
    }

    addActor(actor) {
        this.actors.push(actor);
    }

    build(data) {
        const movie = new Movie(
            data.title,
            data.actors,
        );

        movie.setModel({ actors: [] });

        data.actors.forEach((actor) => {
            const new_actor = new Actor(
                actor.firstname,
                actor.lastname
            );

            movie.addActor(new_actor);
        });

        return movie;
    }

    getMovies() {
        let movies = [];

         this.movieService.getMovies().subscribe(
            data => {
                data.map((result) => {
                    movies.push(this.build(result));
                });
            },
            error => {
                console.error(error);
            }
        );

        return movies;
    }
}
like image 605
Jérémie Chazelle Avatar asked Dec 19 '25 01:12

Jérémie Chazelle


1 Answers

You should read this about Smart and Presentation (Dumb) components. This is by far the best practice there is, as the whole angular data management and detection changes revolves around it.

http://blog.angular-university.io/angular-2-smart-components-vs-presentation-components-whats-the-difference-when-to-use-each-and-why/


Your error comes from the two parameters you set in the constructor, as these should be sent either by the @Input decorator or fetched from a service. You don't do things like let foo = new MovieComponent(.., ...); so this can't work.

Read this from the official documentation. It will also help you for setting up the smart / dumb component structure :

https://angular.io/guide/component-interaction#pass-data-from-parent-to-child-with-input-binding

EDIT : To make your service work, simply pass it as a dependency into your MovieComponent constructor like to :

constructor(
  private movieService: MovieService
) {}

Do not forget to provide your MovieService in your (I expect) MovieModule or wherever the MovieComponent is declared (in the same module)


EDIT2 : Here are the code parts that worked for me. The model class would need to be reworked, with a method to send back the movies built asynchronously, but even then, I'd find that model not very useful. You are better off using only interfaces and a service. Also, this is obviously not a smart/dumb component interaction, so some upgrades will be needed to achieve what you want.

MovieListComponent

export class MovieListComponent implements OnInit {
  public movies = [];
  public movie: Movie;

  constructor(private movieService: MovieService) {
    this.movie = new Movie('', []);
  }

  ngOnInit() {
    this.movie.movieService = this.movieService;
    this.movie.getMovies().subscribe(
      data => {
        data.map((result) => {
          this.movies.push(this.movie.build(result));
        });
      }
    );
  }
}

Movie (model)

export class Movie {
  movies: any[];
  movieService: MovieService

  constructor(
    private title: string = '',
    private actors: any[] = [],
  ) { }

  setModel(obj) {
    Object.assign(this, obj);
  }

  addActor(actor) {
    this.actors.push(actor);
  }

  build(data) {
    const movie = new Movie(
      data.title,
      data.actors,
    );

    movie.setModel({ actors: [] });

    data.actors.forEach((actor) => {
      const new_actor = new Actor(
        actor.firstname,
        actor.lastname
      );

      movie.addActor(new_actor);
    });

    return movie;
  }

  getMovies() {
    return this.movieService.getMovies();
  }
}

Module

@NgModule({
  imports: [
    HttpModule,
    CommonModule
  ],
  declarations: [
    MovieListComponent
  ],
  providers: [
    MovieService
  ]
})
export class MainModule { }
like image 96
Alex Beugnet Avatar answered Dec 21 '25 18:12

Alex Beugnet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!