1
votes

So I'm sending a movie object from a parent to a child component. I use @Input from the core module to do this.

Now, I am able to use this data inside the template to display my view, but when I try to access it in for example editReview() then this.movie returns undefined.

Does anyone know how to fix this?

Child Component: the console.log returns undefined

export class ReviewListComponent implements OnInit {
@Input('movie') movie;

constructor(private reviewService: ReviewService){}

editReview() {
    console.log(this.movie);
}

}

Child Component Template: I am able to display my name and the content of the review. What's not working unfortunately is when I click the button it says that this.movie is undefined

<ul class="list-group">
    <li *ngFor="let review of movie?.reviews" class="list-group-item">
        <p>{{review.user.firstName}} {{ review.user.lastName}}</p>
                <hr>
        <p>{{review.content}}</p>
    </li>
</ul>
<button (click)="editReview()">Button</button>

Edit: I added the components and templates of the two parent components: The first one is the movie component where I retrieve the movie object asynchronously, the second is the review component which contains the review-list component that I had already posted above

movie.component.ts

import {Component, OnInit} from "@angular/core";
import { MovieService} from "./movie.service";
import {ActivatedRoute} from "@angular/router";


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

export class MovieComponent implements OnInit{
    rating;
    movie;
    movieId;

    constructor(private movieService: MovieService, private route: ActivatedRoute){

    }

    checkRating(){
        return typeof this.rating === 'number';
    }

    ngOnInit(){
        this.route.params.subscribe(params => {
           this.movieId = params.id;

            var userId = localStorage.getItem('userId');

            this.movieService.getMovie(this.movieId)
                .subscribe(movie => {
                    this.movie = movie.obj;
                    this.movie.averageRating = Number(this.movie.averageRating);
                    console.log(this.movie);
                });

            if (userId){
                this.movieService.getRating(userId, this.movieId)
                    .subscribe( result => {
                        this.rating = result.rating;
                    })
            }
        });
    }

    addRating(score) {
        var userId = localStorage.getItem('userId');

        this.movieService.addRating(score, userId, this.movie._id)
            .subscribe(data => {
                this.rating = data.obj.rating;
            });
    }
}

movie.component.html: this gives movie object to review.component through element app-review

<div class="container">
    <div class="col col-md-4 col-md-offset-2">
        <img [src]="movie?.pictureUrl" class="img-responsive" alt="hello">
    </div>
    <div class=" col col-md-6">
        <h2>{{movie?.title}} ({{movie?.year}})</h2>
        <h3>Average Score:</h3>
        <span class="glyphicon glyphicon-star"></span><span><h1>{{movie?.averageRating}}</h1></span><br>
        <h3>My Score:</h3>
        <div class="row">
            <div class="col">
                <div *ngIf="!checkRating()" ngbDropdown class="d-inline-block">
                        <button class="btn btn-outline-primary" ngbDropdownToggle>Rate The Movie!</button>
                        <div ngbDropdownMenu aria-labelledby="dropdownBasic1">
                            <button value="1" (click)="addRating(1)" class="dropdown-item">1</button>
                            <button value="2" (click)="addRating(2)" class="dropdown-item">2</button>
                            <button value="3" (click)="addRating(3)" class="dropdown-item">3</button>
                            <button value="4" (click)="addRating(4)" class="dropdown-item">4</button>
                            <button value="5" (click)="addRating(5)" class="dropdown-item">5</button>
                        </div>
                    </div>
                        <div *ngIf="checkRating()">
                            <h1>{{rating}}</h1>
                        </div>
            </div>
        </div>
        <h4>{{movie?.director}}</h4>
        <h4>{{movie?.actors}}</h4>
        <h4>{{movie?.country}}</h4>
        <p> {{movie?.description}}</p>
    </div>

</div>

<hr class="col-md-8 col-md-offset-2">

<div class="col-md-8 col-md-offset-2">
    <ng-container *ngIf="!!movie">
        <app-review [movie]="movie"></app-review>
    </ng-container>
</div>

review.component.ts

import {Component, ElementRef, Input, OnInit, ViewChild} from "@angular/core";
import {NgForm} from "@angular/forms";
import {ReviewService} from "./review.service";
import {ActivatedRoute} from "@angular/router";


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

export class ReviewComponent implements OnInit{

    movieId;
    @Input('movie') movie;
    @ViewChild('textArea') textArea;


    constructor(private reviewService: ReviewService, private route: ActivatedRoute){}

    ngOnInit(){
        this.route.params.subscribe( params => {
          this.movieId = params.id
        });
    };


    onClear(form: NgForm) {
        form.resetForm()
    }

    onSubmit(form: NgForm) {
        let content = form.value.review;
        let userId = localStorage.getItem('userId');
        let movieId = this.movieId;

            this.reviewService.addReview(content, userId, movieId)
                .subscribe( result => {
                    console.log(result.obj);
                    this.movie.reviews.unshift(result.obj);
                    form.resetForm()
                })


    }
}

review.component.html: this gives movie object to the review-list component through app-review-list

<ng-container *ngIf="!!movie">
    <app-review-list [movie]="movie"></app-review-list>
</ng-container>


<hr>

<form ngNativeValidate (ngSubmit)="onSubmit(f)" #f="ngForm">
    <div class="form-group">
        <label for="review">Write A Review:</label>
        <textarea
                #textArea
                (keyup.enter)="onSubmit(f)"
                rows="4"
                cols="50"
                type="text"
                id="review"
                ngModel
                class="form-control"
                name="review"
                required
        ></textarea>
    </div>
    <button type="button" class="btn btn-danger" (click)="onClear(f)">Clear</button>
    <button class="btn btn-primary" type="submit">Save</button>
</form>
1
try using this:@Input() movie; - Murli Prajapati
Still undefined :/ - tilly
Can you access to movie in ngOnInit(){ console.log(movie); } ? - carton
Can you show the parent's html code, where you assign the movie property? - David
Carton, yeah, that way I can access the movie object. - tilly

1 Answers

1
votes

you can access it in ngOnInit() just implement OnInit interface