IOnic native file plugin for listing out directories containing pdf files

Hi, I’d like to access and show all the device directories that contain only pdf files

plt.ready().then(() => {
      this.listDir(this.fileNavigator.externalRootDirectory, '');
    });

This is my list dir method:

listDir = (path, dirName) => {
    this.fileNavigator
       .listDir(path, dirName)
      .then(entries => {
        this.items = entries;
      })
      .catch(this.handleError);
  }```

I'm able to list all the directories but not the directories that contain pdf's

Please help me out on this. Thank You...!

Loop over your this.items and see if a file is a pdf file by checking if it ends with a .pdf extension.

I’m looping over the items in the html template but it will give us all the folders if the entries are folders and it will be the same for the pdf files as well. My requirement is not to render the folders that don’t contain pdf files. Please refer to the below html template code.

<ion-list class="virphy_pdf_directories" *ngFor="let item of items" > 
    <ion-item class="virphy_pdf_directory_item" *ngIf="item.isDirectory" lines="none" no-padding>
      <ion-label class="virphy_pdf_directory_item_title" text-wrap>
          {{ item.name }}
      </ion-label>
    </ion-item>
  </ion-list> 
   <ion-list *ngFor="let item of items" padding>
  <ion-item *ngIf="item.isFile && item.name.substr(item.name.lastIndexOf('.') + 1) == 'pdf'" lines="full" no-padding>
      <ion-icon name="document" slot="start"></ion-icon>  
      <ion-label text-wrap>
          {{ item.name }}
      </ion-label>
      <ion-checkbox slot="end"></ion-checkbox>
      </ion-item>
    </ion-list> 

I understood your requirement. Can you show me what content items variable has?

The items content will either be folders or pdf files if they are present in respective subsequent folders. I’m having a function to navigate between folders(GO down method for entering into the directory & GoUp method for navigating to the root directory from the inner ones.) - code is shown below:

goDown = item => {
    const parentNativeURL = item.nativeURL.replace(item.name, '');
    this.savedParentNativeURLs.push(parentNativeURL);
    this.listDir(parentNativeURL, item.name);
  };

 goUp = () => {
    const parentNativeURL = this.savedParentNativeURLs.pop();
    this.listDir(parentNativeURL, '');
  };

I’m not able to loop through all the inner directories at once from one page (with root folder) so that I can list out all the directories that contain pdf and show them or hide them depending on the pdf files existence.

I do get the idea but can you show me the exact JSON you get from the server?

I’m doing it from the android device - folders & pdf files will be coming from the native device(Android & IOS - for now I’m doing it on android) using ionic native file plugin. Below is the doc URL

IonicNativeFIle_URL

Later, I’ll upload the files to the server once I’ve the option to choose the pdf file after listing out the directories from the native device root directory

Ok, so somewhere(probably in listDir) you reassign items. I want to see what data you get from your android file system when you read it’s directory.

The following is the JSON stringified object data that we get from the device

 [
  {
    "isFile": false,
    "isDirectory": true,
    "name": "name of the directory",
    "fullPath": "/nameof the folder",
    "filesystem": "<FileSystem:sdcard>"
    "nativeURL": "file:///storage/emulated0/Download"
  },
  {
    "isFile": true,
    "isDirectory": false,
    "name": "name of the file",
    "fullPath": "/Download/sample.pdf",
    "filesystem": "<FileSystem:sdcard>"
    "nativeURL": "file:///storage/emulated0/Download/sample.pdf"
  },
  {
    
    "isFile": false,
    "isDirectory": true,
    "name": "name of the directory",
    "fullPath": "/nameof the folder",
    "filesystem": "<FileSystem:sdcard>"
    "nativeURL": "file:///storage/emulated0/Download"
  },
  {
    "isFile": true,
    "isDirectory": false,
    "name": "name of the file",
    "fullPath": "/Download/sample.pdf",
    "filesystem": "<FileSystem:sdcard>"
    "nativeURL": "file:///storage/emulated0/Download/sample.pdf"
  },
 {
    // and so on 
 }
]

Below is the code I’ve added for the getting JSON data:

listDir = (path, dirName) => {
    this.fileNavigator
      .listDir(path, dirName)
      .then(entries => {
        this.items = entries;
        this.toast = this.toastCtrl.create({
          message: '' + JSON.stringify(this.items),
          duration: 10000,
        }).then((toastData) => {
          toastData.present();
        });
      })
      .catch(this.handleError);
  }

Ok, this is much clearer but for this you will have to dig to a very deep level to see if the PDF exists inside a folder or not, or do you want to check only the next sub level?

Yeah, you got it tight! I will need to check every possible folder that contains even a single pdf file and show the respective root folder at the top level in a single page. Any further ideas to move forward in terms of code tweaks??

Thank You…!

Below should work. We go through the list entries recursively and check if the folders have pdf files.

We return data in 2 conditions:

  • If current folder we are in has a pdf file.
  • If sub folders have the pdf file.

Else we return false.

// you could make an instance variable in your constructor called as this.folders = [];

listDir = async (path, dirName) => {
  this.folders = await listDirHelper(path,dirName);
  console.log('Folders who have pdf files',this.folders);
}


listDirHelper = async(path,dirName) => {
  var current_folder = {
    path : path,
    dirName : dirName,
    children : []
  };

  return await this.fileNavigator
    .listDir(path, dirName)
    .then(entries => {
        var does_current_have_pdf = false;

        for(var i=0;i<entries.length;++i){
            if(entries[i]['isDirectory'] === false){
              var pdf_index = entries[i]['fullPath'].lastIndexOf('.pdf');
              if(pdf_index != -1 && pdf_index + 4 === entries[i]['fullPath'].length){
                does_current_have_pdf = true;
              }
            }else{
              var children_data = await this.listDirHelper(entries[i]['nativeURL'],entries[i]['name']);
              if(children_data !== false){
                current_folder['children'].push(children_data);
              }
            }
        }

        if(current_folder['children'].length === 0 && does_current_have_pdf === false){
          return false;
        }

        return current_folder;
    })
    .catch((err) => {
        console.log('error in listing directory',err);
    });
};

Hi Vivek,

I’ve tried your code but it’s currently returning null values with current folder children. And also I’m also getting file listing errors for the other inner directories and returning null.

File listing errors for inner directories should be because of permission issue I presume. Can you post what output did you get from my current code? Also, if child sub directories can’t be read due to whatever issue, then the response returned from the method will be incomplete anyway.

Please find the below screenshot for the output:

Please refer to the below code added:


  constructor(private plt: Platform, private fileNavigator: File, private toastCtrl: ToastController) {
    this.folders = [];
    this.plt.ready().then(() => {
      this.listDir(fileNavigator.externalRootDirectory, '');
    });
}


listDir = async (path, dirName) => {
  this.folders = await this.listDirHelper(path, dirName);
  console.log('Folders who have pdf files', this.folders);
  this.outputFolder = JSON.stringify(this.folders);
 
}


listDirHelper = async(path, dirName) => {
  var current_folder = {
    path : path,
    dirName : dirName,
    children : []
  };

  return await this.fileNavigator
    .listDir(path, dirName)
    .then(async entries => {
        var does_current_have_pdf = false;

        for (var i = 0; i < entries.length; ++i) {
            if (entries[i].isDirectory === false) {
              var pdf_index = entries[i].fullPath.lastIndexOf('.pdf');
              if (pdf_index != -1 && pdf_index + 4 === entries[i].fullPath.length) {
                does_current_have_pdf = true;
              }
            } else {
              var children_data = await this.listDirHelper(entries[i].nativeURL, entries[i].name);
              if (children_data !== false) {
                current_folder.children.push(children_data);
              }
            }
        }

        if (current_folder.children.length === 0 && does_current_have_pdf === false) {
          return false;
        }
        this.folders.push(JSON.stringify(current_folder.dirName));
        return current_folder;
    })
    .catch((err) => {
        console.log('error in listing directory', err);
        this.errors.push(JSON.stringify(err));
    });
}

html template:

 <ion-list class="virphy_pdf_directories"> 
        <ion-item class="virphy_pdf_directory_item" lines="none" no-padding > 
          <ion-label class="virphy_pdf_directory_item_title" text-wrap>
              {{ outputFolder }}
          </ion-label>
        </ion-item>
      </ion-list> 

      <ion-list class="virphy_pdf_directories" *ngFor="let err of errors"> 
        <ion-item class="virphy_pdf_directory_item" lines="none" no-padding > 
          <ion-label class="virphy_pdf_directory_item_title" text-wrap>
              {{ err }}
          </ion-label>
        </ion-item>
      </ion-list> 

Please let me know if I’m doing any mistake and also I’m not able to understand where we are pushing the folders containing pdf’s to the this.folders??

We do it in this.folders = await listDirHelper(path,dirName);

Also, I can see that the path and dirName are not pointing to any folder beforehand when it’s passed to listDir = async (path, dirName). Why? Certainly, empty path without pointing to a folder can’t give you any results. You could manually give these methods a proper folder path and it’s name and see if it gives the correct results.