Retrieve object from nested array based on its id using Angular 6

I have an array of courses, where each course contains an array of segments. In my course-detail component, I have a specific course and I want to retrieve a segment by its ID.

For example, let's say I have the following course:

{
    "id": 1,
    "title": "Introduction",
    "author": "Ofir",
    "segments": [
        { "id": 1, "name": "lesson 1", "segment_type": "video", "data": "www.hey.com/1" },
        { "id": 2, "name": "lesson 2", "segment_type": "video", "data": "www.hey.com/1" },
        { "id": 3, "name": "lesson 3", "segment_type": "video", "data": "www.hey.com/1" },
        { "id": 4, "name": "quiz 1", "segment_type": "quiz1", "questions": [ {"id":1, "name":"q1"} ] }
    ]
}

And I have the segment with ID 4. I am trying to retrieve the segment object. Here is what I have attempted so far (unsuccessful and without displaying errors):

In the course.ts file:

export interface ICourse {
  id: number;
  title: string;
  author: string;
  segments: ISegment[];
}

export interface ISegment {
  id: number;
  unit_id: number;
  unit_title: string;
  name: string;
  type: string;
  data: string;
  questions: IQuestion[];
}

export interface IQuestion {
  id: number;
  question: string;
  answer1: string;
  answer2: string;
  answer3: string;
  answer4: string;
  correct: number;
}

In the course-play.component file:

import { Component, OnInit, Input} from '@angular/core';
import { ActivatedRoute, Router, Routes, NavigationEnd } from '@angular/router';
import { MatSidenavModule } from '@angular/material/sidenav';
import { LocalStorage } from '@ngx-pwa/local-storage';

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

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

export class CoursePlayComponent implements OnInit {
  errorMessage: string;
  course: ICourse;
  courseId: number;
  public currentSegment: ISegment;

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

    ngOnInit() {
        this.courseId = JSON.parse(localStorage.getItem("courseId"))
        this.getCourse(this.courseId);

        console.log(this.currentSegment.id);
      }

      getCourse(id: number) {
          this.courseService.getCourse(id).subscribe(
            course => this.course = course,
            error  => this.errorMessage = error,
            const id = +this.route.snapshot.paramMap.get('id');
            getCurrentSegment(id)
          );
        }

      getCurrentSegment(id: number){
          this.currentSegment = this.course.segments.find(d => d.id === id);
      }
}

In the HTML file:

  <div class="row content" *ngIf="course">
    <div class="col-md-3">
      <div id="head_sidebar">
        <img src="./assets/images/lg-white.png" class="d-inline-block align-top logo" alt="" routerLink="/courses" style="outline: none">
        <h3>{{course.title}}</h3>
      </div>

      <div class="col-md-12 sidenav">
        <div class="nav nav-pills nav-stacked" *ngFor="let unit of course.segments | groupBy: 'unit_title'; let i = index">
          <h6 class="course_play_title">Unit {{ i+1 }}: {{ unit.key }} </h6>
          <ul *ngFor="let lesson of unit.value">
            <li class="course_play_item">
              <a class="nav-link" routerLink="/courses/{{course.id}}/segments/{{lesson.id}}" (click)=getCurrentSegment(lesson.id)>{{lesson.name}} </a>
            </li>
          </ul>
        </div>
      </div>
    </div>

    <div class="col-md-9 no-gutters" *ngIf="currentSegment">
      <div class="col-md-12 course_play_body text-center" id="#lesson">
        <h1>{{currentSegment.name}}</h1>
        <p class='sub-text' *ngIf="course.segments?.length > 0">lesson {{currentSegment.id}} of {{course.segments?.length}}</p>
        <hr>
        <iframe *ngIf="currentSegment.segment_type === 'Video'" frameborder="0" allowfullscreen="true" src="{{currentSegment.data}}"></iframe>
      </div>
    </div>

  </div>

Answer №1

The JSON appears to be incorrect, however, it is assumed that the variable data is an object and not an array.

To find the first element that matches, you can utilize the find function of arrays.

In this scenario, we utilize (c) => c.id === 4 to define a function that will return true as soon as it locates an item with an id equal to 4

let course = {
    "data": {
        "id": 1,
        "title": "Introduction",
        "author": "Ofir",
        "segments": [
          { "id": 1, "name": "lesson 1", "segment_type": "video", "data": "www.hey.com/1" },
          { "id": 2, "name": "lesson 2", "segment_type": "video", "data": "www.hey.com/1" },
          { "id": 3, "name": "lesson 3", "segment_type": "video", "data": "www.hey.com/1" },
          { "id": 4, "name": "quiz 1", "segment_type": "quiz1", "questions": [
                                                                   {"id":1, "name":"q1"}] },
        ]
    }
}

let result = course.data.segments.find((c) => c.id === 4);

console.log(result)

It is important to wait until this.course is defined before calling getCurrentSegment. Consider implementing the following

