Angular Material Data Table component is not live streaming - javascript

I'm using Angular Material Data Table in my project. The table is rendering with data
My problem is that I can't update automatically the view when I add new data to the database, every time I should refresh my page.
According to Cdk-table and after reading this tutorial I tried to add live data streaming that to table:
Here's my logique :
import { Component, OnInit } from "#angular/core";
import { MatTableDataSource } from "#angular/material";
import { AjoutprojService } from "../ajoutproj.service";
import { NouveauProjet } from "../models/nouveau-projet";
import { Observable } from "rxjs/Observable";
import 'rxjs/add/observable/merge';
import { DataSource } from "#angular/cdk/collections";
#Component({
selector: "app-liste-projets",
templateUrl: "./liste-projets.component.html",
styleUrls: ["./liste-projets.component.css"]
})
export class ListeProjetsComponent implements OnInit {
constructor( private ajoutProj: AjoutprojService ) {}
nouveauProjet: NouveauProjet[];
nouveauProjet2: NouveauProjet[];
stateExression: string = "inactive";
ngOnInit() {}
displayedColumns = ["Nom projet", "Lead Projet", "effectif"];
dataSource = new UserDataSource(this.ajoutProj);
applyFilter(filterValue: string) {
filterValue = filterValue.trim(); // Remove whitespace
filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches
//this.dataSource.filter = filterValue;
}
}
export class UserDataSource extends DataSource<any> {
constructor(private ajoutProj: AjoutprojService) {
super();
}
/*returns an observable that emits an array of data.
Whenever the data source emits data to this stream, the table will render an update.*/
connect(): Observable<NouveauProjet[]> {
return this.ajoutProj.getAllProj();
}
disconnect() {}
}
Here's my service
getAllProj(): Observable<NouveauProjet[]> {
return this.http.get<NouveauProjet[]>(
"http://127.0.0.1:8081/api/proj/projets"
);
}
ajoutProj.getAllProj() service is getting right data. but view is not live updating.

HttpClient doesn't stream. You're getting your data only once.

First you'd need a realtime database / backend solution, then you need to connect to that via websocket and listen to changes in the database.
Some frameworks / libraries that I like and package both the client- and serverside of the equation, and make the whole thing a lot easier:
Fireloop - built on top of Loopback 3 on nodejs, provides Angular SDK creation, ie. same models and APIs on client as on server. Typescript, Observables all the way. It's just awesome.
Firebase - "backendless", totally different way of thinking about a "server" from any REST scheme you might be used to.
Meteor - a monolithic framework, probably also very far from what you're used to.
Of course there's always another (very inefficient) way: Poll your DB every X seconds for changes.
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/switchMap';
export class UserDataSource extends DataSource<any> {
constructor(private ajoutProj: AjoutprojService) {
super();
}
connect(): Observable<NouveauProjet[]> {
const initialDelay = 0; // Time to wait before first poll, after the table has connected to this DataSource
const period = 10000; // Polling period in milliseconds
return Observable.timer(initialDelay, period)
.switchMap(() => this.ajoutProj.getAllProj());
}
disconnect() {}
}

Related

Updating Angular DOM immediately after editing data and retrieving from the database

