3

I have been trying in Angular2/4 to make something like when page renders it checks for a file and if file exists it shows a checkbox icon while if it doesnot exist then a download icon is shown. But it runs into infinite loop, it is suggested to use a boolean variable but my elements are dynamic and there can be any number of download links so predefined variables are not an option.

Angular2 Code

<div *ngFor="let item of getItems();">
  <div ngIf="fileExists(item.url); then example2 else example1"></div>
  <ng-template #example1>
    <ion-icon class="myicon" name="download" color="primary"></ion-icon>
  </ng-template>
  <ng-template #example2>
    <ion-icon class="myicon" name="checkbox" color="secondary"></ion-icon>
  </ng-template>
</div>

TypeScript function to check if file exists

 fileExists(url)
 {
   let path = "notif/"+url.substr(url.lastIndexOf('/')+1);
   this.file.checkFile(this.file.externalRootDirectory, path).then(_ => {
     console.log('File exists');    
     return true;
   }).catch(err => {
     console.log(err);
     return false;
   });
 }
Piyush Gupta
  • 33
  • 1
  • 3

2 Answers2

4

It's not an infinity loop. Every time Angular runs change detection, it evaluates the expressions in bindings, this means your function is called very often.

Binding to functions in component templates is usually a bad idea in Angular. Instead assign the result of the function call to a field and bind to this field.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Can you give me some hint, I am new to Angular environment moreover if from field you refer to variable then it is not possible as I dont know how many links would be there – Piyush Gupta Sep 30 '17 at 23:29
  • You would need to call `getItems()` in your code. The problem is the same with this '*ngFor` anyway. Prepare all the data in code, so that it is easy to bind to without function calls. – Günter Zöchbauer Oct 01 '17 at 07:15
0

Here you are returning nothing from method fileExists(url). Whatever true/false you are returning is inside callback handler and returned to caller function (here Promise). So, calling fileExists(url) will always get void and evaluated as false

fileExists(url) {
  let path = "notif/"+url.substr(url.lastIndexOf('/')+1);
  this.file.checkFile(this.file.externalRootDirectory, path).then(_ => {
    console.log('File exists');
    return true; // "true" returned by this success callback, not "fileExists()"
  }).catch(err => {
    console.log(err);
    return false; // "true" returned by this error callback, not "fileExists()"
  });
}

You can use simple functions in ngIf, but you must ensure it returns correctly.

Now in above example, Promise is the thing which can trigger change detection as Promise is monkey-patched by Angular Zone.js.


You can get more knowledge on Angular2+ Change Detection at https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html

Somnath Sinha
  • 662
  • 6
  • 16
  • As stated in Ionic documentation this method Returns: Promise Returns a Promise that resolves with a boolean or rejects with an error. So can you help me out how to resolve it into a boolean which can there be passed on. – Piyush Gupta Oct 01 '17 at 10:52
  • Okay, this kind of operation must be done before. You can prepare the resultant array and then use in the template, then this issue will not happen. – Somnath Sinha Oct 02 '17 at 01:09
  • Thanks I did the same, used an array initialised the value to 0 and 1 initially by checking if the file exists and changing the status after file the downloaded. – Piyush Gupta Oct 11 '17 at 21:13