ngOnInit() {
    // Save the course id from course-detail component and make a GET request to the service
    this.courseId = JSON.parse(localStorage.getItem("courseId"))
    this.getCourse(this.courseId);

    this.courseService.getCourse(this.courseId).subscribe(
        course => {
            this.course = course;
            const id = +this.route.snapshot.paramMap.get('id');
            this.getCurrentSegment(this.course, id);
        },
        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

Instructions for setting a default value for ng-options when dealing with nested JSON data in AngularJS

I need help setting a default value for my ng-options using ng-init and ng-model with dependent dropdowns. Here is an example of my code: <select id="country" ng-model="statessource" ng-disabled="!type2" ng-options="country for (country, states) in c ...

Angular 11 is throwing an error stating that the type 'Observable<Object>' is lacking certain properties as required by its type definition

My code is producing the following error: TS2739 (TS) Type 'Observable<Object>' is missing the following properties from type 'WeatherForecast': ID, date, temperatureC, temperatureF, summary I'm puzzled as to why this error ...

When trying to access the key value of a dynamically generated object, it returns as undefined

I am facing a challenge with my student object structure... { Freshmen: [{id: 3}, {id: 5}], Sophomores: [{id: 2}, {id: 6}], Juniors: [{id: 1}, {id: 8}], Seniors: [{id: 9}, {id: 4}, {id: 7}] } My goal is to retrieve full student objects from the d ...

How do I make functions from a specific namespace in a handwritten d.ts file accessible at the module root level?

Currently, I am working on a repository that consists entirely of JavaScript code but also includes handwritten type declarations (automerge/index.d.ts). The setup of the codebase includes a Frontend and a Backend, along with a public API that offers some ...

Rendering a sanitized string with interpolation in Angular 2

After receiving the string below: "Today's product of the day is {{product_code}} !" I took this string, sanitized it to bypass security restrictions using HTML this.DomSanitizer.bypassSecurityTrustHtml(str) and inserted it into my template using ...

Limit function parameters to only accept values with matching keys

I am relatively new to using TypeScript and am currently working on a project that involves handling various shapes of data from different sources. My goal is to pass this data to different aggregator classes, with one aggregator class corresponding to eac ...

Angular Form Validations: Mandatory and Optional Fields

One issue I am facing involves a form with over 200 input fields. The title field is required, but I also want to ensure that users fill in at least one additional field before submitting the form. Once this condition is satisfied, they should be able to ...

Whenever I execute the 'ng serve' command, I encounter an issue with ineffective mark-compacts close to the heap limit, resulting in an allocation failure and a JavaScript

I'm currently using Angular 9 and Node.js 12. When I input ng serve, I encounter the following problem: C:\Users\homz\my-app>ng serve 93% after chunk asset optimization SourceMapDevToolPlugin vendor.js generate SourceMap <--- ...

Having trouble executing ng build --prod in Azure CICD pipelines

Having trouble setting up my application's CI/CD in Azure as the build process keeps failing. I've gone through my YAML configuration and tried multiple solutions found online, but it still doesn't work. This is the YAML setup I have: ...

Problem with selecting dates in rangepicker

Having trouble with my recursion code for selecting dates in a rangepicker: recurse( () => cy.get('.mantine-DatePicker-yearsListCell').invoke('text'), (n) => { if (!n.includes(year)) { //if year not f ...

Steps for combining a sequence of subsequent subscriptions in RxJS

In my approach, I followed the code below. this.service1.info .subscribe(a => this.service2.getDetails(a.id) .subscribe(b => { this.doStuff(b); }) ); Lately, it has come to my attention that we will be adding more steps that gradu ...

How to Utilize Class Members in a Callback Function in Angular 12 with Capacitor Version 3

When I click the "Device Hardware Back Button" using Capacitor 3.0, I'm trying to navigate to the parent component with the code below. The device back button is working correctly, but I'm facing an issue where I can't access class members i ...

steps to activate button once the form is validated

Can you provide guidance on disabling and enabling a button when the form is valid? I have several conditions in my form: Name on Card: Should only contain English alphabetic letters. Card Number: Must consist of exactly 16 numbers. Expiration Month: A ...

Tips on clearing and updating the Edit Modal dialog popup form with fresh data

This code snippet represents my Edit button functionality. The issue I am facing is that I cannot populate my Form with the correct data from another component. Even when I click the (Edit) button, it retrieves different data but fails to update my form, ...

Setting a custom port for your Node.js Typescript project on Heroku

In the usual case, Heroku dynamically assigns a port for us. const PORT : string|number = process.env.PORT || 5000; However, how can I alter this code to handle the PORT... utilizing the => TypeScript shorthand? server.listen(port => { console.l ...

Error in React Typescript Order Form when recalculating on change

When creating an order form with React TypeScript, users can input the quantity, unit price, and select whether the item is taxable. In this simplified example, only 1 or 2 items can be added, but in the final version, users will be able to add 10-15 item ...

The functionality of "subscribe()" is outdated if utilized with "of(false)"

My editor is flagging the usage of of as deprecated. How can I resolve this issue and get it working with of? public save(): Observable<ISaveResult> | Observable<boolean> { if (this.item) { return this.databaseService.save(this.user ...

Leveraging property information for a dropdown field

In my index.tsx file, I am fetching data that I pass to the component FormOne. This allows me to access the data in FormOne using props.data const [data, setData] = useState([]); ... return ( ... <FormOne data={data} /> ); I am looking to ...

Discovering how to display the hidden messages section in the absence of any ongoing chats with the help of angular2

I currently have 2 tabs set up on my page. The active messages tab is functioning perfectly without any issues. However, I am encountering an error with the closed messages tab. If there are no messages in this tab, the system displays an error message w ...

Utilize ngFor in Angular Ionic to dynamically highlight rows based on specific criteria

I'm working on an application where I need to highlight rows based on a count value using ngFor in Angular. After trying different approaches, I was only able to highlight the specific row based on my count. Can someone please assist me? Check out m ...