Skip to main content
Inspiring
September 8, 2017
Answered

Console : Printing objects with more details

  • September 8, 2017
  • 4 replies
  • 8853 views

Hi everyone, I started scripting for after effects 3 days ago and I came across tons of disappointments.

I think the $.write() and $.writeln methods don't do enough. (I'm used to console.log in web development). My biggest problem right now is that if you log an object, it'll only output [object Object].

I'm trying to print the full object with all its properties and sub/sub_sub... objects.

Question #1: Am I missing something? Is there an easy way to do this?

Question #2: if #1's answer is no, do you guys have an idea why I can't print the properties of the sub-objects using this method. (I recommend you guys try it)

var testObj = {

    property_string : "string",

    property_int : 999,

    property_arr : ["test",1],

    property_obj : {

        sub_property_string : "hello"

    }

};

objLog(testObj);

   function objLog(object){

        var log = object.toString() + " {";

        var line;

        for (var property in object) {

            line = "\r" + tabsString(1) + property.toString() + " : " + object[property].toString();

            log += line;

            objLoop(property,object);

        }

        log += "\r }"

        $.writeln(log);

        /*

        * Creates Tabs for the formatting

        * */

        function tabsString(amount){

            var string = "";

            for(var i = 0; i < amount; i++){

                string += "    ";

            }

            return string;

        };

        /*

        * Should be an infinite-able recursive loop to always print the properties of any object at any level.

        * */

        function objLoop(prop,obj){

            var subObject =  obj[prop].toString();

            if(subObject.indexOf("[object Object]") !== -1){

                line = "{\r"

                log += line;

                 for (var subProperty in subObject){

                     /*

                     * Can't get anything to work in this part.

                     * Any object contained in an object won't print it's properties

                     * */

                     line = tabsString(2) + "*Should be printing propeties here*"

                     log += line;

                     line = subProperty  + "\r" + subObject.toString() + " \r";

                     line = "\r" + tabsString(2) + subProperty.toString() + " : " + subObject[subProperty].toString();

                     log += line;

                 }

                log += "\r" + tabsString(2) + "}"

            }

        };

    }

Currently, this will output the following in the javascript console:

[object Object] {

    property_string : string

    property_int : 999

    property_arr : test,1

    property_obj : [object Object]{

       *Should be printing propeties here*

        toJSON :

function () {

                    return this.valueOf();

                }

        }

}

I'm really confused on why it prints

"toJson : function(){ return this.valueOf(); }"

instead of

sub_property_string : hello

Anyway, I hope you guys have better ways than me to print lots of information in the console because I really feel like a newbie.

Thanks a lot!

This topic has been closed for replies.
Correct answer Tomas Sinkunas

Hey buddy, welcome to the club!

I am not a trained programmer, but I've been doing lots of scripting for AE so I will try to explain as best as I can.

1. No, you cannot print/log AE objects. Why? Really hard to tell.AE has some logic to it, that no one knows about. Some time ago tried writing some function that would parse all objects properties and print it's values, but at some point it's still failing. You can test it out AE Script: AE Object to Source — Bitbucket   just pass an AE object to objectToSource() function and it should print some stuff (by default resulting file is saved to desktop).

2. If you want to print/log regular objects, do not reinvent the wheel. Use JSON. However, since ESTK is operating on ECMA 3 (duhhhh) it doesn't natively support JSON. To fix this you have to download/clone this repository GitHub - douglascrockford/JSON-js: JSON in JavaScript​ and then do #include "path/to/json2.js" in your script file. Next time you know it, you can to do alert(JSON.stringify(myObject, false, 4));

-------------

I just re-read your question and I see my #1 reply probably makes no sense. With #1 I was implying to if you want to print LayerObject or CompObject or any other AE object, it's probably not possible

-------------

PS. Sorry I didn't try your function, maybe I should have, but there JSON.stringify for that.

4 replies

New Participant
January 10, 2024

I scrolled through the results and see alternative solutions proposed, but it doesn't seem like anybody helped actually identify why the provided code wasn't working?

 

The original code mostly works, it was just a small issue with the assignment of subObject and updating the if condition. I tested the original code with this fix and it prints recursively as the OP desired

 

function objLoop(prop,obj){

    // ❌ SOURCE OF PROBLEM: subObject is a STRING, not an Object
    var subObject =  obj[prop].toString();

    // ✅ CORRECTION: 
    // var subObject = obj[prop]

    if(subObject.indexOf("[object Object]") !== -1){
    // ✅ CORRECTION: 
    // if (subObject) {

        line = "{\r"
        log += line;

        // ⚠️ Because you created subObject as a string, you are attempting to iterate a string rather than an object
        for (var subProperty in subObject){

            line = tabsString(2) + "*Should be printing propeties here*"
            log += line;

            line = subProperty  + "\r" + subObject.toString() + " \r";
            line = "\r" + tabsString(2) + subProperty.toString() + " : " + subObject[subProperty].toString();
            log += line;
        }
        log += "\r" + tabsString(2) + "}"
    }
};

 

