• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Console : Printing objects with more details

Explorer ,
Sep 08, 2017 Sep 08, 2017

Copy link to clipboard

Copied

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!

TOPICS
Scripting

Views

6.8K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Advocate , Sep 08, 2017 Sep 08, 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 ob

...

Votes

Translate

Translate
Advocate ,
Sep 08, 2017 Sep 08, 2017

Copy link to clipboard

Copied

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 08, 2017 Sep 08, 2017

Copy link to clipboard

Copied

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Sep 08, 2017 Sep 08, 2017

Copy link to clipboard

Copied

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 11, 2017 Sep 11, 2017

Copy link to clipboard

Copied

Hey, I had the time to test this all out and I'm very happy with the outcome. If I create an object myself it prints exactly what I need. So that answers the question. There is still a little issue that I'm trying to fix to really be able to use an awesome object workflow.

Here's an exemple that won't print using Json2.

var ui = {};

ui.window = this;

ui.content = {};

function addUi(name,type,pos,content,params){

   var position = !!pos ? [pos[0],pos[1], pos[0]+pos[2], pos[1]+pos[3]] : undefined;

   if(!!params){ ui.content[name] = ui.window.add(type, position, content, params) }

   else{ ui.content[name] = ui.window.add(type, position, content) }

};

addUi("btnOk", "button", [10, 10, 80, 40], "Ok");

addUi("btnCancel", "button", [100, 10, 80, 40], "Cancel");

addUi("textArea", "edittext", [10,100,200,150], "text", {multiline:true});

the object would look like this:

ui{

     window : this,

     content: {

          btnOk: [button object],

          btnCancel: [button object],

          textArea: [edittext object]

     }

}

So basically I add all the UI elements inside an object named ui. That way they are well organised and if I find a way to print this object, I'll easily be able to find all the objects I need to modify my script UI.

Any idea how I could be able to print that? if not, I might just go all-in and try to modify the json2 script to display something.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 21, 2021 Nov 21, 2021

Copy link to clipboard

Copied

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 21, 2021 Nov 21, 2021

Copy link to clipboard

Copied

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).
 * @Param {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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Dec 22, 2021 Dec 22, 2021

Copy link to clipboard

Copied

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).
* @Param {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;
}

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Dec 22, 2021 Dec 22, 2021

Copy link to clipboard

Copied

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/9645...

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:

 2021-12-23 00_12_12-Clipboard.png.

2021-12-23 00_14_44-Clipboard.png

the selected path:

2021-12-23 00_15_16-Clipboard.png


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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Dec 23, 2021 Dec 23, 2021

Copy link to clipboard

Copied

It is good that the code helped someone.
I changed my code since I posted it here. Only used it a few times...

I did not totally comprehend your usage of it.

I updated mine using your suggestions. I noted a strange thing though:

$.writeln(typeof app.selection);

Running in Illustrator, the engine main could not execute the script. I received an error. Changing the engine to transient, I could execute it. Changing it back to main, I received no error.

 

This is my code with your additions:

/**
 * Creates a string from the entire object (and sub objects).
 *
 * @SEE	{@link https://community.adobe.com/t5/after-effects-discussions/console-printing-objects-with-more-details/m-p/12611158#messageView2_1_8e4f5f8fbc23d1_5 m0riya's answer}
 *
 * @Param {Object} obj Object to be printed in the console (keys and values).
 * @Param {number} [level=1] Sublevel number. Optional. Default 1.
 * @Returns {String} The formatted string of the object.
 */
function objectToString(obj, level) {
	var level = level || 1;
	var log;
	var line; // Represents each line inside object.
	var trimmedStr; // For functions.
	var tabInClosingFunction; // For functions.

	function createTab() {
		return "    "; // 4 spaces
	}

	// The end of the object.
	function closeObj(level) {
		level--;
		var tab = "";
		// Creates the tabulation.
		for (var i = 0; i < level; i++) {
			tab += createTab();
		}

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

	// The beginning of the object.
	if (Object.prototype.toString.call(obj) === "[object Array]") {
		log = "Array(" + obj.length + ") [\r";
	} else {
		// m0riya wrapped the line below with an if(obj) block to prevent null Error.
		if (obj) {
			// log = obj.toString() + " {\r";
			log = obj.reflect.name + " {\r";
		}
	}

	// Added by m0riya.
	try {
		// Added by m0riya.
		if (obj) {
			// Loop through all keys and values.
			for (var key in obj) {
				/*	Clears the line and tabs (for closing } of functions) for the
				next loop iteration. */
				line = "";
				tabInClosingFunction = "";

				// Creates the tabulation.
				for (var i = 0; i < level; i++) {
					line += createTab();
				}

				// In case the value is a string.
				if (typeof obj[key] === "string") {
					line += key + ': "' + obj[key] + '"\n';
					log += line;
					continue;

					/*	In case the value is an object (objects or arrays).
					&& key !== "parent" by m0riya */
				} else if (typeof obj[key] === "object" && key !== "parent") {
					// Do not print inherited properties.
					if (obj.hasOwnProperty(key)) {
						line +=
							key + ": " + objectToString(obj[key], level + 1); // Recursion
						log += line;
						continue;
					}

					// In case the value is a function.
				} else if (typeof obj[key] === "function") {
					if (obj.hasOwnProperty(key)) {
						trimmedStr = obj[key].toString().trim();

						// Creates the tabulation at the end of the function.
						for (var j = 0; j < level; j++) {
							tabInClosingFunction += createTab();
						}

						trimmedStr = trimmedStr.replace(
							/\t+}$/,
							tabInClosingFunction + "}"
						);
						line += key + ": " + trimmedStr + "\n";
						log += line;
						continue;
					}

					// In any other case (boolean or number).
				} else {
					line += key + ": " + obj[key] + "\n";
					log += line;
				}
			}
		}
	} catch (e) {
		$.writeln(e);
	}

	closeObj(level);

	return log;
}

 

Using this function with

app.selection

I receive the errors you mentioned too.

After reading this reference:

Working with selections 

I tried to apply it with

var topObject = app.activeDocument.selection[0];
$.writeln(topObject.typename); // PathItem

Then, I searched for

PathItems 

There, I found the list of methods.

 

I saved the files you shared and tried them a little bit.

But, as I said at the begining, I did not fully comprehend what you are trying to do.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Jan 10, 2024 Jan 10, 2024

Copy link to clipboard

Copied

LATEST

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){

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

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

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

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

        // :warning: 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) + "}"
    }
};

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines