Access angular component meta-data - javascript

is it possible to get the value of e.g. changeDetection attribute defined as part of a given component's decoration?
import { Component, ChangeDetectionStrategy } from '#angular/core';
#Component({
selector: 'app-banner',
template: '<h1>{{title}}</h1>',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class BannerComponent { }
i've tried:
Reflect.getMetadataKeys(BannerComponent) // []
Reflect.getOwnMetadataKeys(BannerComponent) // []
Reflect.getMetadata('annotations', BannerComponent) // undefined
https://plnkr.co/edit/VXfcZH9BWPWbdyBOJRTV?p=preview

Seemingly hacky but nevertherless a solution:
BannerComponent['__annotations__'][0]
https://plnkr.co/edit/HAbomBljAACHVz6N33m5?p=preview
Credits this SO answer.

Related

Angular - trying to use child component function in parent view but I'm gettting an error

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

Problem calling one Angular component from another component

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>

Value undefined after a function

I have one class with one fuction in it, and another class that will import the first class and use that function. After the function operates i need one value, but i am not getting any value afte the function.
First class:
export class MoveEff {
checkEffect(effectFaceOff1,moveEff1,moveEff2){
if ( effectFaceOff1=== 'grassgrass') {
moveEff1 = 10;
console.log(moveEff1);
}
}
}
Second class :
import { Component, OnInit } from '#angular/core';
import {GenIService} from "../Pokemons/gen-i.service";
import {MovesService} from "../Moves/moves.service";
import {MoveDataClass} from "../MoveDATA/move-data-class";
import {MoveEff} from "../MoveDATA/move-eff";
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
effectFaceOff1;
moveEff1;
moveEff2;
constructor(private moveeff: MoveEff) {}
this.moveeff.checkEffect(this.effectFaceOff1,this.moveEff1,this.moveEff2);
console.log(this.moveEff1,this.moveEff2);
On the last console.log i should be seeing the 10 value of moveEff1, but it appears undefined.
Why? and how can i solve it?
Exporting the class may not be enough. Try exporting and importing all your methods as modules, or exporting the method directly.
i don't know where you are getting effectFaceOff1, moveEff1 and moveEff2 from, but if they are #Input, their values cannot be retrieved in the constructor.
In that case, you should move your code to the ngOnInit:
ngOnInit() {
this.moveeff.checkEffect(this.effectFaceOff1,this.moveEff1,this.moveEff2);
console.log(this.moveEff1,this.moveEff2);
}
Last but not least, MoveEff should be made an Injectable in order to provide it to your class:
#Injectable({ providedIn: 'root' })
export class MoveEff {
checkEffect(effectFaceOff1,moveEff1,moveEff2){
if ( effectFaceOff1 === 'grassgrass') {
moveEff1 = 10;
console.log(moveEff1);
}
}
}

How can I access an already transcluded ContentChild?

I have a angular component app-b that is used within a component app-a that is used in the app-component. The app-component has some content in app-a, app-a transcludes this with ng-content into app-b, app-b shows it with another ng-content - but how can I access this content within the component (and not it's template)?
I would think that ContentChild is the correct approach but appears to be wrong.
Example:
https://stackblitz.com/edit/angular-ddldwi
EDIT: Updated example
You cannot query by tag name with #ContentChild decorator. You can query either by template variable, component or directive selector.
app-a.component.html
<app-b>
<ng-content></ng-content>
<p #myContent>This is a content child for app-b.</p>
</app-b>
app-b.component.ts
import { Component, AfterContentInit, ContentChild } from '#angular/core';
#Component({
selector: 'app-b',
templateUrl: './b.component.html',
styleUrls: ['./b.component.css']
})
export class BComponent implements AfterContentInit {
#ContentChild('myContent') contentchild;
ngAfterContentInit() {
console.log(this.contentchild);
}
}
Live demo
I recommend sharing the data between components. For example, move your data (E.G. dummyName) into a service. Then add the service to each component (where you need the shared data).
Service:
import { Injectable } from '#angular/core';
#Injectable()
export class DataShareService {
public dummyName: String = 'one';
constructor() { }
}
Add the new service to app.module.ts:
providers: [DataShareService],
Child Component:
import { DataShareService } from './data-share.service';
import { Component } from '#angular/core';
#Component({
selector: 'app-child',
templateUrl: './child.component.html'
})
export class ChildComponent {
constructor(public ds: DataShareService) { }
toggle() {
this.ds.dummyName = this.ds.dummyName === 'one' ? 'two' : 'one';
}
}
Child Component template (html):
<p> {{ds.dummyName}}</p>
<button (click)="toggle()">Click Me to Toggle Value</button>
Parent Component:
import { Component, OnInit } from '#angular/core';
import { DataShareService } from './data-share.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
constructor(public ds: DataShareService) {}
displayNumber() {
return this.ds.dummyName === 'one' ? 1 : 2;
}
}
Parent Component template (html):
<p> this is the parent component:</p>
<div> value as string: {{ ds.dummyName }} </div>
<div> value as number: <span [textContent]="displayNumber()"></span></div>
<hr>
<p> this is the child component:</p>
<app-child></app-child>
Note! The child component toggle() function demonstrates how you can change the data. The parent component displayNumber() function demonstrates how to use the data, independent of it's display (I.E. as just pure data).
This appears to be impossible due to a bug in Angular:
https://github.com/angular/angular/issues/20810
Further reference:
https://www.reddit.com/r/Angular2/comments/8fb3ku/need_help_how_can_i_access_an_already_transcluded/

How to create nested components in Angular 4?

I have created a component called Parent and Child. I want to display all the UI of ChildComponent to my ParentComponent.
child.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
testContent = 'child component content...';
constructor() { }
ngOnInit() {
}
}
child.component.html
<p>{{testContent}}</p>
parent.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-admin',
templateUrl: './admin.component.html',
styleUrls: ['./admin.component.scss'],
directives: [ChildComponent]
})
export class AdminComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
parent.component.html
<div>
Lorem ipsum
<app-child></app-child>
</div>
I want to display the contents of child component inside parent component. However, I am encountering an error in Angular 4
"Object literal may only specify known properties, and 'directives'
does not exist in type 'Component'."
Do you have any idea what is the alternative property to add child component?
Remove directives from the parent component and add the child component to the module declarations array where the parent component lives.
Directives and pipes in #component are deprecated since angular RC6. Just remove it from the component.
#Component({
selector: 'app-admin',
templateUrl: './admin.component.html',
styleUrls: ['./admin.component.scss']
})

Categories

Resources