I am working on a shopping cart application. I'm facing issue while displaying the user selected products in the cart.component.html, as the data is not rendering. DOM is being created every time but the data is not displaying in the cart.component.html ? can anyone suggest how to solve this problem ?
cart.component.html
`
<ng-container *ngIf="products.length !=0">
<div class="container">
<div class="card-table">
<div class="cart-product">
<table class="table table-responsive">
<thead>
<tr>
<th>Sr.No</th>
<th>Product Name</th>
<th>Product Image</th>
<th>Description</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<!-- <th>Action</th> -->
</tr>
</thead>
<tbody>
<tr *ngFor="let item of products; let i = index">
<td>{{ i + 1 }}</td>
<td>{{ item.title }}</td>
<td>
<img style="width: 120px" src="{{ item.image }}" alt="" />
</td>
<td style="width: 25%">{{ item.description }}</td>
<th style="width: 12%">{{ item.price }}</th>
<td style="width: 12%">{{ item.quantity }}</td>
<td style="width: 12%">{{ item.total }}</td>
<td>
<!-- <button (click)="removeItem(item)" class="btn btn-danger"><i class="fas fa-trash-alt"></i></button> -->
<!-- </td> -->
</td>
</tr>
<tr>
<td colspan="4"></td>
<!-- <td><button (click)="emptycart()" class="btn btn-danger">Empty Cart</button></td> -->
<td>
<button routerLink="/products" class="btn btn-primary">
Shop More
</button>
</td>
<!-- <td><button class="btn btn-success">Checkout</button></td> -->
<td>
<strong>Grand Total : ${{ grandTotal }}</strong>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</ng-container>
<ng-container *ngIf="products.length == 0">
<div class="container">
<div class="card">
<h5 class="card-title">My Cart</h5>
</div>
<div class="center">
<img
src="https://rukminim1.flixcart.com/www/800/800/promos/16/05/2019/d438a32e-765a-4d8b-b4a6-520b560971e8.png?q=90"
alt=""
/>
<h4>Your cart is empty!</h4>
<h6>Add item to it now</h6>
<button routerLink="/products" class="btn btn-primary">Shop Now</button>
</div>
</div>
</ng-container>
cart.component.ts
`
import { Component, OnInit } from '#angular/core';
import { NavbarserviceService } from 'src/app/navbarservice.service';
import { CartService } from 'src/app/service/cart.service';
#Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
export class CartComponent implements OnInit {
public products : any = [];
public grandTotal !: number;
constructor(private cartService : CartService, public nav: NavbarserviceService) { }
ngOnInit(): void {
this.nav.show();
this.cartService.getProducts()
.subscribe(res=>{
this.products = res;
this.grandTotal = this.cartService.getTotalPrice();
});
}
// removeItem(item: any){
// this.cartService.removeCartItem(item);
// }
// emptycart(){
// this.cartService.removeAllCart();
// }
}
cart.service.ts
`
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
import { HttpClient } from '#angular/common/http';
import { LoginService } from '../component/login/login.service';
import { UserCart } from './cart';
import { item } from './product';
#Injectable({
providedIn: 'root'
})
export class CartService {
public cartItemList: any = []
public productList = new BehaviorSubject<any>([]);
public search = new BehaviorSubject<string>("");
constructor(private http: HttpClient, private login: LoginService) {
console.log ("constrcutor called")
}
populateDataFromBackend() {
console.log ("populateDataFromBackend called")
var cartItemListLocal: any = []
//return this.productList.asObservable();
//Return data from backend
var apiRequest: string = "http://localhost:3000/userCart?emailId=" + this.login.loggedInUserID;
this.http.get<UserCart[]>(apiRequest)
.subscribe(res => {
console.log(res);
res.forEach(element => {
console.log(element.emailId, element.productId);
var getProductAPI: string = "http://localhost:3000/products?id=" + element.productId;
this.http.get<item>(getProductAPI).subscribe(res => {
//
console.log(res);
cartItemListLocal.push(res);
// this.productList.next (res);
// productListNew.next (cartItemListLocal);
})
});
}
)
console.log("cartItemsLocal\n");
console.log(cartItemListLocal);
this.productList.next(cartItemListLocal);
}
getProducts() {
this.populateDataFromBackend();
return this.productList.asObservable();
}
setProduct(product: any) {
this.cartItemList.push(...product);
this.productList.next(product);
}
addtoCart(product: any) {
var cartItem = new UserCart(this.login.loggedInUserID, product.id);
console.log(cartItem, "cartItem");
this.http.post("http://localhost:3000/userCart", cartItem).subscribe(
(data) => {
console.log("Datasent to cart ", data);
}
)
/*
this.cartItemList.push(cartItem);
this.productList.next(this.cartItemList);
this.getTotalPrice();
console.log(this.cartItemList,"this.cartItemlist")
this.http.post("http://localhost:3000/userCart",this.cartItemList).subscribe(
(data) => {
console.log("Datasent to cart ",data);
}
)
*/
}
getTotalPrice(): number {
let grandTotal = 0;
this.cartItemList.map((a: any) => {
grandTotal += a.total;
})
return grandTotal;
}
// removeCartItem(product: any){
// this.cartItemList.map((a:any, index:any)=>{
// if(product.id=== a.id){
// this.cartItemList.splice(index,1);
// }
// })
// this.productList.next(this.cartItemList);
// }
// removeAllCart(){
// this.cartItemList = []
// this.productList.next(this.cartItemList);
// }
}
product.ts
export class item {
id!: number;
title!: string;
price!: number;
description!: string;
category!: string;
image!: string;
/*
"rating": {
"rate": 3.9,
"count": 120
}*/
}
Can you try calling the http request in the constructor and doing the assignment there?
{{ item?.description }}
and others arrange table cells like this
There are few things I would improve:
First, your interface (or model) product.ts is called item, but you are not using it anywhere. Try to do this:
export class Product {
id: number;
title: string;
price: number;
description: string;
category: string;
image: string;
}
Doing that, you can import it in your component.ts use it when you instantiate a product object, like this:
products : Product[] = [];
Try to do this every time it is possible since we are working with Angular (and TypeScript) and we must avoid using any.
As other people mentioned in the comments, the rest looks good, so try to do that and update the question.
Related
I am new to Angular. Here, I was trying to add an object to a db and to display it in template simultaneously.
app.component.ts
export class AppComponent implements OnInit {
title = 'HttpRequest';
allProducts: Product[] = [];
#ViewChild('productsForm')
form!: NgForm;
constructor(private http: HttpClient) {}
ngOnInit() {
this.fetchProducts();
}
onProductsFetch() {
this.fetchProducts();
}
onProductCreate(products: { pName: string; desc: string; price: string }) {
console.log(products);
let header = new HttpHeaders({ myHeader: 'sachin' });
this.http
.post<{ name: string }>(
'*****',
JSON.stringify(products),
{ headers: header }
)
.subscribe({
next: (res) => {
// console.log(res);
},
});
//--------------------Error is here-----------------------------------------
//! This is not working
this.onProductsFetch();
//! This is working
// setTimeout(() => {
// this.onProductsFetch();
// }, 1000);
//--------------------Error is here-----------------------------------------
}
private fetchProducts() {
this.http
.get<{ [key: string]: Product }>(
'*****'
)
.pipe(
map((res) => {
let products: Product[] = [];
for (const [key, value] of Object.entries(res)) {
products.push({ ...value, id: key });
}
return products;
})
)
.subscribe({
next: (products) => {
this.allProducts = [...products];
console.log(this.allProducts);
},
});
}
}
app.component.html
<div class="main-area">
<div class="content-area">
<div class="header">
<h1>Manage Products</h1>
<hr />
</div>
<div class="container">
<!--Add product form-->
<div class="form-area">
<h3>Create Product</h3>
<form
#productsForm="ngForm"
(ngSubmit)="onProductCreate(productsForm.value)"
>
<label>Procuct Name</label>
<input type="text" name="pName" ngModel />
<label>Procuct Description</label>
<input type="text" name="desc" ngModel />
<label>Procuct Price</label>
<input type="text" name="price" ngModel />
<input type="submit" value="Add Product" />
</form>
</div>
<!--Display product area-->
<div class="product-display-area">
<h3>All Products</h3>
<table id="products">
<tr>
<th>#</th>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th></th>
<th></th>
</tr>
<tr *ngFor="let prod of allProducts; let i = index">
<td>{{ i + 1 }}</td>
<td>{{ prod.pName }}</td>
<td>{{ prod.desc }}</td>
<td>${{ prod.price }}</td>
</tr>
</table>
<hr />
<div class="action-btn-container">
<button class="btn-fetch" (click)="onProductsFetch()">
Refresh Products
</button>
</div>
</div>
</div>
</div>
</div>
products.model.ts
export class Product {
pName!: string;
desc!: string;
price!: string;
id?: string;
}
So here, when i use onProductCreate() method, the POST method is working but onProductFetch() isnt working and the template is not updating while if we use setTimeout(), its working completely and also template got updated. Why its happening like that?
PS: Please forgive me if my question is wrong :)
http.post just returns observable immidiately and does not wait your POST get response.
You have to put your this.onProductsFetch(); in subscribe.
this.http
.post<{ name: string }>(
'******',
JSON.stringify(products),
{ headers: header }
)
.subscribe({
next: (res) => {
// console.log(res);
this.onProductsFetch();
},
});
I actually want to create a table with the data who the api return to me.
The problem is that i can't print the data.
The IdLangage have his column in the table and i want to put the data of the traduction into the correct cell.
The JSON data format :
traductionData ={
"Data":
[
{
"Code": "BJR",
"TraductionsFormat":
[{
"Code": "BJR",
"Description": null,
"Id": 0,
"IdLangage": "FR",
"Traduction": "Bonjour"
},
{
"Code": "BJR",
"Description": null,
"Id": 0,
"IdLangage": "EN",
"Traduction": "Hello"
}]
},
] };
Here is my table where i want to print the data into :
<table>
<thead>
<tr>
<th width="25%">Code</th>
<th width="15%">FR</th>
<th width="15%">EN</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let traduction of traductionData">
<td>{{ traduction.TraductionsFormat.Code }}</td>
<td>{{ traduction.TraductionsFormat.Traduction}}</td>
</tr>
</tbody>
</table>
Here is my angular service :
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http'
import { map } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
#Injectable({
providedIn: 'root'
})
export class ApiService {
localUrlAPI: string = environment.urlAPI;
constructor(private http : HttpClient) { }
getAllTraductions(){
return this.http.get<any>(this.localUrlAPI+"GetAllTraductionsGroupByCode")
.pipe(map((res:any)=>{
return res;
console.log(res);
}))
}
}
And here is my angular Component with my http request :
import { Component, OnInit } from '#angular/core';
import { ApiService } from 'src/app/services/api.service';
#Component({
selector: 'app-grid-edit-traductions',
templateUrl: './grid-edit-traductions.component.html',
styleUrls: ['./grid-edit-traductions.component.scss']
})
export class GridEditTraductionsComponent implements OnInit {
traductionData !: any[];
constructor(private api: ApiService) { }
ngOnInit(): void {
this.getLesTraductions();
}
getLesTraductions(){
this.api.getAllTraductions()
.subscribe(res=>{
this.traductionData = res.Data;
console.log(this.traductionData)
})
}
}
<table>
<thead>
<tr>
<th *ngFor="let column of tableHeaders">
{{column}}
</th>
</tr>
</thead>
<tbody>
<tr ng *ngFor="let row of tableRows">
<td *ngFor="let column of tableHeaders">
{{row[column]}}
<ng-container *ngFor="let trad of row.TraductionsFormat, let j = index">
<span *ngIf="row.TraductionsFormat[j].IdLangage === column">
{{row.TraductionsFormat[j].Traduction}}
</span>
</ng-container>
</td>
</tr>
</tbody>
</table>
Here's the ts:
tableRows: Array<any> = [];
tableHeaders: Array<any> = [];
ngOnInit(): void {
//---- TABLE HEADERS -----
this.tableHeaders.push("Code")
this.traductionData.Data.forEach(el => {
el.TraductionsFormat.map(c => c.IdLangage).forEach(lang => {
this.tableHeaders.push(lang);
})
});
this.tableHeaders = [...new Set(this.tableHeaders)];
//---- TABLE ROWS -----
this.traductionData.Data.forEach(el => {
this.tableRows.push(el)
});
}
Stackblitz example
The JSON data you've provided is wrong, there are missing commas and brackets. Although, I'm pretty sure that the reason the data isn't shown in table is that the "TraductionsFormat" is an array. If you want to get an item from array you have to provide an index.
<tr *ngFor="let traduction of traductionData">
<td>{{ traduction.TraductionsFormat[0].Code }}</td>
<td>{{ traduction.TraductionsFormat[0].Traduction}}</td>
</tr>
Above is just simple solution. You might want to use dynamic indexes.
list.component.ts
import { Component, OnInit } from '#angular/core';
import { StudentAPIService } from 'src/app/services/student-api.service';
import { Student } from 'src/app/model/student';
#Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {
constructor( private studentAPI: StudentAPIService ) { }
ngOnInit(): void {
this.studentAPI.studentList().subscribe(res=>{
console.log(res);
return res;
});
}
}
list.component.html
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="center">
<table id="student_Table">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of res">
<td>{{ row.student_name }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
I am new in angular and I want to show data in list.component.html table. In ts file I have successfully fetch data through an API and data are showing in console.log(res) but unable to show in table. So, How can I do this? Please help me.
Thank You
You have to define the variable (and it should be public) in the class definition, then assign the service response to that variable. So;
#Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {
constructor( private studentAPI: StudentAPIService ) { }
public res: any | any[]; // you can create an interface to the data type
ngOnInit(): void {
this.studentAPI.studentList().subscribe(res=>{
this.res = res;
});
}
}
You can use async pipe and get rid of subscribing inside component. Because async pipe will auto unsubscribe when component destroyed.
export class ListComponent implements OnInit {
response$:Observable<IStudentList[]>;
constructor( private studentAPI: StudentAPIService ) { }
ngOnInit(): void {
this.response$ = this.studentAPI.studentList();
}
}
Now You can iterate response$ like below..
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="center">
<table id="student_Table">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of response$ | async">
<td>{{ row.student_name }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
See above <tr *ngFor="let row of response$ | async"> this is auto-subscribe and you will get your list data in html and iterate over it and display it.
I need to set different classes depending of the Button.
Example:
delete -> class='danger';
edit -> class='primary' (setted by default)
This is my HTML:
<div class="container">
<table class="table">
<tr>
<th *ngFor="let col of columns" (click)="sortTable(col)">{{col}}</th>
<th>Actions</th>
</tr>
<tr *ngFor="let user of users | paginate: {itemsPerPage: 5,
currentPage: page,
totalItems: users.length } ; let i = index">
<td *ngFor="let col of columns">{{user[col]}}</td>
<td>
<button class="btn btn-{{class}}" *ngFor="let act of actions" (click)="actionFunc(act,i)">{{act}}</button>
//THE RESULT MUST BE LIKE THIS
<!--<button class="btn btn-danger">Delete</button>-->
<!--<button class="btn btn-primary"> Edit</button>-->
</td>
</tr>
</table>
</div>
<div>
<pagination-controls (pageChange)="page = $event"></pagination-controls>
</div>
This is my component.ts:
import {Component, Input, OnInit} from '#angular/core';
#Component({
selector: 'app-dynamic-table',
templateUrl: './dynamic-table.component.html',
styleUrls: ['./dynamic-table.component.css']
})
export class DynamicTableComponent implements OnInit {
#Input()
users = [];
#Input()
columns: string[];
#Input()
actions: string[];
#Input()
class = 'primary';
direction = false;
page: any;
constructor() {
}
sortTable(param) {
/*...*/
}
actionFunc(i, index) {
if (i === 'deleteUser') {
if (confirm('Are you sure you want to delete this item?') === true) {
this.users.splice(index, 1);
}
}
if (i === 'editUser') {
/*...*/
}
}
ngOnInit(): void {
/*if (this.actions ==='deleteUser') {
this.class = 'danger';*/ SOMETHING LIKE THIS
}
}
}
I'm not sure if I have to insert the logic inside "onInit()" so If you any suggestion I would appreciate it.
UPDATE
HTML
<button [ngClass]="getClassCondition(act)" *ngFor="let act of actions" (click)="actionFunc(act,i)">{{act}}</button>
COMPONENT.TS
getClassCondition(act) {
return act === 'deleteUser' ? this.class = 'btn btn-danger' : 'btn btn-primary' ;
}
Add an enum for your Actions:
enum Action {
'Delete' = 'delete',
'Edit' = 'primary',
// etc...
}
Add a function to get the class from enum:
getActionClass(action: string): string {
return Action[action];
}
Get the class from the template:
<button class="btn btn-{{getActionClass(act)}}"
*ngFor="let act of actions"
(click)="actionFunc(act,i)">{{act}}
</button>
This is a simple example. Bear in mind function calls in template are not the smartest ideas since they get called on every change detection run.
Another idea is to use setter on actions Input:
_actions: string[];
#Input('actions')
set actions(actions) {
this._actions = actions;
this._actionsWithClasses = this._actions.map(action => {
return { action: action, class: Action[action] };
});
}
get actions() {
return this._actions;
}
_actionsWithClasses: { action: string; class: string }[];
... and then use actionsWithClasses in the template instead of actions.
I am using Angular-DataTables 6.0 (found here https://l-lin.github.io/angular-datatables/#/welcome) and I have been running into a reoccurring problem. When a table item is added or deleted, the record either vanishes or reappears upon sorting or searching. Is this possibly because the adding/deleting is occurring from outside the dataTable?
I've tried adding the ' datatable="ng" ' fix many others suggested but that didn't change anything. I also attempted to add a re-render function, but in that case I ran into 'object unsubscribed' errors that I couldn't resolve. For reference, some similar problems can be found here: Similar examples include: (angular : lost data after sort datatable)
(Sorting of numbers within brackets in angular datatables)
(https://github.com/l-lin/angular-datatables/issues/852)
Here is my code:
HTML:
<table datatable="ng" [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="table table-hover" id="t1">
<thead>
<tr>
<th>
<button id="b5">Asset ID</button>
</th>
<th>
<button id="b5">Employee ID</button>
</th>
<th>
<button id="b5">Asset Type</button>
</th>
<th>View</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let a of assets; let i = index">
<td>{{ a.assetID }}</td>
<td>{{ a.currentUser }}</td>
<td>{{ a.assetType }}</td>
<td><button id="button1" (click)="viewAsset(a)"><i class="fas fa-search"></i></button></td>
<td><button id="b2" class="btn" (click)="scrapAsset(a)" (mouseenter)="buttonHover(i)" (mouseleave)="buttonHoverLeave(i)"><i class="{{buttonIconArray[i].text}}"></i></button></td>
</tr>
</tbody>
</table>
-elsewhere in the code-
<button class="btn" id="b1" (click)="addAsset()">Add New Asset</button>
TS
dtOptions: DataTables.Settings = {};
dtTrigger = new Subject();
addAsset()
{
this.confirmChanges = false;
//Create a new asset:
let a: Asset = {
assetID: this.assetID,
currentUser: this.currentUser,
assetType: this.dropdownMessage,
}
//send a notification to the user that owns the new asset
let notify: Notice = {
emplyID: a.currentUser,
notificationSource: "Asset",
details: "A new " + this.dropdownMessage + " was added to your assets.",
timeStamp: new Date()
}
//Add the asset to the server
this.AssetsService.addAsset(a)
.subscribe(asset => { this.assets.unshift(asset);
//All of the inputs need to be emptied
this.clearFields();
})
}
scrapAsset(a: Asset)
{
console.log("The ID is " , a.assetID)
//this.AssetsService.deleteAsset(this.currentAsset).subscribe()
this.confirmChanges = false;
//This deletes the asset from the back-end.
this.AssetsService.deleteAsset(a).subscribe(() => {
console.log('test')
this.assets = this.assets.filter(t => t !== a);
this.NotificationsService.addNotice(notify).subscribe();
this.clearFields(); });
}
dtActivate()
{
this.dtOptions = {
pagingType: 'full_numbers',
pageLength: 7,
order: (this.assets.assetType),
orderClasses: false,
};
this.AssetsService.getAssetsIT().subscribe((assetsImported) => {
this.assets = assetsImported;
this.parseData();
// Calling the DT trigger to manually render the table
this.dtTrigger.next();
});
}
This is only a partial section of the code, so if you need to see more, just ask. Thank you for any help you might provide!
I've had the same problem for a long time. After a lot of stack overflow and documentation, I found a solution that fixed my problem. Maybe it helps you too.
Allow datatable to be destroyed
ngOnInit() {
this.dtOptions = {
destroy: true,
...
};
...
}
The method that received new items (called after edit, insert, add...).
onReceived(items){
let isFirst = this.items.length === 0;
this.items = <itemsModel[]>items;
if (isFirst)
this.dtTrigger.next();
else
this.rerender();
}
The rerender as in documentation
rerender(): void {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
dtInstance.destroy();
this.dtTrigger.next();
});
}
https://l-lin.github.io/angular-datatables/#/advanced/rerender
I hope that this might help you.
this will work, but i am still looking for better solutions
setTimeout(function () {$(function () {$('#ng').DataTable();});}, 10);
You can remove the ng, Following code fixed my problem
<div class="container-fluid">
<div class="page-title">
<h4>Milk Types</h4>
</div>
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-block">
<a href="" class="btn btn-success" href='' [routerLink]="['/milk/create-milk']">
<i class="ti-zip pdd-right-5"></i>
<span>Add New Milk</span>
</a>
<div class="table-overflow">
<table class="table table-lg table-hover" datatable [dtTrigger]="dtTrigger" [dtOptions]="dtOptions">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Status</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let drink of data">
<td>
<div class="mrg-top-15">
<b class="text-dark font-size-16">{{ drink.id }}</b>
</div>
</td>
<td>
<div class="mrg-top-15">
<span class="text-info pdd-left-20"><b>{{ drink.name }}</b></span>
</div>
</td>
<td>
<div class="col-md-5">
<div class="toggle-checkbox toggle-success checkbox-inline">
<input type="checkbox" name="isEnabled" id="toggle4" [checked]="drink.isEnabled">
<label for="toggle4"></label>
</div>
</div>
</td>
<td>
<div class="mrg-top-15">
<span class="text-info"><b>KD {{ drink.price }}</b></span>
</div>
</td>
<td>
<div class="mrg-top-10 text-center">
<a href="" class="btn btn-warning">
<i class="ti-comment pdd-right-5"></i>
<span>Edit</span>
</a>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
import { Component, OnInit, Input, OnDestroy , ViewEncapsulation } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { pipe, Subscription } from 'rxjs';
import { MilksItem, MilksDataSource } from './milks-datasource';
import { Subject } from 'rxjs';
#Component ({
templateUrl: 'milk.html'
})
export class MilkComponent implements OnInit {
dtOptions: DataTables.Settings = {};
subscription: Subscription;
data: MilksItem[] = [];
dtTrigger: Subject<MilksItem> = new Subject();
constructor(private db: AngularFireDatabase)
{
}
ngOnInit() {
this.dtOptions = {
pagingType: 'full_numbers'
};
this.subscription = this.db.list<MilksItem>('milkTypes').valueChanges().subscribe(d=>{
console.log('data streaming');
this.data = d;
this.dtTrigger.next();
});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
this.dtTrigger.unsubscribe();
}
}
Another Working Solution
Just move your data-table inside a separate component
AND
Provide your new options/data as an Input()
import { AfterViewInit, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '#angular/core';
import { DataTableDirective } from 'angular-datatables';
import { Subject } from 'rxjs';
#Component({
selector: 'app-datatable',
templateUrl: './datatable.component.html',
styleUrls: ['./datatable.component.scss']
})
export class DatatableComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
#ViewChild(DataTableDirective, { static: false }) dt!: DataTableDirective;
#Input() dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject<any>();
constructor() { }
private _initComponent() {
this.dtTrigger.next(this.dtOptions);
}
ngOnInit(): void {
}
ngAfterViewInit(): void {
this._initComponent();
}
ngOnChanges(changes: SimpleChanges): void {
}
ngOnDestroy(): void {
this.dtTrigger.unsubscribe();
}
}
<table #dtA datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger"
class="custom-dt-1 table table-sm table-striped card-table w-full row-border hover">
</table>