Reputation: 8681
I have implemented ngx-spinner in my angular 7 application.
The spinner loads but I want it to spin only when the data is loading. At the moment I can see some part of the page in advance and then spinner loads.
Where am I going wrong?
I have written the this.spinner.show();
in getAllocationsDetails()
<style>
.alert {
margin-top: 10px;
height: 500x;
position: relative;
width: 100%;
/* padding: 15px; */
bottom: 0%;
border: 1px solid transparent;
border-radius: 4px;
float: left;
}
.alert-danger {
background-color: #f2dede;
border-color: #ebccd1;
color: #a94442;
}
table {
border-collapse: collapse;
}
.spacing {
padding-top: .5em;
padding-bottom: .5em;
}
.k-tabstrip>.k-content.k-state-active {
display: none!important;
}
</style>
<ngx-spinner bdOpacity = 0.9
bdColor = "#ce6d43"
size = "medium"
color = "#fff"
type = "ball-spin"
fullScreen = "true"
> <p style="color: white" > Loading... </p>
</ngx-spinner>
<div class="form-group row col-md-12" style="margin-top:30px">
<label for="inputFax" class="col-md-1 col-form-label " style="font-weight: bold;">Eval Date</label>
<div class="col-md-1">
<kendo-datepicker style="width: 100% ;float: left;" [format]="'MMMM yyyy'" [topView]="'decade'" [bottomView]="'year'" [(ngModel)]="evalDate"
(valueChange)="evalDateChanged($event)">
</kendo-datepicker>
</div>
<div class="col-md-2" style="padding-left: 10px; width: 100%"><a class="btn btn-primary "
(click)="downloadFundAllocationDetails()" [attr.href]="Url">Export To
EXCEL<i title="PDF" class="fa fa-file-excel-o"></i> </a></div>
</div>
<div class="form-group row">
<div class="panel panel-default col-md-12">
<div *ngIf="AllocationDetails && AllocationDetails.ManagerAllocations" class="panel-body">
<div [style.height.px]="GridHeight()" [style.width.%]="100" style="float: left;">
<span style="text-decoration: underline; cursor: pointer;padding-right: 10px;"><a (click)="expandAll()">Expand
All</a></span>
<span style="text-decoration: underline; cursor: pointer;"><a (click)="collapseAll()">Collapse
All</a></span>
<ag-grid-angular #agGrid class="ag-theme-balham" [gridOptions]="GridOptions" style="width: 100%; height: 100%"
[columnDefs]="ColumnDefs" [rowData]="AllocationDetails.ManagerAllocations" rowHeight="30" headerHeight="30"
rowSelection="single">
</ag-grid-angular>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="panel panel-default col-md-12">
<div style="height: 100%; width: 100%;"
*ngIf="AllocationDetails && AllocationDetails.MissingProducts" class="alert alert-danger col-md-5">
<p><strong>The investments made in the following products are not included in this report:</strong></p>
<table>
<ng-container *ngFor="let group of AllocationDetails.MissingProducts">
<tr>
<th> {{group[0].ProductType}}</th>
</tr>
<tr *ngFor="let post of group">
<td> {{ post.ProductName }} </td>
</tr>
<tr>
<td class="spacing"></td>
</tr>
</ng-container>
</table>
</div>
<div style="height: 100%; width: 100%; float:left;" *ngIf="AllocationDetails && AllocationDetails.ChartData"
class="col-md-7">
<app-pie-chart [series]="allocation_series"></app-pie-chart>
</div>
</div>
</div>
import { Component, NgZone, Input } from '@angular/core';
import { OnInit } from '@angular/core';
import { AllocationsService } from '../services/allocations.service';
import { formatDate } from '@angular/common';
import { GridOptions } from 'ag-grid-community/dist/lib/entities/gridOptions';
import { Comparator } from '../utilities/comparator';
import { ActivatedRoute } from '@angular/router';
import { NgxSpinnerService } from 'ngx-spinner';
@Component({
selector: 'mgr-allocations',
templateUrl: './allocations.component.html'
})
export class AllocationsComponent implements OnInit {
private Error: string;
public evalDate: Date;
private _evalDate: Date;
public AllocationDetails: any;
private _ManagerStrategyId: number;
public GridOptions: GridOptions;
ExportingToExcel: boolean;
windowHeight: any;
offset: number;
ngZone: any;
router: any;
Comparator: Comparator;
Route: any;
public allocation_series: any;
public LoadingAllocations = true;
public get ManagerStrategyId(): number {
return this._ManagerStrategyId;
}
@Input()
public set ManagerStrategyId(value: number) {
this._ManagerStrategyId = value;
}
constructor(private allocationsService: AllocationsService, private comparator: Comparator,
private zone: NgZone, private route: ActivatedRoute,private spinner: NgxSpinnerService) {
this.Comparator = comparator;
this.Route = route;
window.onresize = (e) => {
this.ngZone.run(() => {
this.windowHeight = window.innerHeight - this.offset;
setTimeout(() => {
if (!this.GridOptions || !this.GridOptions.api) {
return;
}
this.GridOptions.api.sizeColumnsToFit();
}, 500, true);
});
};
}
private FormattedDate(dateToFormat: Date): string {
return formatDate(dateToFormat, 'yyyy/MM/dd', 'en');
}
setGridOptions() {
this.GridOptions = {
columnDefs: this.getColumns(),
enableFilter: true,
treeData: true,
enableColResize: true,
animateRows: true,
groupDefaultExpanded: 1,
enableSorting: true,
suppressAggFuncInHeader: false,
getDataPath: function (data) {
return data.Hierarchy;
},
onGridReady: e => {
if (!e || !e.api) {
return;
}
e.api.sizeColumnsToFit();
this.setDefaultSortOrder();
},
getRowStyle: (params) => {
if (params.node.level === 0) {
return { 'background-color': '#FCE7D7' };
}
},
autoGroupColumnDef: {
headerName: 'Manager Strategy', width: 300,
valueFormatter: uniqueColumn
},
};
function uniqueColumn(params) {
// if (!params.value) return;
// return params.value.split('#')[0];
const startIndex = params.value.indexOf('#');
if (startIndex === -1) { return params.value; }
const endIndex = params.value.length;
return params.value.replace(params.value.substring(startIndex, endIndex), '');
}
}
ngOnInit() {
// setTimeout(() => {
// /** spinner ends after 5 seconds */
// this.spinner.hide();
// }, 5000);
this.evalDate = new Date();
this.setGridOptions();
this.getAllocationsDetails(this.FormattedDate(this.evalDate));
}
public getAllocationsDetails(evalDate: string) {
if (this.ManagerStrategyId != null) {
this.initGrid();
this.allocationsService.getAllocationsDetails(this.ManagerStrategyId, evalDate)
.subscribe(data => {
this.spinner.show();
this.LoadingAllocations = true;
this.AllocationDetails = data;
this.GridOptions.rowData = this.AllocationDetails;
this.allocation_series = this.AllocationDetails.ChartData;
setTimeout(() => {
this.spinner.hide();
}, 1000, true);
},
err => {
this.Error = 'An error has occurred. Please contact BSG';
},
() => {
});
}
}
downloadFundAllocationDetails() {
this.ExportingToExcel = true;
this.allocationsService.downloadFundAllocationDetails(this.ManagerStrategyId, this.evalDate)
.subscribe(blob => {
const fileName = ' as of ' + 'TestDate';
const fileURL = window.URL.createObjectURL(blob);
const extention = '.xlsx';
const downloadLink = document.createElement('a');
downloadLink.href = fileURL;
downloadLink.download = fileName + extention;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
this.ExportingToExcel = false;
},
err => {
this.ExportingToExcel = false;
this.Error = 'An error has occurred. Please contact BSG';
},
() => {
});
}
public evalDateChanged(value: Date): void {
this.getAllocationsDetails(this.FormattedDate((value)));
}
GridHeight() {
if (!this.windowHeight) {
this.windowHeight = window.innerHeight - this.offset + 10;
}
return this.windowHeight;
}
setDefaultSortOrder() {
const defaultSortModel = [
{ colId: 'ManagerStrategyName', sort: 'asc' },
{ colId: 'UsdEmv', sort: 'desc' }
];
this.GridOptions.api.setSortModel(defaultSortModel);
}
private initGrid() {
const self = this;
}
private getColumns(): Array<any> {
const self = this;
const definition = [
{ headerName: 'Date', field: 'EvalDate', hide: true },
{ headerName: 'Firm ID', field: 'FirmID', hide: true },
{ headerName: 'Manager Strategy ID', field: 'FirmName', hide: true },
{ headerName: 'Firm', field: 'ManagerStrategyID', hide: true },
{ headerName: 'Manager Strategy', field: 'ManagerStrategyName', hide: false },
{ headerName: 'Fund ID', field: 'ManagerFundID', hide: true },
{ headerName: 'Fund', field: 'ManagerFundName' },
{ headerName: 'Product Name', field: 'ProductName'},
{
headerName: 'As Of', field: 'EvalDate',
cellStyle: {textAlign: 'right'}
},
{
headerName: 'EMV (USD)', field: 'UsdEmv', valueFormatter: this.currencyFormatter, rowGroup: false,
cellRenderer: 'agGroupCellRenderer',
aggFunc: 'sum',
cellStyle: {textAlign: 'right'}
},
{
headerName: '% of Fund Strategy', field: 'GroupPercent', valueFormatter: this.formatPercent, rowGroup: false,
cellRenderer: 'agGroupCellRenderer',
aggFunc: 'sum',
cellStyle: {textAlign: 'right'}
},
{
headerName: '% of Product', field: 'WeightWithEq',
valueFormatter: this.formatPercent,
cellStyle: {textAlign: 'right'}
}
];
return definition;
}
public expandAll() {
this.GridOptions.api.expandAll();
}
public collapseAll() {
this.GridOptions.api.collapseAll();
}
currencyFormatter(number) {
// this puts commas into the number eg 1000 goes to 1,000,
if (!isNaN(number.value)) {
number = Math.floor(number.value).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
number = number === '0' ? '0.00' : number;
return '$' + number;
}
}
formatPercent(number) {
if (!isNaN(number.value) && number.value !== null) {
return (number.value).toFixed(2) + '%';
}
}
}
service code
The service returns an observable. It calls the http.get
getAllocationsDetails(mgrStrategyId: number, evalDate: string) {
let pars = new HttpParams();
pars = pars.append('id', mgrStrategyId.toString());
pars = pars.append('date', evalDate);
const url = this.config.api.allocationDetails;
return this.http.get(url, { params: pars, withCredentials: true });
}
Upvotes: 3
Views: 6784
Reputation: 87
the solution is very simple. you have to display spinner before you are giving call to the subscription and then hide the spinner in the success of the subscription.
For Example,
ngOnInit(){
this.spinner.show();
this.yourServiceName.methodName().subscribe((response : any)=> {
// condition checks if any
this.spinner.hide();
},(error) => {
// if api gives you an error like 500 etc then also you have to stop the spinner
this.spinner.hide();
});
Thats it!
Upvotes: 0
Reputation: 2430
you have to Change public getAllocationsDetails(evalDate: string)
code segment in typescript class to below changes
public getAllocationsDetails(evalDate: string) {
if (this.ManagerStrategyId != null) {
this.initGrid();
this.spinner.show();
this.allocationsService.getAllocationsDetails(this.ManagerStrategyId, evalDate)
.subscribe(data => {
this.spinner.show();
this.LoadingAllocations = true;
this.AllocationDetails = data;
this.GridOptions.rowData = this.AllocationDetails;
this.allocation_series = this.AllocationDetails.ChartData;
setTimeout(() => {
this.spinner.hide();
}, 1000, true);
},
err => {
this.Error = 'An error has occurred. Please contact BSG';
},
() => {
});
}
}
this.spinner.show(); must initiate before service call initiate
see the sample code
Hope this will help..!!
Upvotes: 0
Reputation: 11162
Your problem is that you show the spinner in your subscribe. That is the code that's executing when the observable result is ready.
Instead you should start your spinner before the observable subscription, and stop the spinning inside the finalize
function that runs when the observable has completed (see docs)
(You have to use the .pipe
operator and import the finalize
function)
import { finalize } from 'rxjs/operators';
...
this.spinner.show();
this.allocationsService.getAllocationsDetails(this.ManagerStrategyId, evalDate)
.pipe(
finalize(() => this.spinner.hide())
)
.subscribe(data => {
// Handle your data
});
Upvotes: 3