0

I'm trying to send an ajax request that retrieves a list of file names from an ftp server. Retrieving the files is not a problem, but when I pass my ajax request (click on the button in my index.ejs file), it renders the view before finishing getting all the files (the files variable in res.render is empty). I've tried using async parallel but the execution either gets stuck in the searchFiles function or renders the view before the function execution. Any thoughts ? (I guess I do my callback the wrong way,I just can't figure how).

In my server.js file :

var Files = require('./prototypes/files.js');
var files, searchedFiles;

app.get('/search', function (req, res) {
    files = new Files();
    files.searchFiles(req.query.t, function(searchedFiles) {
        console.log(searchedFiles);
        res.render('index', {files: searchedFiles});
    });
});

In my files.js file :

function Files() {
}

Files.prototype.searchFiles = function(searchedText, callback) {
    var connectionProperties = {
        host: "host",
        user: "username",
        password: "password"
    }
    var folders = ["", "0-9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X-Z"];
    var Client = require('ftp'); 
    var c = new Client();
    var files = {};    
    c.on('ready', function () {
        folders.forEach(function(folder) {
            c.list("/pools/A/A0/Movies/Films/" + folder, function (err, list) {
                if (err) throw err;
                list.forEach(function (element, index, array) {
                    if (element.name.match("(mkv|avi|mp4|mov)$") && (element.name.toLowerCase().indexOf(searchedText.toLowerCase()) > -1)) {
                        console.log(element.name);
                        files[element.name] = element.size;
                    }
                });
            });
        });
    });
    c.connect(connectionProperties);
    callback(files);
}

module.exports = Files

In my index.ejs file I've got this block and script:

<div id="container">
    <% if (typeof files !== 'undefined' && files ) { for (file in files) { %>
        <p><%= file + " ----- " + files[file] %></p>
    <% }} %>
</div>
<button onclick="getFiles(); return false; %>">LOL</button>
<script>
    function getFiles() {
        searchedText = 'wild'; // wild is used as an example here
        if (searchedText != "") {
            $.ajax({
                type: 'GET',
                cache: false,
                url: "http://localhost:8080/search?t=" + searchedText,
                success: function(data) {
                    $('#container').html(data);
                }
            });
        }
    }
</script>
5
  • callback(files); should be after line files[element.name] = element.size; Commented Oct 20, 2015 at 8:04
  • @RayonDabre : it works but only returns the first element of the Array before sending the error : Error: Can't set headers after they are sent. Commented Oct 20, 2015 at 8:08
  • Is list.forEach performing any async operation ? Commented Oct 20, 2015 at 8:09
  • the Array.forEach method is blocking. But I don't know how to do it in another way ... Any thoughts ? Thx for your help ! Commented Oct 20, 2015 at 8:11
  • Try this: npmjs.com/package/async#each Commented Oct 20, 2015 at 8:32

1 Answer 1

1

I found out how to work it out with async, thx to @RayonDabre

I had to check if the loops were all done before doing my callback function using async (the foreach loop in javascript is blocking so async has to be used).

The code is now :

var i = 0;
c.on('ready', function () {
    folders.forEach(function(folder) {
        c.list("/pools/A/A0/Movies/Films/" + folder, function (err, list) {
            if (err) throw err;
                var j = 0;
                async.forEach(list, function (element, index, array) {
                if (element.name.match("(mkv|avi|mp4|mov)$") && (element.name.toLowerCase().indexOf(searchedText.toLowerCase()) > -1)) {
                    files[element.name] = element.size;
                }
                if ((i == folders.length - 1) && (j == list.length - 1)) {
                    callback(files);
                }
                j++;
            });
            i++;
        });
    });
});`
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.