0

I have this little bit of code mixed in with node.js and it allows me to create an unordered list of the directory. What I want is for the parent looping function to pause and wait for the child loop to finish and then continue with the code.

This is my code:

listFolders = (dir, callback) ->
  readDir = "#{__dirname}/public/#{dir}"
  fs.readdir readDir, (err, files) ->
  files.forEach (file) ->
    dirname = file
    path = "#{dir}/#{file}"
    readPath = "#{readDir}/#{file}"

    fs.stat readPath, (err, stat) ->
      if stat && stat.isDirectory()
        console.log "<li class='folder' data-path='#{dir}' data-name='#{dir}/#{dirname}'><span>#{dirname}</span><ul>"
        listFolders path, () ->
          console.log "</ul></li>"
      else if stat && stat.isFile()
        console.log "<li class='file' data-path='#{dir}' data-filename='#{dirname}'><span>#{dirname}</span></li>"

  return callback

As you can see, I have tried to give the function a callback but when I use it

listFolders path, () ->
  console.log "</ul></li>"

the console log is never run, nor did it pause my code.

My output of the folder I am scanning is

<li class='file' data-path='/user_projects/1' data-filename='.DS_Store'><span>.DS_Store</span></li>
<li class='folder' data-path='/user_projects/1' data-name='/user_projects/1/assets'><span>assets</span><ul>
<li class='file' data-path='/user_projects/1' data-filename='index.html'><span>index.html</span></li>
<li class='folder' data-path='/user_projects/1/assets' data-name='/user_projects/1/assets/css'><span>css</span><ul>
<li class='file' data-path='/user_projects/1/assets' data-filename='test.php'><span>test.php</span></li>
<li class='file' data-path='/user_projects/1/assets/css' data-filename='main.css'><span>main.css</span></li>

and it should be

<li class='file' data-path='/user_projects/1' data-filename='.DS_Store'><span>.DS_Store</span></li>
<li class='folder' data-path='/user_projects/1' data-name='/user_projects/1/assets'><span>assets</span><ul>
    <li class='folder' data-path='/user_projects/1/assets' data-name='/user_projects/1/assets/css'><span>css</span><ul>
       <li class='file' data-path='/user_projects/1/assets' data-filename='test.php'><span>test.php</span></li>
       <li class='file' data-path='/user_projects/1/assets/css' data-filename='main.css'><span>main.css</span></li>
    </ul></li>
</ul></li>
<li class='file' data-path='/user_projects/1' data-filename='index.html'><span>index.html</span></li>

I've been suffering with this problem for a while now and would like someone to help me out. Your help will be very much appreciated.

>>>>>>UPDATE USING forEachSeries<<<<<<<

I am now using the code provided below

listFolders = (dir, callback) ->
  readDir = "#{__dirname}/public/#{dir}"
  fs.readdir readDir, (err, files) ->
    async.forEachSeries files, (file, callback) ->
      dirname = file
      path = "#{dir}/#{file}"
      readPath = "#{readDir}/#{file}"

      fs.stat readPath, (err, stat) ->
        if stat && stat.isDirectory()
          console.log "<li class='folder'><span>#{dirname}</span><ul>"
          listFolders path, () ->
            console.log "</ul></li>"
            callback()
        else if stat && stat.isFile()
          console.log "<li class='file'><span>#{dirname}</span></li>"
          callback()
  , callback

and my output is not ant I'd like but instead this (closing 'ul' and 'li' not showing):

<li class='file' data-path='/user_projects/1' data-filename='.DS_Store'><span>.DS_Store</span></li>
<li class='folder'><span>assets</span><ul>
    <li class='folder'><span>css</span><ul>
        <li class='file'><span>main.css</span></li>

my folders in the directory are and should be displayed like

- .ds_store
- asstets
  - css
    - main.css
  - test.php
- index.html

1 Answers1

0

You're passing in a function callback, but you're never calling it. You're just returning it. You may want to look into something like async.js. Then you would write code that looks something like:

listFolders = (dir, callback) ->
  readDir = "#{__dirname}/public/#{dir}"
  fs.readdir readDir, (err, files) ->
    async.forEachSeries files, (file, callback) ->
      dirname = file
      path = "#{dir}/#{file}"
      readPath = "#{readDir}/#{file}"

      fs.stat readPath, (err, stat) ->
        if stat && stat.isDirectory()
          console.log "<li class='folder' data-path='#{dir}' data-name='#{dir}/#{dirname}'><span>#{dirname}</span><ul>"
          listFolders path, () ->
            console.log "</ul></li>"
            callback()
        else if stat && stat.isFile()
          console.log "<li class='file' data-path='#{dir}' data-filename='#{dirname}'><span>#{dirname}</span></li>"
          callback()
  , callback
Aaron Dufour
  • 17,288
  • 1
  • 47
  • 69
  • Installed using npm, what would I require in the server file as currently I am receiving ReferenceError: _ is not defined from part "_.forEach". Sorry a little new at node.js – JosephSmith127 Oct 16 '13 at 17:26
  • i have no idea how to use coffeescript but in normal javascript this would look like `var async = require('async'); async.forEach(yourArray, yourIteratorFunction, finalCallbackFunction)` see the [async docs](https://github.com/caolan/async#eacharr-iterator-callback) – Plato Oct 16 '13 at 17:52
  • Also I am pretty sure that _.forEach has to be indented for it to use the variable of files. Can you correct me if I am wrong this is where I could be going wrong? – JosephSmith127 Oct 16 '13 at 18:53
  • @JosephSmith127 I based it off your original code, which has the same indenting problem. Also, I accidentally used `_` instead of `async`. Is the `console.log` in the callback running now? – Aaron Dufour Oct 16 '13 at 19:26
  • @JosephSmith127 You should probably try indenting the second-to-last line (`callback()`) the same way I did. – Aaron Dufour Oct 16 '13 at 19:27
  • @AaronDufour I've updated it again just now check out below >>>>>>UPDATE<<<<<< – JosephSmith127 Oct 16 '13 at 19:42
  • @JosephSmith127 I didn't realize that you were doing asynchronous work inside the callback to `fs.stat` - check out the new placement of the lines that call `callback`. – Aaron Dufour Oct 16 '13 at 19:44
  • @AaronDufour Hey thanks man but that just throws out the same as my most recent update of the code above but this time without the also is there a way (off topic) to order folders first? – JosephSmith127 Oct 16 '13 at 20:03
  • @JosephSmith127 Oh, you probably want `forEachSeries`. I'm not sure about ordering folders first; you'd have to fs.stat all of them, then sort them, then do the `console.log`s. – Aaron Dufour Oct 16 '13 at 20:51
  • @AaronDufour is it possible to ask for you to help re-write my code to work how i want it I have been trying to do this for almost 12 hours now. – JosephSmith127 Oct 16 '13 at 21:03
  • @AaronDufour I didn't see you edited the code above but still I made the change and showed you what it gave back to me in my update. Still not working :( I hate problems like this. – JosephSmith127 Oct 16 '13 at 21:34