Display content on ngbModal when clicking on table row - Angular 2

2.7k Views Asked by At

I have been learning Angular 2 I have currently implemented Components as content.

I have a table on my Bug-list.component.html which connects to firebase 3 reads data from the bug table and displays this data within the table using *ngFor as shown here:

enter image description here

When I click + Add Bug button, the ngbModal appears which allows me to enter new data and press save which then saves to firebase - note: this is working as expected.

This issue:

What I'm trying to achieve is when the user presses edit on either of the rows, I pass in the uniqueId for the bug and try to pre-populate the ngbModal with information about that bug, which then allows the end user to edit it / save it or delete it, I do this using the routerlink as shown here:

 <a [routerLink]="['/bug-detail', 1]">
   Edit
 </a>

However when I click on 'Edit' this is the current error message I see within the console:

enter image description here

I also tried navigating programmatically but the same error appears.

Now inside the component I'm loading via the ngbModal this is the .ts file:

** Bug Detail Component ** - Displaying content about individual bugs, which is loaded via ngbModal.

import { Component, OnInit, Input, OnDestroy } from '@angular/core';
// Routing
import { ActivatedRoute } from '@angular/router';
// Bootstrap
import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
// Forms
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
// Services
import { BugService } from '../bugs/service/bug.service';
// Models
import { Bug } from '../bugs/model/bug';
// Validators
import { forbiddenStringValidator } from '../shared/validation/forbidden-string.validator';

@Component({
  selector: 'bug-detail',
  templateUrl: './bug-detail.component.html',
  styleUrls: ['./bug-detail.component.css']
})

export class BugDetailComponent implements OnInit {

private bugForm: FormGroup;
private id: number;
private sub: any;

@Input() currentBug = new Bug(null, null, null, null, null, null, null, null, null);

constructor(private formBuilder: FormBuilder, private bugService: BugService, private route: ActivatedRoute, public activeModal: NgbActiveModal) { }

ngOnInit() {
    this.sub = this.route.params.subscribe(params => {
        this.id = +params['id']; // (+) converts string 'id' to a number
        console.log(this.id);
    });

    this.configureForm();
}

ngOnDestroy() {
    this.sub.unsubscribe();
}

configureForm() {
    this.bugForm = new FormGroup({
        title: new FormControl(null, Validators.required), 
        status: new FormControl(1, Validators.required),
        severity: new FormControl(1, Validators.required),
        description: new FormControl(null, Validators.required)
    });
}

submitForm() {
    this.addBug();
}

addBug() {
    this.currentBug.title = this.bugForm.value["title"];
    this.currentBug.status = this.bugForm.value["status"];
    this.currentBug.severity = this.bugForm.value["severity"];
    this.currentBug.description = this.bugForm.value["description"];
    this.bugService.addBug(this.currentBug);
    this.activeModal.close();
}

}

As you can see I have imported the NgbActiveModal inside the constructor for this component.

Now this is my bug-list.component.ts: - Displays all bugs on the table, and when + Add Bug is clicked, it calls the open function.

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { BugService } from '../service/bug.service';
import { Bug } from '../model/bug';
import { NgbModal, NgbActiveModal, NgbModalRef, NgbModalOptions } from '@ng-bootstrap/ng-bootstrap';
import { BugDetailComponent } from '../../bug-detail/bug-detail.component';
import { ActivatedRoute, Router } from '@angular/router';


@Component({
  selector: 'bug-list',
  templateUrl: './bug-list.component.html',
  styleUrls: ['./bug-list.component.css']
})

export class BugListComponent implements OnInit {

private bugs: Bug[] = [];

constructor(private bugService: BugService, private cdRef: ChangeDetectorRef, private modalService: NgbModal, private route: ActivatedRoute, private router: Router) { }

ngOnInit() {
    this.getAddedBugs();
}

getAddedBugs() {
    this.bugService.getAddedBugs().subscribe(bug => {
        this.bugs.push(bug);
        this.cdRef.detectChanges();

    },
        err => {
            console.error("unable to get added bug - ", err);
        });
}

open(options: NgbModalOptions = { size: 'lg' }): NgbModalRef {
    const modalRef = this.modalService.open(BugDetailComponent, options);
    modalRef.componentInstance.name = 'bugDetail';
    return modalRef;
}


}

So my question is, how can I pass in the ID of the bug clicked into the bug-detail.compoenent, populate that component with values linked to that bug and then display the modal again, allowing the user to edit / delete.

Surely there must be a way to pass in a uniqueId, populate the fields on the ngbModal and then display it.

Update

Ok so after following component communication I created a service:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class BugCommunication {

// Literally copied straight from example.

private missionAnnouncedSource = new Subject<string>();

missionAnnounced$ = this.missionAnnouncedSource.asObservable();

announceMission(mission: string) {
    this.missionAnnouncedSource.next(mission);

    console.log(mission);

}

}

This service is injected into Bug-list.component.ts when the user clicks edit, I then call the above service passing in a value as shown here:

 editBug(bug: Bug) {

    let mission = "Testing sevice";

    this.comServe.announceMission(mission);
    this.history.push(`Mission "${mission}" announced`);

}

Note: comServe is the name of the service mentioned above after it's been imported.

The service then console.logs "Testing service".

Inside my bug-detail.component.ts I subscribe to the above event as shown here:

    ngOnInit() {
    this.subscription = this.comServe.missionAnnounced$.subscribe(
        mission => {
            console.log(mission);
        });

    this.configureForm();
}

However whenever I click on the edit button and call the service, bug-detail.component does not log anything to the console.

I have correctly imported this service into the Module, can someone explain what I'm doing wrong?

1

There are 1 best solutions below

0
On

It sounds like your subscribe method isn't receiving the .next() value from your service.

this.missionAnnouncedSource.next(mission);

I believe it's because your observable is observing to the mission property, while your service is sending the message as an unnamed property. Aka: next(string) Two sections of your code that will need to change

bug-detail.component.ts

.subscribe(
    mission => {
        console.log(mission);
    });

BugCommunication

this.missionAnnouncedSource.next(mission);

Here's a solid example: http://jasonwatmore.com/post/2016/12/01/angular-2-communicating-between-components-with-observable-subject