How to transfer data between components in Angular 6 using a service

I'm facing an issue with passing data between the course-detail component and the course-play component. I tried using a shared service and BehaviorSubject, but it didn't work as expected. Strangely, there are no errors thrown, and the data remains unchanged. The only error message I see when I open course-detail.html is "ERROR ReferenceError: course is not defined". Although the data gets passed correctly to the course-detail component through the service, I struggle with getting the data back to the service so that course-play can also utilize it. Below are the relevant files:

course.ts

export interface ICourse {
  course_id: number;
  title: string;
  autor: string;
  segments: ISegment[];
}

export interface ISegment {
  segment_id: number;
  unit_id: number;
  unit_title: string;
  name: string;
  type: string;
  data: string;
}

course.service

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';

import { Observable, throwError } from 'rxjs';
import { catchError, groupBy } from 'rxjs/operators';

import { ICourse } from './course';

// Inject Data from Rails app to Angular app
@Injectable()
export class CourseService{

  // JSON url to get data from
  private url = 'http://localhost:3000/courses';
  private courseUrl = 'http://localhost:3000/courses.json';

  // Subscribe data
  private courseData = new BehaviorSubject<ICourse>(null);
  public courseData$ = this.courseData.asObservable();

  // here we set/change value of the observable
  setData(course) {
    this.courseData.next(course)
  }

  constructor(private http: HttpClient) { }

  // Handle Any Kind of Errors
  private handleError(error: HttpErrorResponse) {

    // A client-side or network error occured. Handle it accordingly.
    if (error.error instanceof ErrorEvent) {
      console.error('An error occured:', error.error.message);
    }

    // The backend returned an unsuccessful response code.
    // The response body may contain clues as to what went wrong.
    else {
      console.error(
        'Backend returned code ${error.status}, ' +
        'body was ${error.error}');
    }

    // return an Observable with a user-facing error error message
    return throwError(
      'Something bad happend; please try again later.');
  }

  // Get All Courses from Rails API App
  getCourses(): Observable<ICourse[]> {
  const coursesUrl = `${this.url}` + '.json';

  return this.http.get<ICourse[]>(coursesUrl)
      .pipe(catchError(this.handleError));
  }

  // Get Single Course by id. will 404 if id not found
  getCourse(id: number): Observable<ICourse> {
    const detailUrl = `${this.url}/${id}` + '.json';

    return this.http.get<ICourse>(detailUrl)
        .pipe(catchError(this.handleError));
  }


}

course-detail.component

import { Component, OnInit, Pipe, PipeTransform } from '@angular/core';
import { ActivatedRoute, Router, Routes } from '@angular/router';

import { ICourse } from '../course';
import { CourseService } from '../course.service';


// Course-detail decorator
@Component({
  selector: 'lg-course-detail',
  templateUrl: './course-detail.component.html',
  styleUrls: ['./course-detail.component.sass']
})

export class CourseDetailComponent implements OnInit {
  course: ICourse;
  errorMessage: string;

  constructor(private courseService: CourseService,
        private route: ActivatedRoute,
        private router: Router) {
  }

  // On start of the life cycle
  ngOnInit() {
    // get the current segment id to use it on the html file
    const id = +this.route.snapshot.paramMap.get('id');
    this.getCourse(id);
    }

   // Get course detail by id
   getCourse(id: number) {
     this.courseService.getCourse(id).subscribe(
       course => this.course = course,
       error  => this.errorMessage = <any>error;
       this.courseService.setData(course))
   }

   // When we click the back button in browser
   onBack(): void {
     this.router.navigate(['/courses']);
   }

}

course-play.component

import { Component, OnInit, Input} from '@angular/core';
import { ActivatedRoute, Router, Routes, NavigationEnd } from '@angular/router';
import { MatSidenavModule } from '@angular/material/sidenav';

import { ICourse } from '../course';
import { CourseService } from '../course.service';


// Couse-play decorator
@Component({
  selector: 'lg-course-play-course-play',
  templateUrl: './course-play.component.html',
  styleUrls: ['./course-play.component.sass']
})

export class CoursePlayComponent implements OnInit {
  errorMessage: string;
  courseData: ICourse;

  constructor(private courseService: CourseService,
      private route: ActivatedRoute,
      private router: Router) {
        courseService.courseData$.subscribe( courseData => this.courseData = courseData)
  }

    // On start of the life cycle
    ngOnInit() {
        // get the current segment id to use it on the html file
        const id = +this.route.snapshot.paramMap.get('id');
      }

    // When we click the back button in browser
     onBack(): void {
       this.router.navigate(['/courses/:id']);
     }

}

Answer №1

You should not be calling the

this.courseService.setData(course)
function in this particular location.

Please update the code block in the course-detail.component file with the following:

  // Retrieve course details by ID
   getCourseDetails(id: number) {
     this.courseService.getCourse(id).subscribe(
       course =>  {
          this.course = course;
          this.courseService.setData(course);
       },
       error  => this.errorMessage = <any>error;
      )
   }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Resetting md-radio-button choices within an Angular 2 application

My Angular app has a sorting filter using radio buttons via md-radio-group for users to choose how they want data displayed. The radio buttons work fine, but I'm struggling to clear them when the "Restore Defaults" button is clicked. This is the code ...

