1

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>
7
  • try using this:@Input() movie; Commented Mar 1, 2018 at 13:37
  • Still undefined :/ Commented Mar 1, 2018 at 13:41
  • Can you access to movie in ngOnInit(){ console.log(movie); } ? Commented Mar 1, 2018 at 13:54
  • 1
    Can you show the parent's html code, where you assign the movie property? Commented Mar 1, 2018 at 14:09
  • Carton, yeah, that way I can access the movie object. Commented Mar 1, 2018 at 18:40

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

1 Comment

I can access it in ngOnInit(), but not in the editReview() method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.