Am working on a Single page Application built using Angular 8 on the frontend and Laravel on the backend. It is a CRUD application, on the delete functionality, it is working well by deleting the user of the specific id on the database. After the user of the specific id is deleted, am fetching all the products from the database but I want to update the data on the U.I afresh with the new data (excluding the deleted resource).
Kindly assist?
Show.component.ts file
import { Component, OnInit , ViewChild, ElementRef} from '#angular/core';
import { SharedService } from 'src/app/Services/shared.service';
import { AuthService } from 'src/app/Services/auth.service';
import { Router } from '#angular/router';
import { Observable } from 'rxjs';
import { SnotifyService } from 'ng-snotify';
#Component({
selector: 'app-show',
templateUrl: './show.component.html',
styleUrls: ['./show.component.css']
})
export class ShowComponent implements OnInit {
public userData : any[];
public error = null;
constructor(
private Shared : SharedService,
private Auth:AuthService,
private router: Router,
private Notify:SnotifyService
) { }
//Update the data when the DOM loads
ngOnInit() {
this.Shared.checkAll$.subscribe(message => this.userData = message);
}
//Method called when the delete button is triggered from the html
//Inside it we submit the data to the backend via a service and get
//the response
deleteUser(id:number){
return this.Auth.delete(id).subscribe(
data => this.handleDeleteResponse(data),
error => this.handleDeleteError(error)
);
}
//data below contains data from the backend after successful deletion
handleDeleteResponse(data:any){
this.Notify.success(`Successfully Deleted in our records`, {timeout:4000});
}
handleDeleteError(error:any){
console.log(error);
}
}
In you’re handleDeleteResponse method, there is a data if the data is the userData this.userData = data or it’s simple delete the user id from the array in you’re Js in the subscription of your delete method.
Like:
this.userData = this.userData.filter(user => user.id !== idToDelete )
Method 1:
Define a Subject in your service and subscribe to that subject in the service to receive the data. In the component, change the lifecycle hook to 'onChanges'. As soon as the data in the Subject is received/updated (with the deleted records) ngChanges shall reflect it in the DOM.
Method 2:
Track the records on the front-end in the form of list and when the service gives the response of delete as success then delete that very record in the list using ID or any other unique identifier. In this case you need not to populate all the records again.
export class MyComponent implements OnInit, OnChanges {
ngOnChanges() {
// code here
}
ngOnInit() {
// code here
}
}

How to send array in router navigate?

Searched for a solution in other questions but nothing helped me..
I wish to redirect to url like,
this.router.navigateByUrl('/products');
In which i need to pass the array and need to get it it in the component which has the active link products using skip location change without showing anything in url.
Array will be like,
products = [{"id":1,"name":"Product One","id":2,"name":"Product Three","id":3,"name":"Product Six"}]
I need to pass this entire array in router link and need to retrieve it in another component (products) active link using skipLocation Change true..
Tried with sharedService but i am getting issue of data loading at right point of time and hence i decided to use via router link..
If this is not a good approach, kindly suggest other alternative without using sharedservice..
You can use Angular Services for a large data.
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class ExampleService {
private subject = new Subject<any>();
updateRouteData(data) {
this.subject.next(data);
}
routeData(): Observable<any> {
return this.subject.asObservable();
}
}
In your components;
For set route data;
import { ExampleService } from '/example.service'
export class ComponentOne{
constructor(private exampleService:ExampleService){
this.exampleService.updateRouteData(data)
}
You can pass data like;
import { ExampleService } from '/example.service'
export class ComponentTwo{
constructor(private exampleService:ExampleService){
this.exampleService.routeData().subscribe(data => {
console.log(data)
})
}

NodeJS, Angular 2 | Executing method on Observable next

I'm currently getting started with Angular 2 and got stuck on something probably pretty simple:
I have a shared service chatMessageService.ts:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class ChatMessageService {
private messageList = new BehaviorSubject<string>("");
currentMessage = this.messageList.asObservable();
constructor() {
}
public addMessage(msg:string) {
this.messageList.next(msg) }
}
The service is imported by two components, one that calls it's addMessage function to add the message to the Observable and then my chatComponent.ts looks like this (shortened fpr convinience):
import { Component } from '#angular/core';
import { Message } from './message';
import { ChatMessageService } from './chatMessage.service';
#Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.css']
})
export class ChatComponent {
conversation: Message[] = [];
//.....
constructor(private chatMessageService: ChatMessageService) { }
addUserMessage(message) {
this.conversation.push({
content: message
});
}
ngOnInit() {
this.chatMessageService.currentMessage.subscribe(message => {this.addUserMessage(message);} )
}
}
My crisis arises at that last subscripion part. When I replace
{this.addUserMessage(message);}
with
{console.log(message)}
the message is printed out perfectly fine. If I call the addUserMessage()-method manually it works just fine. But when I call the method right there, with the message as argument, nothing happens. The method isn't even executed?
Thankful for your insights!
It looks like you need some buffering in the service.
Instead of BehaviorSubject, try
private messageList = new ReplaySubject<string>(10);
See working example: Plunker

