I have 2 components.
The .html of parent component this is the code:
<div class="space">
<ng-container *ngFor="let item of items">
<ng-container [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{item: item}">
</ng-container>
</ng-container>
</div>
<ng-template #itemTemplate let-item="item">
<div class="host">
<img class='card-img-top'
src={{item.image}}
>
<p> </p>
<h6 class="title">{{item.projectTitle}}</h6>
<hr>
<ng-container *ngIf="item.type=='inactive'">
<button id="inactive"
class="btn btn-sm btn-warning py-0 custom-button text-uppercase">{{item.type}}</button>
</ng-container>
</div>
</ng-template>
All code since line: <ng-template #itemTemplate let-item="item">
It's necessary to show in the .html of the child component.
This is the .ts of parent component
import { AfterViewInit, Component, ComponentFactoryResolver, ViewChild, ViewContainerRef, OnInit, TemplateRef, Input, ContentChild } from '#angular/core';
import listProjects from './projects.json';
import { ChildComponent } from './child.component';
#Component({
selector: 'parent-view',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss'],
})
export class ParentComponent {
public items: any = listProjects;
#ContentChild('itemTemplate', { read: TemplateRef }) itemTemplate: ViewContainerRef;
How can show the <ng-template #itemTemplate let-item="item"> in other component?
The solution to this problem:
File: projects-tile-view-components.ts
export class ProjectsTileViewComponent {
#ViewChild('tileViewItems', { static: true }) tileViewItemTemplate: TileViewComponent;
public items = listProjects;
public type = 'etb';
constructor() {}
addItems(e) {
if (this.type === 'osd') {
this.type = 'etb';
} else {
this.type = 'osd';
}
}
}
the file projects-tile-view-components.html
<lib-tile-view [items]="items" #tileViewItems>
<ng-template #tileViewItem let-item>
<div [ngSwitch]="type">
<lib-osd-tile-view-item [item]="item" *ngSwitchCase="'osd'"></lib-osd-tile-view-item>
<lib-osd-tile-view-item [item]="item" *ngSwitchDefault></lib-osd-tile-view-item>
<lib-etb-tile-view-item [item]="item" *ngSwitchCase="'etb'"></lib-etb-tile-view-item>
</div>
</ng-template>
</lib-tile-view>
the file view-item.ts (interface)
export interface ViewItem {
item: any;
}
the file tile-view-components.html
<div>
<ng-container *ngFor="let item of items">
<ng-container *ngTemplateOutlet="tileViewItemTemplate; context: {$implicit: item}">
</ng-container>
</ng-container>
</div>
the file tile-view-item.components.ts
#Component({
selector: 'lib-tile-view',
templateUrl: './tile-view.component.html',
styleUrls: ['./tile-view.component.scss'],
})
export class TileViewComponent {
#Input()
public items: any;
#ContentChild('tileViewItem', { static: true }) tileViewItemTemplate;
}
the file osd-tile-view-components.ts
#Component({
selector: 'lib-osd-tile-view-item',
templateUrl: './osd-tile-view-item.component.html',
styleUrls: ['./osd-tile-view-item.component.scss'],
})
export class OsdTileViewItemComponent implements ViewItem {
#Input() item: any;
public projectView() {
alert('show project');
}
}
the file osd-tile-view-item.components.html
<div class="host" fxFlex="0 1 calc(100% - 32px)" fxFlex.lt-md="0 1 calc(100% - 32px)" fxFlex.lt-sm="100%" (click) = 'projectView()'>
<img class='img-fluid img-thumbnail' src={{item?.image}} alt='logo nih'>
<p> </p>
<h6 class="title">{{item?.projectTitle}}</h6>
<p class="small"><span class="text-muted small text-uppercase">ZIA ID
Number:</span>{{item?.number}}</p>
</div>
Thanks for your help
You need to share this TemplateRef in service (if you want to have access in every component in your application), and then in other component you can read this reference and do something with it - because if you want to pass this reference only to child, then you can use #Input() in child component, but if it should be available across all components, then you need to create service.
service:
#Injectable({
providedIn: 'root'
})
export class TemplateService {
someTemplate: TemplateRef<any>;
}
componentA:
#Component({
selector: 'parent-view',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss'],
})
export class ParentComponent {
public items: any = listProjects;
#ViewChild('itemTemplate', { read: TemplateRef }) set itemTemplate(value) {
this.ts.someTemplate = value;
}
construtor(private ts: TemplateService) {}
}
then in any other component, you can read this template reference
componentB:
#Component({
selector: 'component-b',
templateUrl: './component-b.component.html',
styleUrls: ['./component-b.component.scss'],
})
export class ComponentBComponent {
get itemTemplateReference() {
return this.ts.itemTemplate;
}
construtor(private ts: TemplateService) {}
}
.html of componentB
<ng-container [ngTemplateOutlet]="itemTemplateReference"></ng-container>
And it should render the same <ng-template>
Related
I want to take values from input to a function to alert
here is my html
<div class="container p-5 ">
<input #titleInput *ngIf="isClicked" type="text" class="col-4"><br>
<button (click)="OnClick()" class="btn btn-primary col-2 ">
Show
</button>
<button (click)="Send(titleInput.value)" class="btn btn-success col-2 m-3">
Send
</button>
</div>
and here is my componet.ts
import { Component} from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
Send(data: any) {
alert(data)
}
OnClick() {
this.isClicked=true;
}
title = 'demoproject1';
isClicked=false;
}
I want to get value from input field and I want get value into components function
Create Variable to store input value:
component.ts
...
export class AppComponent {
input: string;
...
Add FormsModule to your module.ts if not already imported
module.ts
import { FormsModule } from '#angular/forms';
setup ngModel on your HTML:
html:
<input type="text" [(ngModel)]="input" ></-input>
Important:
Dont forget to add a Route to the component in your app-routing.module.ts
ngModel Docs
#ViewChild('titleInput') titleInput:
ElementRef;
ngAfterViewInit() {
// Put your logic here ...
}
i put the code here :
https://stackblitz.com/edit/angular-ivy-b4hcqw?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fapp.component.html
My task: The received value from service 1 or 2, depending on the value, change the styles in the html component. Using the ng-switch directive, I expect to compare the value received from the object with the specified template value. Styles are not applied. The main problem is that the styles are not applied
My component:
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, Self } from '#angular/core';
import { ConfigService, IProductListItem, SliderValueOptions } from 'common-modules';
import { Router } from '#angular/router';
import { debounceTime, filter, takeUntil, tap } from 'rxjs/operators';
import { NgOnDestroy } from '../../core/services/destroy.service';
import { BehaviorSubject } from 'rxjs';
import { OnInit, OnDestroy } from '#angular/core';
#Component({
selector: 'app-product-item',
templateUrl: './product-item.component.html',
styleUrls: ['./product-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [NgOnDestroy],
})
export class ProductItemComponent implements OnInit, OnDestroy {
#Input() product: IProductListItem;
#Input() doubleClickEnabled: boolean;
// tslint:disable-next-line:no-output-on-prefix
#Output() onAddToCart = new EventEmitter<any>();
themeProperties: number;
visibility: boolean = false;
constructor(private _router: Router, private _config: ConfigService, #Self() private onDestroy$: NgOnDestroy) {}
ngOnInit() {
this._config.marketplaceConfig.pipe(takeUntil(this.onDestroy$)).subscribe((config) => {
this.themeProperties = config.structure?.theme;
});
}
}
My html:
<mat-card class="card">
<div [ngSwitch]="themeProperties">
<ng-template *ngswitchcase="2">
{{ themeProperties }}
<mat-card id="cardbackground">
<a class="card__link" (click)="redirectToProduct(product)" (dblclick)="doubleClicked(product)">
<div
style="display: none"
class="card__promo"
*ngIf="product.priceWithDiscount && product?.promoIndividual?.percentDiscount"
>
-{{ product?.promoIndividual?.percentDiscount }}%
</div>
<!-- <b2b-modern-image mat-card-image [src]="product.photos[0]"></b2b-modern-image> -->
<img class="mat-card-image" [src]="product.photos" alt="" />
<mat-card-content class="card__content" [class.has-padding-top]="product && product['discount']">
<div class="super-sale">супер скидка</div>
<div *ngIf="product && product['discount']" class="discount">-{{ product['discount'] }}%</div>
<div
*ngIf="product && product.promoIndividual && product?.promoIndividual?.percentDiscount"
class="discount"
>
-{{ product?.promoIndividual?.percentDiscount }}
%
</div>
<ng-template #defaultPrice>
<!-- <span class="price">{{product.price}} ₽</span>-->
</ng-template>
<div class="rating">
<ngx-stars color="#ffd700" [readonly]="true" [initialStars]="product.rating || 0"> </ngx-stars>
<span class="ml-3">{{ product.views || 0 }} отзывов</span>
</div>
<h3 class="name wrap-two-line" [matTooltip]="product?.feed" matTooltipPosition="above">
{{ product | localize: 'name' }}
</h3>
<div class="а">
<div
class="d-flex align-items-center"
*ngIf="product.priceWithDiscount && product.priceWithDiscount != product.price; else defaultPrice"
>
<span class="price old">{{ product.price }}₽</span>
</div>
<p class="price">{{ (product.priceWithDiscount || 0).toFixed(1) }}₽</p>
</div>
</mat-card-content>
</a>
<mat-card-footer class="card__footer">
<a routerLink="/confirm-order" [queryParams]="{ products: product.id }" mat-raised-button color="primary">
Купить сейчас
</a>
<button mat-button color="primary" (click)="addToCart(product)">
<mat-icon>add_shopping_cart</mat-icon>
</button>
</mat-card-footer>
</mat-card>
</ng-template>
</div>
</mat-card>
change component to:
themeProperties$: Observable<number>;
...
ngOnInit() {
this.themeProperties$ = this._config.marketplaceConfig.pipe(map((config) => config.structure?.theme))
}
change template to:
<div [ngSwitch]="themeProperties$ | async">
<ng-container *ngSwitchCase="2">
....
</ng-container>
issues:
casing wrong on ngSwitchCase directive
OnPush change detection not running correctly, async pipe resolves
ng-template doesn't render to DOM. it's a template for use elsewhere. use ng-container instead.
The spelling of the template switch statement is case sensitive, should be *ngSwitchCase.
Also the ng-template does not work in this case, you need to use ng-container
So please change your statements to this layout, and all should work:
<ng-container *ngSwitchCase="2">
also because you are using ChangeDetectionStrategy.OnPush you need to trigger the change detection manually for the ngSwitch.
Here is a working example.
constructor(private _router: Router, private _config: ConfigService, #Self() private onDestroy$: NgOnDestroy, private cdr: ChangeDetectorRef) {}
ngOnInit() {
this._config.marketplaceConfig.pipe(takeUntil(this.onDestroy$)).subscribe((config) => {
this.themeProperties = config.structure?.theme;
this.cdr.detectChanges(); // <=== here, after setting the value
});
}
I have a header component and home component. In header component a download button is there, When I click download button the content of home component will be download,so I need to access the div id(content) of home component from header component. I am not getting how to do it.
header.component.html
<button (click)="generarPDF()" type="button" class="btn btn-primary">Download</button>
<nav *ngIf="router.url !== '/' && router.url !== '/login'" class="mb-3 navbar navbar-expand-sm bg-dark-custom navbar-dark">
<!-- Brand/logo -->
<a class="navbar-brand" routerLink="/"><img class="img-responsive" src="../assets/logo.png"></a>
</nav>
header.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router";
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
constructor(public router: Router){}
ngOnInit() {
}
}
home.component.html
<div class="container-fluid" id="content">
<div class="row">
<div class="col-md-6">
<div class="mb-3 text-left">
<div>Total Expenses are: <b>Rs. {{this.sum}}</b></div>
</div>
</div>
<div class="col-md-6">
<div class="mb-3 text-right">
<input [(ngModel)]="searchText" autocomplete="off" class="col-md-6 searchinput" type="text"
placeholder="Search.." />
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-bordered expensetable">
<thead>
<tr>
<th>Date</th>
<th>Treatment</th>
<th>Expenses (INR)</th>
<th>Results</th>
</tr>
</thead>
<tbody>
<ng-container *ngIf="( getListData | filter:searchText) as result">
<tr *ngFor="let item of result">
<td>{{item.Date}}<div><small>({{item.day}})</small></div>
</td>
<td [innerHtml]="getTreatment(item.Treatment)"></td>
<td>{{item.Expenses}}</td>
<td><span placement="left" ngbTooltip="{{item.Description}}" class="{{item.Result}}"><i
class="las la-info-circle info"></i> Info</span></td>
</tr>
<tr *ngIf="result.length === 0">
<td colspan="4" class="text-center">No Data Found</td>
</tr>
</ng-container>
</tbody>
</table>
</div>
</div>
</div>
home.component.ts
import { Component, OnInit,ViewChild, ElementRef} from '#angular/core';
import { CommonserviceService } from './../utilities/services/commonservice.service';
import {NgbModal, ModalDismissReasons} from '#ng-bootstrap/ng-bootstrap';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
getListData: any;
sum:number;
constructor(private modalService: NgbModal,private commonserviceService: CommonserviceService) { }
#ViewChild('content', { 'static': true}) content:ElementRef;
ngOnInit() {
this.getHeroes();
}
getTreatment(data) {
console.log(data);
let str = '<div class="demooutput">'
let arr = data.split(',');
if (arr.length > 0) {
for (let i = 0; i < arr.length; i++) {
str += '<span class="' + arr[i] + '">' + arr[i] + '</span>'
}
}
str += '</div>'
return str
}
getHeroes(){
this.commonserviceService.getData().subscribe(getListData =>{
this.getListData = getListData;
console.log(this.getListData);
this.sum=0;
for(let a of this.getListData){
this.sum=this.sum+a.Expenses;
}
console.log(this.sum);
},
(error) => {
alert('No data');
}
);
}
generarPDF() {
const div = document.getElementById('content');
const options = {
background: 'white',
scale: 3
};
html2canvas(div, options).then((canvas) => {
var img = canvas.toDataURL("image/PNG");
var doc = new jsPDF('l', 'mm', 'a4', 1);
// Add image Canvas to PDF
const bufferX = 5;
const bufferY = 5;
const imgProps = (<any>doc).getImageProperties(img);
const pdfWidth = doc.internal.pageSize.getWidth() - 2 * bufferX;
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
doc.addImage(img, 'PNG', bufferX, bufferY, pdfWidth, pdfHeight, undefined, 'FAST');
return doc;
}).then((doc) => {
doc.save('postres.pdf');
});
}
}
app.component.html
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'sampleproject';
}
You can do it using an output/eventEmitter on your parent component, but you would need to include the <app-header> in the home component rather than the app component.
If you want to keep the <app-header> in the app component you'll need another approach, potentially using a service to communicate between the header and the home components.
header.component.html
<button (click)="downloadClicked.emit(null)" type="button" class="btn btn-primary">Download</button>
header.component.ts
export class HeaderComponent implements OnInit {
#Output()
downloadClicked: EventEmitter<any> = new EventEmitter();
constructor(public router: Router){}
ngOnInit() {
}
}
home.component.ts
<app-header (downloadClicked)="generarPDF()"></app-header>
<div class="container-fluid" id="content">
...
app.component.html
<router-outlet></router-outlet>
<app-footer></app-footer>
I am Using Angular 7. i run this cmd ng build --prod build for protection.
That time i am caching this Error( Property 'service' is private and only accessible within class 'LoginComponent'):
ERROR in src\app\login\login.component.html(5,33): : Property 'service' is private and only accessible within class 'LoginComponent'.
src\app\login\login.component.html(18,104): : Property 'service' is private and only accessible within class 'LoginComponent'.
It's my HTML Code:
<div id="login_section" class="d-flex justify-content-center align-items-center">
<div class="login_cnt col-8 row">
<div class="col-6 d-flex justify-content-center py-4">
<form class="col-8" [formGroup]="service.loginform">
<h2 class="text-center">User Login</h2>
<mat-form-field class="col-12">
<input matInput type="text" placeholder="Username" formControlName="username" >
<mat-error>Username is Required</mat-error>
</mat-form-field>
<mat-form-field class="col-12">
<input matInput [type]="hide ? 'password' : 'text'" formControlName="password" placeholder="Password">
<mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
<mat-error>Password is Required</mat-error>
</mat-form-field>
Forgot Password
<button mat-raised-button color="primary" class="float-right" [routerLink]="['/home']" [disabled]="service.loginform.invalid">Login</button>
</form>
</div>
</div>
</div>
It's My TS File:
import { Component, OnInit } from '#angular/core';
import { LoginService } from '../shared/login.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
username : string;
password: string;
hide = true;
constructor(private service: LoginService) { }
ngOnInit() {
}
}
when running ng serve am not catching it .
There are 2 ways to resolve this.
1.
Change private service: LoginService to public service: LoginService
As you are using AOT during compilation, you can not access private properties of your component in your HTML template.
2.
If you want to keep your service private, you can provide a public method in the controller which returns the service properties. You can call this method from your HTML template. It would be something like this:
Template:
<div id="login_section" class="d-flex justify-content-center align-items-center">
<div class="login_cnt col-8 row">
<div class="col-6 d-flex justify-content-center py-4">
<form class="col-8" [formGroup]="getLoginForm()"> <!-- Change here-->
<h2 class="text-center">User Login</h2>
<mat-form-field class="col-12">
<input matInput type="text" placeholder="Username" formControlName="username" >
<mat-error>Username is Required</mat-error>
</mat-form-field>
<mat-form-field class="col-12">
<input matInput [type]="hide ? 'password' : 'text'" formControlName="password" placeholder="Password">
<mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
<mat-error>Password is Required</mat-error>
</mat-form-field>
Forgot Password
<button mat-raised-button color="primary" class="float-right" [routerLink]="['/home']" [disabled]="getLoginForm().invalid">Login</button> <!-- Change here-->
</form>
</div>
</div>
</div>
Controller:
import { Component, OnInit } from '#angular/core';
import { LoginService } from '../shared/login.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
username : string;
password: string;
hide = true;
constructor(private service: LoginService) { }
ngOnInit() {
}
getLoginForm() {
return this.service.loginform;
}
}
P.S: I have not tested the second one myself for the moment.
You need to make your access specifier to be public to make it accessible
constructor(public service: LoginService) { }
Seems that you're using Ahead-of-Time compilation (while build), and you're trying to access a private member (service) of the component in its template [disabled]="service.loginform.invalid", service.loginform. But it must be public in the case of using it in template and ahead-of-time compilation:
constructor(private service: LoginService) { }
should be:
// your component: change private service to public service
constructor(public service: LoginService) { }
// then you can use it like this in the template of your component:
[formGroup]="service.loginform"
[disabled]="service.loginform.invalid"
If you need a service be private and still need to use some of its members in the template of your component, use get or other methods (public) to return that members:
// your component
constructor(private service: LoginService) { }
get loginForm() {
return this.service.loginform;
}
get loginIsInvalid(): boolean {
return this.service.loginform.invalid;
}
// then in the template of your component you can use:
[formGroup]="loginform"
[disabled]="loginIsInvalid"
Do you have concerns about having to call a function instead of using just a variable in the template?
Catch this self-executing function tip:
Template:
<form class="col-8" [formGroup]="loginform"> <!-- Change here-->
Controller:
import { Component, OnInit } from '#angular/core';
import { LoginService } from '../shared/login.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
username : string;
password: string;
hide = true;
constructor(private service: LoginService) { }
ngOnInit() {
}
loginform = (() -> this.service.loginform)(); /* Change here */
}
This can be useful if you need to access some internal fields of that variable inside the template.
<form class="col-8" [formGroup]="loginform.SOME_FIELD.INNER_PROP">
instead of
<form class="col-8" [formGroup]="getLoginForm().SOME_FIELD.INNER_PROP">
It looks more convenient and readable, imho.
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>
you can access it in ngOnInit() just implement OnInit interface