What is the best way to assign a value to an ngrx reducer/action in order to update the state?

As a newcomer to Angular ngrx, I am in the process of integrating it into my 'standard beginner-project' by replacing all @Input()s and @Output()s. While incrementing and decrementing the state is straightforward, I am faced with the challenge of ...

Unable to select multiple checkboxes as they are unresponsive and not registering any clicks

I am facing an issue with rendering multiple checkboxes in a grid cell. I attempted to use formly multicheckbox, but unfortunately the checkboxes did not render properly. So I decided to try a different approach, however, now the checkboxes are not being c ...

Angular elements nested within each other are causing the ExpressionChangedAfterItHasBeenCheckedError

After conducting thorough research on this issue, I am now uncertain whether it is a bug or an error in my implementation. The problem arises with an element that utilizes a service to retrieve data and then passes it on to a child element. However, upon ...

Cannot use a 'string' type expression to index a 'Request<ParamsDictionary, any, any, Query>' type

Currently, my goal is to develop a middleware that can validate the input data in a request. export function validator(schema: Joi.ObjectSchema, key: string) { return function (req: Request, res: Response, next: NextFunction): void { try { Joi ...

What is the best way to transform a string into an array?

After receiving an object from the http response, it looks something like this: {"[3, company1]":["role_user"], "[4, company2]":["role_admin"] } The key in the object is represented as an array. Is there a method in ...

React Native is throwing an error message saying that the Component cannot be used as a JSX component. It mentions that the Type '{}' is not assignable to type 'ReactNode'

Recently, I initiated a new project and encountered errors while working with various packages such as React Native Reanimated and React Navigation Stack. Below is my package.json configuration: { "name": "foodmatch", "version ...

Using Javascript or ES6, you can compare a nested array object with another array of elements and generate a new array based on

I am dealing with a complicated array structure as shown below sectionInfo = [{id: 1, name:'ma'}, {id: 2, name:'na'}, {id: 3, name:'ra'}, {id: 4, name:'ka'}, {id: 5, name:'pa'}]; abc = [{id:'1' ...

Setting up a variable with a changing value

In a very specific scenario, the body of type varies based on the length_type attribute (as illustrated in the example). enum LengthTypeEnum { SELECT = 'SELECT', STATIC = 'STATIC', CONDITION = 'CONDITION', PERIOD = ...

Loading SVG templates dynamically in Angular can be done by utilizing a string

Is it possible to convert SVG content loaded from a server into a component template in Angular, with the ability to bind properties to it? For example, <tspan [attr.color]="textColor" ...>{{myText}}</tspan>. I have tried loading and ...

Obtain data attributes using JQuery's click event handler

I'm facing an issue with a div structure setup as follows: <div class='bar'> <div class='contents'> <div class='element' data-big='join'>JOIN ME</div> <div class=& ...

What could be causing the code to not wait for the listener to finish its execution?

I've been attempting to make sure that the listener has processed all messages before proceeding with console.log("Done") using await, but it doesn't seem to be working. What could I possibly be overlooking? const f = async (leftPaneRow ...

Want to enhance user experience? Simply click on the chart in MUI X charts BarChart to retrieve data effortlessly!

I'm working with a data graph and looking for a way to retrieve the value of a specific column whenever I click on it, and then display that value on the console screen. Check out my Data Graph here I am using MUI X charts BarChart for this project. ...

Tips for personalizing an angular-powered kendo notification component by adding a close button and setting a timer for automatic hiding

I am looking to enhance the angular-based kendo notification element by adding an auto-hiding feature and a close button. Here is what I have attempted so far: app-custom-toast.ts: it's a generic toast component. import { ChangeDetectorRef, Componen ...

Difficulty updating Angular packages using NCU (npm-check-update)

I attempted to update everything on my project by running the following commands: G:\Projects\salarkazazi> npm i -g npm-check-updates The output displayed the following warnings: npm WARN deprecated [email protected]: this library is n ...

Encountering an ERROR during the compilation of ./src/polyfills.ts while running ng test - Angular 6. The module build

I encountered a problem in an angular project I am working on where the karma.config was missing. To resolve this, I manually added it and attempted to run the test using the command ng test. However, during the execution, an error message appeared: [./src ...

Preserving type information in TypeScript function return values

Wondering how to make this code work in TypeScript. Function tempA copies the value of x.a to x.temp and returns it, while function tempB does the same with x.b. However, when calling tempA, the compiler seems to forget about the existence of the b field ...

Modifying Angular 4 instance field in the code does not update the template as expected

One issue I am encountering is that changes in the instance variable in my component class are not automatically reflected in my template file unless I explicitly call ref.detectChanges The method signInWithGoogle in my auth service is called from the com ...

Securing routes in Angular without relying on LocalStorage or Cookies by implementing an Auth Guard

Currently, I am working on implementing an authentication guard in Angular. Instead of the conventional method of checking local storage or cookies to verify user authentication, I am utilizing API endpoints that respond with 200 OK if a httponly cookie co ...

Issue encountered: [object Object] is being displayed upon attempting to submit my username and password through a REST service in Angular

My code was written in Angular CLI using the Sublime text editor and Node.js. The login component can be found in logincomponent.ts file. import { Component, OnInit } from '@angular/core'; import { FormsModule, NgForm } from '@angular/forms ...