leonardpin
Participating Frequently
November 21, 2021

I worked on the code of my previous answer a little bit more. I do not know why, but I cannot find a way to edit the answer... Anyway, below is my new code:

First the polyfill:

/** 
* @SEE			{@link https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#polyfill Polyfill}
 */

// This polyfill will be necessary below.
if (!String.prototype.trim) {
	String.prototype.trim = function () {
		return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
	};
}

Then, the function to create the string:

/**
 * Creates a string from the entire object (and sub objects).
 * @9397041 {Object} obj Object to be printed in the console (keys and values).
 * @Returns {String} The formatted string of the object.
 */
function objectToString(obj, subObjTab) {
	var log;
	if (Object.prototype.toString.call(obj) === "[object Array]") {
		log = "Array " + " [\r";
	} else {
		log = obj.toString() + " {\r";
	}
	var line = "";
	tab = "    ";
	if (!subObjTab) {
		subObjTab = "";
	}
	var value;

	for (var key in obj) {
		if (typeof obj[key] === "object") {
			subObjTab = "    ";
			line = tab + key + ": ";
			line = line + objectToString(obj[key], subObjTab); // Recursion
			subObjTab = "";
			log += line;
			continue;
		}

		if (typeof obj[key] === "string") {
			line = subObjTab + tab + key + ': "' + obj[key] + '"\r';
			log += line;
			continue;
		}

		if (typeof obj[key] === "function") {
			value = obj[key].toString().trim();
			line = subObjTab + tab + key + ": " + value + "\r" + subObjTab;

			log += line;
			continue;
		}

		line = subObjTab + tab + key + ": " + obj[key] + "\r";
		log += line;
	}

	if (Object.prototype.toString.call(obj) === "[object Array]") {
		log += subObjTab + "]\r";
	} else {
		log += "}\r";
	}

	return log;
}

Then, the code that uses the function:

var myObject = {
	day: "monday",
	hour: 12,
	propertyBoolean: true,
	property_arr: ["test", 1],
	greet: function () {
		$.writeln("Hello");
	},
	subObj: {
		subObjString: "This is the sub object string property",
		subObjMethod: function () {
			$.writeln("Hello from sub object!");
		},
	},
};

$.writeln(objectToString(myObject));

And the expected result:

[object Object] {
    day: "monday"
    hour: 12
    propertyBoolean: true
    property_arr: Array  [
        0: "test"
        1: 1
    ]
    greet: function () {
		$.writeln("Hello");
	}
    subObj: [object Object] {
        subObjString: "This is the sub object string property"
        subObjMethod: function () {
			$.writeln("Hello from sub object!");
		}
    }
}

I hope this helps someone in the future. Peace.

m0riya
Participating Frequently
December 22, 2021

hi, thank you so much!
in order to print objects with 'parent' key like: app.selection or app.document[0], i added to the line:

for (var key in obj) {
    if (typeof obj[key] === "object" && key!=="parent") { // added ' && key!=="parent' ----> in order to Prevent Infinite loop
...
}

I got 2 errors in the function or those lines:

  1. 1. sometimes there isn't an object -so I added if(obj).
  2. a strange error in the for loop above:  when it tries to read from obj[key], it throws an error: "Requested property is only available for wrapped items."

so, I wrapped it with try and catch.

 

your code with my additions:

/**
* @SEE {@link https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#polyfill Polyfill}
*/

// This polyfill will be necessary below.
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
};
}

/**
* Creates a string from the entire object (and sub objects).
* @9397041 {Object} obj Object to be printed in the console (keys and values).
* @Returns {String} The formatted string of the object.
*/
function objectToString(obj, subObjTab) {
var log;
if (Object.prototype.toString.call(obj) === "[object Array]") {
log = "Array " + " [\r";
} else {
if(obj){ // added--> to prevent null Error
log = obj.toString() + " {\r";
}
}
var line = "";
tab = " ";
if (!subObjTab) {
subObjTab = "";
}
var value;
try{
if(obj){ //added
for (var key in obj) {
if (typeof obj[key] === "object" && key!=="parent") { // added ' && key!=="parent' ----> in order to Prevent Infinite loop
subObjTab = " ";
line = tab + key + ": ";
line = line + objectToString(obj[key], subObjTab); // Recursion
subObjTab = "";
log += line;
continue;
}

if (typeof obj[key] === "string") {
line = subObjTab + tab + key + ': "' + obj[key] + '"\r';
log += line;
continue;
}

if (typeof obj[key] === "function") {
value = obj[key].toString().trim();
line = subObjTab + tab + key + ": " + value + "\r" + subObjTab;

log += line;
continue;
}

line = subObjTab + tab + key + ": " + obj[key] + "\r";
log += line;
}
}
}
catch(e)
{
$.writeln(e)
}
if (Object.prototype.toString.call(obj) === "[object Array]") {
log += subObjTab + "]\r";
} else {
log += "}\r";
}

return log;
}

 

