Search code examples
javascriptangularjsasynchronousiframeangularjs-watch

Disable the listener to src of iframe


I have an iframe in my template, src refers to a physical html file.

<iframe id="myiframe" src="{{src}}">
</iframe>

In the controller, a function rewriteAllFiles is called from time to time to update the physical html, js, css files. It first removes all the old files, then write the new one, then refresh the iframe.

var refreshIframe = function () {
    var iframe = document.getElementById('myiframe');
    iframe.src = iframe.src;
    console.log("refreshIframe, done")
}

rewriteAllFiles = function (path, files) {
    return $http.post('/emptyDir', { dir: prefix + idP + "/", path: path })
        .then(function (res) {
            console.log("rewriteAllFiles /emptyDir, done");
            return $http.post('/writeFiles', { dir: prefix + idP + "/", files: files })
                .then(function (res) {
                    console.log("rewriteAllFiles /writeFiles, done");
                    refreshIframe();
                    return res
                })
        })
}

$scope.$watch(... {
    return rewriteAllFiles($location.path(), $scope.files);
})

My test shows sometimes it works without error, but sometimes, it gives the following log:

rewriteAllFiles /emptyDir, done
GET http://localhost:3000/tmp/P0L7JSEOWux3YE1FAAA6/index.html 404 (Not Found)
rewriteAllFiles /writeFiles, done
refreshIframe, done

So it seems that after the old files are removed and before new files are written, the html template tries to load src, and of cause the file is temporarily unavailable. I did not set a watcher for src, does anyone know where is the listener to src, and how to disable it?

Edit 1: here is the code of writeFiles in the server side:

router.post('/writeFiles', function (req, res, next) {
    var dir = req.body.dir, files = req.body.files;
    var fs = require('fs');
    var queue = files.map(function (file) {
        return new Promise(function (resolve, reject) {
            fs.writeFile(dir + file.name, file.body, function (err) {
                if (err) return reject(err);
                console.log(dir + file.name + " is written");
                resolve(file);
            })
        })
    });

    Promise.all(queue)
        .then(function(files) {
            console.log("All files have been successfully written");
            res.json(dir);
        })
        .catch(function (err) {
            return console.log(err)
        });
});

Solution

  • I realise that it is related to another line of code in the controller.

    $scope.src = getSrc() // getSrc(); returns the right html link initiated by a resolving 
    
    $scope.$watch(... {
        return rewriteAllFiles($location.path(), $scope.files);
    })
    

    When we load the template, the above code has a possibility that $scope.src = getSrc() is executed just after after the old files are removed and before new files are written, which raises a Not Found error.

    So we just need to make sure the execution order by then; the following code works:

    $scope.$watch(... {
        return rewriteAllFiles($location.path(), $scope.files)
            .then(function () {
                $scope.src = getSrcP();
            });
    });