Activity › Forums › Adobe After Effects Expressions › Mutual recursion: this.function is undefined. error.
-
Mutual recursion: this.function is undefined. error.
Posted by Miguel De mendoza on September 3, 2015 at 8:59 amHello, I’m writing a ‘static’ class to walk arround Project ítems. I want it to be abstract as posible so I can walk arround layers and properties as needed. The code bellow works for me when no folders are included on the selected item, but when I include a folder, gives me an error: this.crawl is undefined. Someone can see why is this happening?
var proj = app.project;
var Spider = {crawl : function(callback, object){
for(i = 1; i <= object.numItems; i ++){
subObject = object.item(i);
callback(subObject);
}
},getName : function(obj){
name = obj.name;
return name;
},getNames : function(obj){
if(obj instanceof FolderItem){
this.crawl(this.getNames, obj)
}
else{
this.getName(obj);
}
}
}items = proj.selection[0];
spider.getNames(items)
Miguel De mendoza replied 10 years, 8 months ago 2 Members · 6 Replies -
6 Replies
-
Xavier Gomez
September 3, 2015 at 9:39 amTo see what happens, run the script step by step (using the down arrow button instead of the “play” button).
if obj is a folder, this.getNames(folder) will do:
–> this.crawl(this.getNames, folder)
–> for all children of folder, execute handler(child), ie this.getNames(child).
but now, inside this.getNames(child), this is no longer your spider object but the global object.If you replace everywhere “this” by “spider” it will work.
Xavier
-
Miguel De mendoza
September 4, 2015 at 8:57 amI see. Thanks for help again Xavier!. I changed ‘this’ for ‘Spider’ and don’t give me the error, but now seems that the crawl function overwrites itself on the stack on each new call, and don’t return to the ‘upper level’. I come from C++ and I don’t understand how a function can loose his scope inside an object, so I think I need to review scopes in JavaScript :/
-
Miguel De mendoza
September 4, 2015 at 11:00 amI try to explain:
All my projects start with the same configuration: lots of scenes, vectors and images that need to be precomposed, organized and linked to their own controllers on the top level comps. The footage is organized in their respective folders on my system, so I want to automatically import the project structure from footage folder and create the comps and controls I need, based on that structure and a code system in the footage names (ie: 1.1-Plane_One-Planes.eps, 2.3-Building_B-City_One.png,…), and put all comps in the correct folder on the project.That said, one of the common tasks I have to do is to walk over several tree structures: folders, Project ítems, layers and properties, and my idea was to make a prototype of recurisive function to do the walk, and adapt it for each access type.
I hope it is understandable XD
-
Xavier Gomez
September 5, 2015 at 5:29 pmIt’s possible to give a uniform treatment to layers and items since they belong to a collection, but there is no seach thing as a PropertyCollection, so that properties/propertyGroups would have to be handled differently.
For instance i do use something like your spider object, and it is organized like this:
var $coll = {forEach : function forEach(coll, callback){
var n, N=coll.length;
for (n=1; n<=N; n++){
callback(coll[n], n, coll);
};
return;
},find : function find(coll, filter){
var n, N=coll.length;if (filter(coll[n], n, coll)) return coll[n];
},
return null;
},indexOf : function indexOf(coll, x){
var n, N=coll.length;
for (n=1; n<=N; n++){
if (coll[n]==x) return n;
},
return 0;
},// etc,, etc
};So $coll.forEach would be the equivalent of your spider.crawl
I find it usefull too, so you can write things like :var footageFolder = $coll.find(app.project.items, function(element, index, collection){return element.name === “Footage” && element.typeName === “Folder”;}) || app.project.items.addFolder(“Footage”);
(this searches a folder called “Footage” and creates it if not found).
But as soon as recursions are involved i found it a lot clearer to write full code, since there are many ways to recurse through a folder architecture.
Here is a very basic starting block to import and then create.
It only import basic footage (image, video) and creates comps at a fixed size/duration (not based on content!).
It would require quite a lot of work to turn it ito what you actually want, but it can help to start with:function recursiveImport(sysFolder, aeFolder){
// create a AE folder and parent it to aeFolder:
var folder = app.project.items.addFolder(sysFolder.name);
folder.parentFolder = aeFolder || app.project.rootFolder;var files = sysFolder.getFiles();
var n, N=files.length;for (n=0; n<=N; n++){ if (files[n] instanceof Folder){ recursiveImport(files[n], folder); } else{ try{app.project.importFile(new ImportOptions(files[n])).parentFolder = folder;}catch(e){}; }; }; return folder; }; function recursiveCreate(aeFootageFolder, aeCompFolder, compSpec){ var N=aeFootageFolder.items.length, n, item; var comp = aeCompFolder.items.addComp(aeFootageFolder.name, compSpec.width, compSpec.height, compSpec.pixelAspect, compSpec.duration, compSpec.frameRate); for (n=N; n>0; n--){
item = aeFootageFolder.items[n];
if (item instanceof FolderItem){
comp.layers.add(recursiveCreate(item, aeCompFolder.items.addFolder(item.name), compSpec));
}
else{
comp.layers.add(item);
};
};
return comp;
};(function(){
var sysFolder = Folder.selectDialog();
if (!sysFolder) return;var allFootageFolder = $coll.find(app.project.items, function(element, index, collection){return element.name === "Footage" && element.typeName === "Folder";}) || app.project.items.addFolder("Footage");
var thisFootageFolder = recursiveImport(sysFolder, allFootageFolder);var allCompFolder = $coll.find(app.project.items, function(element, index, collection){return element.name === "Comps" && element.typeName === "Folder";}) || app.project.items.addFolder("Comps");
var thisCompFolder = allCompFolder.items.addFolder(thisFootageFolder.name);
var compSpec = {
width : 1280,
height : 720,
pixelAspect : 1.0,
duration : 10,
frameRate : 25
};recursiveCreate(thisFootageFolder, thisCompFolder, compSpec);
return;
})();
Xavier.
Edit: tried to correct the <= bugs, if failed again i give up.
-
Miguel De mendoza
September 7, 2015 at 4:02 pmWow! That’s awesome! I looks pretty good. I have an overflowed week so I will paly arround with it this weekend. Thanks for help Xavier!
Reply to this Discussion! Login or Sign Up