m0riya
Participating Frequently
December 22, 2021

i actually arrange it a little bit and used also '@Tomas Sinkunas' code for saving text as file
from the question: https://community.adobe.com/t5/after-effects-discussions/create-a-txt-file-in-extendscript/td-p/9645024

the part of printing the function inside of an object is still needs a little work.


example of saving the object in javascript file:

the object is: app.selection:

 .

the selected path:


the 2 files i edited  is attached.
in order to use them you'll need to change their suffix from 'txt' to 'jsx' 

thank you all for your help- and especially@leonardpin  and @Tomas Sinkunas.
i hope it's helping someone.

leonardpin
Participating Frequently
November 21, 2021

I know I am very late to the party, but this answer may be useful for someone.

This is my function to print the entire object and sub objects:

 

 

/**
 * Prints an entire object (and sub objects).
 * @param {Object} obj Object to be printed in the console (keys and values).
 * @returns Void.
 */
function printEntireObject(obj) {
	for (var key in obj) {
		if (typeof obj[key] === "object") {
			$.writeln(key + ": ");
			printEntireObject(obj[key]); // Recursion
			continue;
		}

		if (typeof obj[key] === "string") {
			$.writeln(key + ': "' + obj[key] + '"');
			continue;
		}

		$.writeln(key + ": " + obj[key]);
	}
	return;
}

 

 

This is the code that invokes the function:

 

 

var myObject = {
	day: "monday",
	hour: 12,
	greet: function () {
		$.writeln("Hello");
	},
	subObj: {
		subObjString: "This is the sub object string property",
		subObjMethod: function () {
			$.writeln("Hello from sub object!");
		},
	},
};

printEntireObject(myObject);

 

 

And this is the expected result in the console:

 

day: "monday"
hour: 12
greet: 

function () {

		$.writeln("Hello");

	}
subObj:
subObjString: "This is the sub object string property"
subObjMethod: 

function () {

			$.writeln("Hello from sub object!");

		}

 

As @Tomas Sinkunas said, JSON.stringify is very useful. But, it does not print the function declarations inside objects. So I decided to create my own.
I hope it can help somebody in the future. Peace.
Tomas Sinkunas
Tomas SinkunasCorrect answer
Brainiac
September 8, 2017

Hey buddy, welcome to the club!

I am not a trained programmer, but I've been doing lots of scripting for AE so I will try to explain as best as I can.

1. No, you cannot print/log AE objects. Why? Really hard to tell.AE has some logic to it, that no one knows about. Some time ago tried writing some function that would parse all objects properties and print it's values, but at some point it's still failing. You can test it out AE Script: AE Object to Source — Bitbucket   just pass an AE object to objectToSource() function and it should print some stuff (by default resulting file is saved to desktop).

2. If you want to print/log regular objects, do not reinvent the wheel. Use JSON. However, since ESTK is operating on ECMA 3 (duhhhh) it doesn't natively support JSON. To fix this you have to download/clone this repository GitHub - douglascrockford/JSON-js: JSON in JavaScript​ and then do #include "path/to/json2.js" in your script file. Next time you know it, you can to do alert(JSON.stringify(myObject, false, 4));

-------------

I just re-read your question and I see my #1 reply probably makes no sense. With #1 I was implying to if you want to print LayerObject or CompObject or any other AE object, it's probably not possible

-------------

PS. Sorry I didn't try your function, maybe I should have, but there JSON.stringify for that.

Inspiring
September 8, 2017

Thanks a lot for your reply. It's very appreciated. I'll test it out and tag your answer as "correct answer" if this all works out.

Oh and thanks for talking about #include it's a concept I didn't know was possible in scripting.

Tomas Sinkunas
Brainiac
September 8, 2017

Oh yeah, #include "" is great. However, if JShint or ESLint or any other linting process is giving you errors with #include "" preprocessor, feel free to use //@include "" instead. Linting process will treat it as a comment, but ESTK will still be able to work with it.