How to update the view after my observable stream changes in angular2?

I have one service in which I have setup a stream.
import {Injectable} from '#angular/core'
import {Subject} from 'rxjs/Subject';
import { Column } from './../../column.model';
#Injectable()
export class ColumnService {
selectedColumnInstance:Column = new Column();
// Observable selectColumn source
private selectColumnSource = new Subject<Column>();
// Observable selectColumn stream
selectColumn$ = this.selectColumnSource.asObservable();
// service command
selectColumn(column:Column) {
console.log(column);
this.selectedColumnInstance=column;
this.selectColumnSource.next(column);
}
}
I am updating this stream as:
this.rapidColumnService.selectColumn(this.selectedCol); //selectedCol is new value
Now I have a component which loads its childComponent if this columnStream is having any value:
designer.component.html
<div class="col-md-3" *ngIf="selectedComponent">
<editor component-name="value-editor" [(model)]="selectedComponent.model"></editor>
</div>
Now Inside my designer.component.ts, I have subscribed to this stream inside ngOnInit() lifecycle hook.
ngOnInit() {
this.subscriptionColumn = this.rapidColumnService.selectColumn$.subscribe(
selectedComponent => {
this.selectedComponent = selectedComponent;
});
}
So far so good, If I am in designerComponent , then every time I am updating column in service , the view changes.
But as soon as I redirect to other component and redirect to designer again I am not able to load the editor component.
I can see the stream getting updated in service.
I want to load editor-component every time stream gets updated.
is it the router issue?
any inputs?
thanks & regards.

angular 2 subscribe shareService working twice or several times

I have a ShareService in angular 2,
******************************shareService*************************
import { BehaviorSubject , Subject} from 'rxjs/Rx';
import { Injectable } from '#angular/core';
#Injectable()
export class shareService {
isLogin$:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
CheckUser = this.isLogin$.asObservable();
public isLogin (bool){
this.isLogin$.next(bool);
}
}
and its my another component and subscibe the CheckUser;
***********************another Component*******************************
_shareService.CheckUser.subscribe((val) =>{
*********all of this scope execute for several times just i have one another component and one next function*******
this.isLogin = val;
alert(val);
if(this.isLogin){
console.log("req req req");
this.MyBasket();
}
else if(this.ext.CheckLocalStorage("ShopItems")){
this.ShopItems = JSON.parse(localStorage.getItem("ShopItems"));
setTimeout(() => {
_shareService.sendShopItems(this.ShopItems);
},100);
}
});
my problem is i execute once this.isLogin$.next(bool) but subscribe function execute twice or several times !!!! my basket function is an xhr request this means when user loged in i get the several request to server!!!i cant fix it...i dont know this problem is for angular 2 or not,Anyone have this problem??
last a few days i Involved in this problem!
The problem is that your shareService is getting multiple instances.
One of the solutions is forcing the service to be a singleton.
Something like this should work:
import { provide, Injectable } from '#angular/core';
#Injectable()
export class shareService {
private static instance: shareService = null;
// Return the instance of the service
public static getInstance(/*Constructor args*/): shareService {
if (shareService.instance === null) {
shareService.instance = new shareService(/*Constructor args*/);
}
return shareService.instance;
}
constructor(/*Constructor args*/) {}
}
export const SHARE_SERVICE_PROVIDER = [
provide(shareService, {
deps: [/*Constructor args dependencies*/],
useFactory: (/*Constructor args*/): shareService => {
return shareService.getInstance(/*Constructor args*/);
}
})
];
Everything that is required on your current constructor should be placed where it says constructor args
Now on your components you use the service like this:
#Component({
providers: [SHARE_SERVICE_PROVIDER]
})
And then you can call it like you usually do.
Another solution would be injecting your current service on the main component of the app. See here for more info.
The problem is that the service is singleton and the component subscribe to it each time it created or (I don't see the full code) at the point the
_shareService.CheckUser.subscribe
is placed , so CheckUser should be a method that returns an Observable . if you have plunkr I can edit it .
Another semantic problem is that the observable should end with $ and not the BehaviorSubject.

Categories