I am fairly new to the Angular world and working on angular 7, I am doing some examples where components share data within, The Parent to child part working fine but when i am trying to send any values from child to parent it's not working.
It shows me this error
app-component.html
<div>{{show}}</div>
<app-communicating-components [Parent]="message" (childEvent)="getMessage($event)"></app-communicating-components>
app-component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'AngularLesson2';
public message = 'Hello my child, Parents here';
public show: string;
getMessage($event) {
this.show = $event;
}
}
communicating-components.component.html
<p>
{{Parent}}
</p>
<button (click)="fireEvent()">Fire from child</button>
communicating-components.component.ts
import { Component, OnInit, Input, Output } from '#angular/core';
import { EventEmitter } from 'events';
#Component({
selector: 'app-communicating-components',
templateUrl: './communicating-components.component.html',
styleUrls: ['./communicating-components.component.css']
})
export class CommunicatingComponentsComponent implements OnInit {
#Input() Parent;
#Output() public childEvent = new EventEmitter();
constructor() {
}
ngOnInit() {
}
fireEvent() {
this.childEvent.emit('Hi, I am child');
console.log("event fire" + this.childEvent);
}
}
What am I doing wrong here?
I believe the problem is in your import import { EventEmitter } from 'events'; is not the one you should import here. Try changing the import to import { EventEmitter } from '#angular/core';
UPDATE
Here's a stackblitz example showing that it works
With Angular newer versions, like 8 you have to:
Import correctly Emitter as k.s. said:
import { EventEmitter } from '#angular/core'
Initialize the emitter for Output:
#Output()
emisor = new EventEmitter<type>();
Related
appcomp.html
`<app-child (callemit) = parentFunc($event)> </app-child>`
appcomp.ts
`
import { Component, OnInit, EventEmitter } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.comp.html'
})
export class AppComponent {
ngOnInit() {}
parentFunc(event){
console.log(event)
}
}
`
childcomp.html
childcomp.ts
`
#Component({
selector: 'app-child',
templateUrl: './app.child.component.html'
})
`
mydirective.ts
`
import { Directive, ElementRef, Input, Output, HostListener, EventEmitter } from '#angular/core';
#Directive({
selector: '[myDirective]'
})
export class myAppDirective {
constructor() {}
#Input ('myDirective') val: string;
#Output() callEmit = new EventEmitter();
#HostListener('click')
onClick() {
event.preventDefault();
this.callEmit.emit({event , val});
}
}
`
In the above code i am trying to call parentFunc from appcomp using eventemitter and not able to get this work. Please let me know what is wrong here.
I think you most call callEmit on child component
childcomp.html
and in child Component emit the CallEmit Which called from appComp
childcomp.ts
#Output() callEmit = new EventEmitter();
childFunc(){
this.callEmit.emit();
}
and finally use
appCom.html
`<app-child (callemit) = parentFunc($event)> </app-child>`
appcom.ts
parentFunc(event){
console.log(event)
}
https://stackblitz.com/edit/angular-exxhms
Try it on component
i created a new component in angular 2 with this:
ng g component todos
So it created the new component, I went to the component and I noted that I had a new folder with the files:
todos.component.css, todos.component.html, todos.component.spec.ts, todos.component.ts
Then I openened todos.component.ts and it had:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-todos',
templateUrl: './todos.component.html',
styleUrls: ['./todos.component.css']
})
export class TodosComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
Then I put the new second line because I am learning with a tutorial:
import { Component, OnInit } from '#angular/core';
import { TodosComponent } from './todos/todos.component';
#Component({
selector: 'app-todos',
templateUrl: './todos.component.html',
styleUrls: ['./todos.component.css']
})
export class TodosComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
When I did that and I ran the server it showed me this:
Failed to compile.
C:/angular2/proyecto/src/app/todos/todos.component.ts (2,10): Individual declarations in merged declaration 'TodosComponent' must be all exported or all local.
I'd like to know what is it bad? why does it show that error?
Thanks!
You are importing the class into it's own file.
No need to import your own component, you should import it in other files, where you use it.
I want to add some text in showlist.component.html. My code is given below, I am not aware how to use document.body in Angular 2.
import { Component, OnInit } from '#angular/core';
import { DOCUMENT } from '#angular/platform-browser';
#Component({
selector: 'app-showlist',
templateUrl: './showlist.component.html',
styleUrls: ['./showlist.component.css']
})
export class ShowlistComponent implements OnInit {
public myname = "saurabh";
constructor() { }
ngOnInit() {
//this.myname.appendTo(document.body);
document.body(this.myname);
//document.write(this.myname);
}
}
you do the following to access the document.body
import { Component, OnInit, Inject } from '#angular/core';
import { DOCUMENT } from '#angular/common';
#Component({
selector: 'app-showlist',
templateUrl: './showlist.component.html',
styleUrls: ['./showlist.component.css']
})
export class ShowlistComponent implements OnInit {
public myname = "saurabh";
constructor(#Inject(DOCUMENT) private document: Document) {}
ngOnInit() {
this.document.body.innerHTML = this.myname;
}
}
I am trying to implement angular2-virtual-scroll in an angular4 project. Firstly, can anyone confirm if I would have a problem implementing it in NG4. I don't think I should and I haven't seen any notices to the contrary. Secondly I am using an observable instead of a promise shown in the NPM angular2-virtual-scroll docs. However, when I applied the virtual-scroll tag there is no change in my output...no scroll bar ..the data from the observable is displayed but no scrolling. The following are the relevant code segments:
Home.component.html
<h1 style="color: #76323f">
{{title}}
</h1>
<h4>
{{description}}
</h4>
<h2>Coming Soon....</h2>
<app-events-list [upcomingEvents]="upcomingEvents"></app-events-list>
home.component.ts
import {Component, OnInit,OnDestroy } from '#angular/core';
import {UpcomingEvent} from './../../interface/upcomingevent';
import {EventService} from './../../services/event.service';
import {Subscription} from 'rxjs/Subscription';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit, OnDestroy {
upcomingEvents: Array<UpcomingEvent>;
title = 'Welcome....';
description='Events promotions....';
eventServiceSub: Subscription;
constructor(private eventService: EventService){
this.upcomingEvents = [];
}
ngOnInit() {
this.eventServiceSub=this.eventService.getEvents().subscribe(upcomingEvents=>{this.upcomingEvents=upcomingEvents.slice(0,25);
});
}
ngOnDestroy(){
if (this.eventServiceSub){
this.eventServiceSub.unsubscribe();
}
}
}
event-list-component.html
<virtual-scroll [items]="items" (update)="upcomingEvents = $event"
(change)="onlistChange($event)">
<app-upcomingevent *ngFor="let upcomingEvent of upcomingEvents"[upcomingEvent]="upcomingEvent" [eventItemCss]="'event-item'"></app-upcomingevent>
<div *ngIf="loading" class="loader">Loading.....</div>
</virtual-scroll>
event-list-component.ts
import { Component, Input, OnDestroy, OnInit } from '#angular/core';
import { UpcomingEvent } from './../../interface/upcomingevent';
import { trigger,state,style,transition,animate,keyframes } from '#angular/animations';
import { ChangeEvent } from 'angular2-virtual-scroll';
import {EventService} from './../../services/event.service';
import {Subscription} from 'rxjs/Subscription';
#Component({
selector: 'app-events-list',
templateUrl: './events-list.component.html',
styleUrls: ['./events-list.component.css'],
animations: []
})
export class EventsListComponent implements OnInit, OnDestroy {
#Input()
upcomingEvents: Array<UpcomingEvent>;
items=this.upcomingEvents;
protected buffer: Array<UpcomingEvent> =[];
protected loading: boolean;
eventServiceSub: Subscription;
constructor(private eventService: EventService) {
this.upcomingEvents=[];
}
ngOnInit() {
}
ngOnDestroy(){
if (this.eventServiceSub){
this.eventServiceSub.unsubscribe();
}
}
protected onlistChange(event: ChangeEvent){
if (event.end !==this.buffer.length) return;
this.loading=true;
this.eventServiceSub=this.eventService.getEvents().subscribe(upcomingEvents=>{
this.buffer=upcomingEvents.slice(this.buffer.length,25);
this.loading=false;
}, ()=> this.loading=false);
}
}
eventService.ts
import { Injectable } from '#angular/core';
import {UpcomingEvent} from './../interface/upcomingevent'
import {Http} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class EventService {
constructor(private http: Http) { }
getEvents(): Observable<UpcomingEvent[]>
{
return this.http
.get(`https://jsonplaceholder.typicode.com/posts`)
.map(response => response.json() as UpcomingEvent[]);
}
}
upcomingEvents.html
<md-card [ngClass]="'event-item'">
<h4 [ngClass]="'event-title'" [ngStyle]="{'color':'purple'}"> {{upcomingEvent.title}}</h4>
<md-card-actions>
<button md-button>LIKE</button>
<button md-button>SHARE</button>
</md-card-actions>
</md-card>
upcomingEvents.component.ts
import { Component, Input,OnInit } from '#angular/core';
import { UpcomingEvent } from './../../interface/upcomingevent';
#Component({
selector: 'app-upcomingevent',
templateUrl: './upcomingevent.component.html',
styleUrls: ['./upcomingevent.component.css']
})
export class UpcomingeventComponent implements OnInit {
#Input()
upcomingEvent: UpcomingEvent;
#Input()
eventItemCss: string;
constructor() { }
ngOnInit() {
if (!this.upcomingEvent) {
this.upcomingEvent=<UpcomingEvent> {};
}
}
}
The way it suppose to work is that the HomeComponent request data from the eventService via an observable..the data is then passed to the eventList component where it is iterated on and pass to the upcomingEvents component to present via HTML. 25 events are requested at first and if the user scroll to the end another 25 is requested from the eventService...this time by the upcomingEvents component. I am not sure this is the most efficient way to do it but in either case it doesn't work. The virtual-scroll seems to have no effect on the output....I would really appreciate someone showing me what I am doing wrong....Thanks
I think I see a problem in your code. When using virtual-scroll you need to keep two arrays - one for all loaded data, and one for currently rendered items. Looks like you kinda mixed them up.
Let's call all-items-array as items and render-array - upcomingEvents
First chunk of items will be passed from the parent component, hence:
Home.component.html
...
<app-events-list [items]="upcomingEvents"></app-events-list>
event-list-component.html looks good
event-list-component.ts
import { Component, Input, OnDestroy, OnInit } from '#angular/core';
import { UpcomingEvent } from './../../interface/upcomingevent';
import { trigger,state,style,transition,animate,keyframes } from '#angular/animations';
import { ChangeEvent } from 'angular2-virtual-scroll';
import {EventService} from './../../services/event.service';
import {Subscription} from 'rxjs/Subscription';
#Component({
selector: 'app-events-list',
templateUrl: './events-list.component.html',
styleUrls: ['./events-list.component.css'],
animations: []
})
export class EventsListComponent implements OnInit, OnDestroy {
#Input()
items: Array<UpcomingEvent> = [];
upcomingEvents: Array<UpcomingEvent>;
protected loading: boolean;
eventServiceSub: Subscription;
constructor(private eventService: EventService) {
this.upcomingEvents=[];
}
ngOnInit() {
}
ngOnDestroy(){
if (this.eventServiceSub){
this.eventServiceSub.unsubscribe();
}
}
protected onlistChange(event: ChangeEvent){
if (event.end !==this.items.length) return;
this.loading=true;
this.eventServiceSub=this.eventService.getEvents().subscribe(upcomingEvents=>{
this.items=upcomingEvents.slice(0, this.items.length + 25);
this.loading=false;
}, ()=> this.loading=false);
}
}
warning! code not tested, I simply edited your code.
i'm learning angular 2, and i follow this tutorial: https://egghead.io/lessons/angular-2-angular-2-building-a-toggle-button-component
but the whole part of the output and eventemitter doesn't work.
i do not get any errors and i can't figure out why it doesn't work.
this is my code for the togglelink component:
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'app-togglelink',
templateUrl: 'togglelink.component.html',
styleUrls: ['togglelink.component.css']
})
export class TogglelinkComponent implements OnInit {
#Input() state:boolean = true;
#Output() onChange = new EventEmitter();
onClick(){
this.state = !this.state;
this.onChange.emit(this.state);
}
constructor() {}
ngOnInit() {
}
}
and this is the code for the firstpage component that uses the togglelink component:
import { Component, OnInit } from '#angular/core';
import {TogglelinkComponent} from '../togglelink/togglelink.component';
#Component({
moduleId: module.id,
selector: 'app-firstpage',
templateUrl: 'firstpage.component.html',
styleUrls: ['firstpage.component.css'],
directives: [TogglelinkComponent]
})
export class FirstpageComponent implements OnInit {
thetogglestate:boolean = false;
firsttitle = "the first title";
constructor() {}
ngOnInit() {
}
}
and this is the code for the template of the firstpage component:
{{thetogglestate ? 'On' : 'Off'}}
</p>
<h2 *ngIf="thetogglestate">
{{firsttitle}}
</h2>
<p>
firstpage works!
</p>
when i change manually thetogglestate it does work, so i understand that the issue is with the output and the eventemitter part.
any idea why?
best regards
In the firstpage.component.html template, you need to register some processing for this event to toggle the value of the thetogglestate variable.
Something like that:
<app-togglelink (onChange)="thetogglestate = !thetogglestate"></app-togglelink>