Reputation: 105
If trying to show a loading spinner while a function is being executed. I already tried different things, but the spinner won't show.
<div class="row pt-3" id="firstRow">
<div class="col">
<button class="btn btn-dark back-button">
<fa name="upload"></fa>
<span>Load .csv file</span>
</button>
<input type="file" #fileImportInput name="File Upload" class="txtFileUpload p-3" (change)="fileChangeListener($event)" accept=".csv" />
<img class="spinner" *ngIf="loading" src="../../../assets/img/gif-spinner/Spin-2s-200px.gif" />
</div>
</div>
export class MotionAnalysisComponent implements OnInit {
loading = false;
fileChangeListener($event: any): void {
this.loading = true;
let files = $event.srcElement.files;
if (this.isCSVFile(files[0])) {
let input = $event.target;
let reader = new FileReader();
reader.readAsText(input.files[0]);
reader.onload = () => {
let csvData = reader.result;
let csvRecordsArray = (<string>csvData).split(/\r\n|\n/);
this.csvRecords = this.getDataRecordsArrayFromCSVFile(csvRecordsArray, 4);
};
reader.onerror = function () {
alert('Unable to read ' + input.files[0]);
};
} else {
alert("Please import valid .csv file.");
this.fileReset();
}
this.loading = false;
If I comment the "this.loading = false" out within the function, then the spinner will show AFTER the function is executed and will (obviously) not disappear. So how can I make the HTML understand, that the spinner should be shown during the execution of the function?
Upvotes: 1
Views: 5552
Reputation: 38094
It seems that it is necessary to see debug information. So show value of loading
in your HTML:
Load .csv file
<p>loading {{ loading }} </p>
<img class="spinner" *ngIf="loading"
src="../../../assets/img/gif-spinner/Spin-2s-200px.gif" />
</div>
If you see, that value of loading
updates correctly, then try to set style:
img {
width: inherit;
height: inherit;
position: fixed;
top:0;
left:0;
}
div
tag ends incorrectly: /div>
UPDATE:
Try to set src
of image by template expression:
HTML:
<img class="spinner"
*ngIf="loading"
[src]="imagePath"/>
TypeScript:
imagePath = '../../../assets/img/gif-spinner/Spin-2s-200px.gif;'
Upvotes: 0
Reputation: 73731
To allow time for the spinner to initialize, you can run the code asynchronously after setting loading
to true
. This can be achieved by moving the code inside of a setTimeout
callback. The loading
property should be reset at the end of that callback method.
fileChangeListener($event) {
this.loading = true; // First, set loading property
setTimeout(() => { // Call setTimeout to run code asynchronously
let files = $event.srcElement.files;
if (this.isCSVFile(files[0])) {
...
} else {
...
}
this.loading = false; // Reset loading before leaving callback method
}, 0);
}
See this stackblitz for a demo. Please note that you could increase the setTimeout
delay, if necessary (it is set to 0 ms in the example above).
Upvotes: 1
Reputation: 497
@Component({
selector: 'm-selector',
templateUrl: './selector.component.html',
changeDetection: ChangeDetectionStrategy.OnPush, <-- add this line
styleUrls: ['./selector.component.scss']
})
add a change detection method
then in your constructor
constuctor(
...,
private ref: ChangeDetectorRef <-- add this line
){ }
this make you have an access to ask angular to check changes manually
then you can use it, for example:
this.loading = true
this.ref.markForCheck()
call the ref.markForCheck everytime you change a variable that affect your html with *ngIf
this way you will consume less memory as you do not keep listening to a certain variable
but if your variable often changes overtime then it is recommended to use listener
Upvotes: 0
Reputation: 21638
My guess is that
... other part of the function...
is a call to an observable or an async function so your
this.loading = false;
is called straight away.
Without knowing exactly what is in that block of code I can't tell but most likely you need a callback function the executes once the async call has finished to set loading to false.
Upvotes: 0