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.
Related
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>();
I am trying to practice behaviorsubject in angular 5. I am written a small app with two components and want to change the value in both of them at once but the value is not changing. BehaviorSubject should change the value in all the components. Please help me understand.
Service
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class TestserviceService {
public isAdmin = new BehaviorSubject<boolean>(false);
cast = this.isAdmin.asObservable();
constructor() { }
changeAdmin(){
this.isAdmin.next(!this.isAdmin);
}
}
Component One
import { Component, OnInit } from '#angular/core';
import{ TestserviceService } from '../../testservice.service';
#Component({
selector: 'app-one',
templateUrl: './one.component.html',
styleUrls: ['./one.component.css']
})
export class OneComponent implements OnInit {
isAdmin: boolean;
constructor(private testservice: TestserviceService) { }
ngOnInit() {
this.testservice.cast.subscribe(data => this.isAdmin = data);
}
changeValue(){
this.testservice.changeAdmin();
console.log(this.isAdmin);
}
}
Component One html
<button (click)="changeValue()">Click Me</button>
<p>
one {{isAdmin}}
</p>
Component Two
import { Component, OnInit } from '#angular/core';
import { TestserviceService } from '../../testservice.service';
#Component({
selector: 'app-two',
templateUrl: './two.component.html',
styleUrls: ['./two.component.css']
})
export class TwoComponent implements OnInit {
isAdmin: boolean;
constructor(private testservice: TestserviceService) { }
ngOnInit() {
this.testservice.cast.subscribe(data => this.isAdmin = data);
console.log("two "+this.isAdmin);
}
}
changeAdmin(){
this.isAdmin.next(!this.isAdmin);
}
Should be
changeAdmin(){
this.isAdmin.next(!this.isAdmin.value);
}
this.isAdmin is a BehaviorSubject and you were trying to set !thisAdmin which evaluates to false
Stackblitz
Change your service to :
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class SharedServiceService {
constructor() { }
public isAdmin = new BehaviorSubject<boolean>(false);
cast = this.isAdmin.asObservable();
changeAdmin(){
this.isAdmin.next(!this.isAdmin.value);
}
}
It should be this.isAdmin.value because this.admin will only be behaviourSubject's object
Live Demo
Im having some trouble figuring this out, basically I have a headerTitleService which I want to be able to dynamically set the title in my header component but for some reason when I set the title nothing shows up? Im not getting any errors so I can seem to figure out what the problem is..
headerTitle.service.ts
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class HeaderTitleService {
title = new BehaviorSubject('');
constructor() { }
setTitle(title: string) {
this.title.next(title);
}
}
header.component.ts
import { Component, OnInit } from '#angular/core';
import { HeaderTitleService } from '../../../services/headerTitle.service'
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
providers: [HeaderTitleService]
})
export class HeaderComponent implements OnInit {
title: string;
constructor(
private headerTitleService: HeaderTitleService
) { }
ngOnInit() {
this.headerTitleService.title.subscribe(updatedTitle => {
this.title = updatedTitle;
});
}
}
header.component.html
<h1>{{title}}</h1>
home.component.ts
import { Component, OnInit } from '#angular/core';
import { HeaderTitleService } from '../../services/headerTitle.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
providers: [HeaderTitleService]
})
export class HomeComponent implements OnInit {
constructor(
private headerTitleService: HeaderTitleService
) { }
ngOnInit() {
this.headerTitleService.setTitle('hello');
}
}
The line providers: [HeaderTitleService] in each component means that they will be given one HeaderTitleService each, rather than one between them.
To fix this remove providers: [HeaderTitleService] from your components, and place it in your module definition instead:
#NgModule({
providers: [HeaderTitleService]
})
Move HeaderTitleService in providers of your module. With your implementation you receive new instance of the HeaderTitleService in each component.
Hope this helps.
I recently ran into a problem and can't really figure out what's wrong with my code at this point, hopefully someone of you can help me.
All I am trying to do is changing the value of my BehaviorSubject with a function but it isn't working out.
chat.service.ts
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class ChatService {
chatId = new BehaviorSubject<number>(0);
constructor() {
this.chatId.next(1);
}
changeChatId(chatId: number) {
console.log(chatId);
this.chatId.next(chatId);
}
}
So the subscribers get the default as well as the changed chatId from the constructor. But as soon as I try to change it with the changeChatId function nothing happens at all. The right id's get passed into the function I already debugged that but the line this.chatId.next(chatId) doesn't seem to do anything.
ADD
These are the other components the service is currently used in.
chat-message-list
import { Component, OnInit, Input} from '#angular/core';
import { ChatService } from "../../../shared/services/chat.service";
#Component({
selector: 'app-chat-message-list',
templateUrl: './chat-message-list.component.html',
styleUrls: ['./chat-message-list.component.css'],
providers: [ChatService]
})
export class ChatMessageListComponent implements OnInit {
chatId: number;
constructor(private chat: ChatService) { }
ngOnInit() {
this.chat.chatId.subscribe(
chatId => this.updateMessageList(chatId)
);
}
}
chat-item
import { Component, OnInit, Input} from '#angular/core';
import { User } from '../../../shared/models/user.model';
import { ChatService } from '../../../shared/services/chat.service';
#Component({
selector: 'app-chat-list-item',
templateUrl: './chat-list-item.component.html',
styleUrls: ['./chat-list-item.component.css'],
providers: [ChatService]
})
export class ChatListItemComponent implements OnInit {
#Input()
user: User;
constructor(private chat: ChatService) { }
ngOnInit() {
}
onChatItemSelected(){
this.chat.changeChatId(this.user.id);
}
}
You need to make your ChatService a singleton (shared) service. Add it to the providers of your ngModule. This allows all the components that use the ChatService to share the same service instance.
#NgModule({
providers: [ChatService]
})
And remove it from your components providers. When you are adding it to your components providers, that component gets its own instance of ChatService which can not be used by other components.
This is my .ts file
import { Component, OnInit } from '#angular/core';
import { AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2/database';
#Component({
selector: 'app-candidate-reg-success',
templateUrl: './candidate-reg-success.component.html',
styleUrls: ['./candidate-reg-success.component.css']
})
export class CandidateRegSuccessComponent implements OnInit {
constructor() {
debugger;
const rootRef=firebase.database.ref();
const mail=rootRef.child('candidates_list').orderByChild('email').equalTo('pranavkeke#gmail.com');
console.log(mail);
}
ngOnInit() {
}
}
I am trying to query the user from candidates_list table which has the email address pranavkeke#gmail.com.
But I am unable to console it. It shows a error like
Property 'ref' does not exist on type 'typeof database'.
Any solution to query angular firebase database?
you need to inject the AngularFirebaseData in constructor and change the code and try again
import { Component, OnInit } from '#angular/core';
import { AngularFireDatabase, FirebaseListObservable,
FirebaseObjectObservable } from 'angularfire2/database';
#Component({
selector: 'app-candidate-reg-success',
templateUrl: './candidate-reg-success.component.html',
styleUrls: ['./candidate-reg-success.component.css']
})
export class CandidateRegSuccessComponent implements OnInit {
constructor(public db: AngularFireDatabase) {
debugger;
db.list('/candidates_list', ref => ref.orderByChild('email').equalTo('pranavkeke#gmail.com'));
}
ngOnInit() {
}}