So I try to communicate between components with ngAfterViewInit.
And I want to use the property
participant: ParticipantInfoDTO;
also using in other component. So I try it like this
#Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss'],
template: 'Example: {{participant}}<app-echeq-selector></app-echeq-selector>'
})
export class DetailComponent implements OnInit, AfterViewInit {
#ViewChild(EcheqSelectorComponent) echeqReference: ParticipantInfoDTO;
participant: ParticipantInfoDTO;
constructor(private dialog: MatDialog, route: ActivatedRoute) {
this.participant = route.snapshot.data['participant'];
}
ngOnInit() {
}
ngAfterViewInit(): void {
this.participant = this.echeqReference;
}
}
And in child component(EcheqSelectorComponent) I want it using like this:
<p> selected id:{{participant}} </p>
But I get an error on this line:
#Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss'],
template: 'Example: {{participant}}<app-echeq-selector></app-echeq-selector>'
})
saying:
Component 'DetailComponent' must not have both template and
templateUrlng(0)
Thank you
Remove template property in your component decorator.
In detail.component.html, add all the elements you want so that your html file looks like this:
Example: {{participant}}<app-echeq-selector></app-echeq-selector>
If you want to pass a property to app-echeq-selector component then you can use property binding like this:
<app-echeq-selector [participant]="participant"></app-echeq-selector>
In echeq component.ts:
export class echeq... {
#Input() participant;
// you can use this participant property as you want now.
}
Related
When I use #ViewChild I get the error that the component is not defined.
When I use #ViewChildren I get the error that the function from that component is not a function.
I am new to using child components in Angular so I'm not sure why it's doing this when I do have the child component defined in the parent component and when it's clearly a function in the child component.
I don't want to have to define every function from the child in the parent or else what's even the point of using a separate component.
Child Component
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-mood',
templateUrl: './mood.component.html',
styleUrls: ['./mood.component.css']
})
export class MoodComponent implements OnInit {
moodColors = ['red', 'orange', 'grey', 'yellow', 'green'];
constructor() { }
ngOnInit(): void {
}
chooseMood() {
alert(this.moodColors);
}
}
Parent Component (Relavant Part of Version with "ERROR TypeError: ctx_r3.mood is undefined")
import { Component, OnInit, ViewChild, ViewChildren } from '#angular/core';
import { ViewEncapsulation } from '#angular/core';
import { MoodComponent } from '../mood/mood.component';
#Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.css'],
encapsulation: ViewEncapsulation.None
})
export class CalendarComponent implements OnInit {
#ViewChild('mood') mood: MoodComponent = new MoodComponent;
Parent Component (Relavant Part of Version with "ERROR TypeError: ctx_r3.mood.chooseMood is not a function")
import { Component, OnInit, ViewChild, ViewChildren } from '#angular/core';
import { ViewEncapsulation } from '#angular/core';
import { MoodComponent } from '../mood/mood.component';
#Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.css'],
encapsulation: ViewEncapsulation.None
})
export class CalendarComponent implements OnInit {
#ViewChildren('mood') mood: MoodComponent = new MoodComponent;
Parent View
<h2 (click)="mood.chooseMood()"></h2>
You don't explicitly initialize view children via new.
Just use:
#ViewChild('mood') mood : MoodComponent;
If that doesn't work post a Stackblitz example which I can edit to resolve the issue.
Also, using ViewChild is more of an exception in Angular, and your use of it points to a probable design issue. More likely you child component should emit via an Output to the parent.
Regarding outputs, you can do something like this - though it is hard to give a precise answer without deeper knowledge of what you are trying to achieve:
export class MoodComponent implements OnInit {
#Input() moodId: string;
#Output() chooseMood = new EventEmitter<string>();
moodClicked(){
this.chooseMood.emit(moodId);
}
}
export class CalendarComponent implements OnInit {
moodChosen(string: moodId){
console.log(moodId);
}
}
// Calendar template:
<app-mood
moodId="happy"
(chooseMood)="moodChosen($event)"
></app-mood>
1 - you have to use this code
#ViewChild('mood') mood : MoodComponent;
when you are using #ViewChildren it will return list of items with the 'mood' name then you have to use this code
mood.first.chooseMood() ;
its better use ViewChildren when there is ngIf in your element
2- no need new keyword for initialize mood variable
it would be fill after ngOnInit life cycle fires
Hi i am new to angular
this is my angular component
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
user = ""
constructor() { }
ngOnInit(): void {
}
}
Is there a way that I can execute a block of code whenever this user variable changes?
yes you can set condition on user or if the user is change from html then you can call that method on (change)="methodName()"
I tried to use instance of parent component in child component via constructor. In other words, I create instance of parent component class as private property and use its properties, methods etc.
Besides that, I can affect to values of parent component properties directly without using Input, Output decorators, event listeners etc.
Parent
#Component({
selector: 'parent-component',
templateUrl: './parent-component.component.html',
styleUrls: ['./parent-component.component.scss']
})
export class ParentComponent implements OnInit {
someParentProperty: number = 10;
constructor() {}
ngOnInit() {}
someParentMethod = (num) => num**2;
}
Child
import { ParentComponent } from '../parent-component';
#Component({
selector: 'child-component',
templateUrl: './child-component.component.html',
styleUrls: ['./child-component.component.scss']
})
export class ChildComponent implements OnInit {
someChildProperty: number;
constructor(pc: ParentComponent) {}
ngOnInit() {
this.someChildProperty = this.pc.someParentMethod(this.pc.someParentProperty);
}
}
That's rather comfortable, but I'm not sure, that it's a best practice and right approach.
Could someone explain minuses of this one?
Why don't you use a service?
So that you can access your required method from both child and parent components.
E.g: A common service:
#Injectable({
providedIn: 'root',
})
export class CommonService {
someParentMethod(num) {
return num**2;
}
}
At ParentComponent:
export class ParentComponent implements OnInit {
constructor(private commonService: CommonService) {}
ngOnInit() {
console.log(commonService.someParentMethod(2));
}
}
You can do the same at ChildComponent you can do the same.
It's the best way for sharing.
You can find detail about services here.
At work, I have run into a problem using Angular. I have this kind of Angular component:
#Component({
selector: 'foo',
templateUrl: 'foo.html'
})
export class FooComponent {
#Input() data: string;
content: string;
ngOnInit() {
this.content = this.data;
}
setValue(data) {
this.content = data;
}
}
This is initialized from my main Angular component in a code block such as this:
this.components = [FooComponent, BarComponent, BazComponent, QuuxComponent];
Now this works so far. But if I try to call the setValue() function with this.components[0].setValue("Hello world!"); I get an error "this.components[0].setValue is not a function."
What is the reason for this and how can I fix it?
This seems like a very very weird way to work with components in angular.
You really don't want to break encapsulation by calling methods inside one component from another component.
I personally haven't seen this kind of component referencing anywhere (and have doubts it is a correct approach).
There is no reason to duplicate the data property in the content.
You can pass values in the template. Or use a service if you don't have direct access to the template.
Here is a very basic example on how to modify data from the parent using a template and #Input.
app.component.ts
import { Component } from "#angular/core";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
message = "I am a message from the parent";
}
app.component.html
<app-child [content]='message'></app-child>
child.component.ts
import { Component, OnInit, Input } from "#angular/core";
#Component({
selector: "app-child",
templateUrl: "./child.component.html",
styleUrls: ["./child.component.css"]
})
export class ChildComponent implements OnInit {
#Input("content") public content: string;
constructor() {}
ngOnInit() {}
}
child.component.html
<p>{{content}}</p>
Angular app is compiling successfully but giving the following errors in 'ng build --prod'
ERROR in src\app\header\header.component.html(31,124): : Property 'searchText' does not exist on type 'HeaderComponent'.
src\app\dashboard\dashboard.component.html(3,72): : Property 'newsService' is private and only accessible within class 'DashboardComponent'.
src\app\dashboard\dashboard.component.html(3,72): : Property 'p' does not exist on type 'DashboardComponent'.
src\app\dashboard\dashboard.component.html(29,46): : Property 'p' does not exist on type 'DashboardComponent'.
I have used these properties in my html file as below:
header.component.htmlfile
<input type="text" class="form-control mr-2 align-self-center" required placeholder="Search" name="searchText" [ngModel]="searchText" value="">
dashboard.component.htmlfile
<pagination-controls class="text-center" (pageChange)="p = $event"></pagination-controls>
my header.component.html file
import { Component, OnInit, Output, EventEmitter, ViewEncapsulation } from '#angular/core';
import { NgForm } from '#angular/forms';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
filterText : string;
#Output() search = new EventEmitter();
#Output() filterButton = new EventEmitter();
constructor() { }
ngOnInit() {
}
onSubmit(form : NgForm)
{
console.log(form);
this.search.emit(form);
}
filterClicked($event)
{
this.filterText = $event.target.text;
this.filterButton.emit(this.filterText);
}
}
my dashboard.component.html file
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { NewsService } from '../shared/news.service';
import { NewsModel } from '../shared/news.model';
import { Form } from '#angular/forms';
import { Pipe, PipeTransform } from '#angular/core';
import { element } from 'protractor';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
articles : any;
temp : NewsModel = new NewsModel;
constructor(private newsService : NewsService) { }
ngOnInit() {
this.FetchHeadlines();
}
FetchHeadlines()
{
this.newsService.GetAllGaurdian()
.subscribe((result) =>
{
this.articles = result;
this.articles.response.results.forEach(element => {
this.newsService.newsArticles.push(this.newsService.CusotomMapper(element));
});
})
}
}
can't able to figure out where is the error exactly!
I think the error descriptions are as accurate as it can be. each of them tells you that something wrong with your component, lets examine each of them
ERROR:
ERROR in src\app\header\header.component.html(31,124): : Property 'searchText' does not exist on type 'HeaderComponent'.
you have searchText in HeaderComponent HTML, but not in the Component itself
SOLUTION: add searchText variable to the Component
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
searchText:string
...
}
ERROR :
src\app\dashboard\dashboard.component.html(3,72): : Property 'newsService' is private and only accessible within class 'DashboardComponent'.
all the fields you are using inside the template, must be the public field inside component itself, otherwise it will not compile
SOLUTION: change private modifier to public at newService
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
constructor(public newsService : NewsService) { }
...
}
ERRORS :
src\app\dashboard\dashboard.component.html(3,72): : Property 'p' does not exist on type 'DashboardComponent'.
src\app\dashboard\dashboard.component.html(29,46): : Property 'p' does not exist on type 'DashboardComponent'.
same as HeaderComponent. you are using p field but it's not defined in DashboardComponent
SOLUTION : add p field to the dashboard component
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
p:any
...
}
You are trying to access from the template, variables that aren't defined in the corresponding components.
In header.component.html you are setting [ngModel]="searchText" and variable searchText isn't defined on header.component.ts. Could it be filterText variable instead?
In dashboard.component.html you are setting p = $event and variable p isn't defined on dashboard.component.ts. You also have an error about newsService being private. If you are gonna use it in the template it must be declared public when you inyect it on the constructor. I hope this helps. If you need more help is better if you provide a Stackblitz with minimum code.