why fabricjs kclass fromobject returning undefined on new version? - undefined

yesterday i have changed fabricjs version in our application. suddenly kclass.fromObject returning undefined.
my previous version is 1.7.22 and currently using 3.6.1 https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js
kclass.fromobject returning undefined. but objects[i] has data.
> var klass = fabric.util.getKlass(objects[i].type);
> console.log(klass.fromObject(objects[i])); //returning undefined on 3.6.1
> fabricObj.add(klass.fromObject(objects[i]));
could you please let me know how to fix this issue?
Here is the screenshot

Your objects array contains just plain javascript objects that represent serialized Fabric objects (like path, circles, whatever).
Before rendering these plain javascript objects you need to transform them in Fabric objects. This process is called deserialization.
Your code does it, but only the if the async property of the variable klass is true.
It happens here:
var klass = fabric.util.getKlass(objects[i].type);
if (klass.async) {
klass.fromObject(objects[i], function (img) {
canvas1.add(img);
});
}
The object is deserialized, passed as an argument to the callback function and then added to the canvas, and this is great.
The problem is in the else branch of your conditional, where nothing of that happens. The only code present is this:
else {
console.log(objects[i]);
canvas1.add((objects[i]));
}
Here you are trying to add the plain object to the canvas, and that triggers an error.
One simple solution is to remove the if / else and always execute the deserialization step. If for other reasons you need to maintain the if / else conditional, you can simply deserialize the object in the else path too.
Here is a working Fiddle that preserves the conditional.
Why did it work in the previous version of Fabric? It is hard to say. Maybe that type of object was marked as async, so triggering the right path. Or maybe the canvas.add method was automatically deserializing javascript objects.

Related

JSON Compatible Output of Whole Object and Their Invisible Properties in Node

const TelegramBot= require('./telegram-bot') // It's currently only local.
var bot = new TelegramBot()
console.log(bot)
// This does not print a complete JSON of the object. It misses stuff like
constructor, method, prototype and super_.
Is there some way or npm module that prints a JSON compatible output of the object?
My only work around so far is console logging it out like this and repeatedly checking the log and printing out another but I think it'll be a lot of easier by having a JSON export and using a JSON online viewer that views like a directory tree.
console.log(`
TelegramBot:
> ${Object.getOwnPropertyNames(TelegramBot)}
TelegramBot.prototype:
> ${Object.getOwnPropertyNames(TelegramBot.prototype)}
TelegramBot.prototype.constructor:
> ${Object.getOwnPropertyNames(TelegramBot.prototype.constructor)}
TelegramBot.prototype.constructor.super_:
> ${Object.getOwnPropertyNames(TelegramBot.prototype.constructor.super_)}
`)
I'm aware functions can't be seen with JSON.parse(). I don't mind if they appear as a string like "Anonymous Function()" or "FunctionWithAName()". Or something like this.
I'm doing this since I'm having another go trying to learn prototypes and I've used util.inherits(TelegramBot, EventEmitter) in the TelegramBot object.
To avoid name clashes between TelegramBot methods I've made and the super class of EventEmitter names. I'd like to keep a clear view of the whole object structure. Or do I not have to worry since they use this variable shadowing thing? If I'm correct it checks the object's instance first, then it's prototype. Not sure if EventEmitter prototype checked first or TelegramBot's.

NPM 'should' library causes circular reference error when calling JSON.stringify on object

Now I know why I avoid libraries like should that modify the object prototype
It looks like I get this error:
TypeError: Converting circular structure to JSON
when I require('should')
Is this expected?
before calling JSON.stringify, I can delete the properties from the object to be stringified like so:
delete obj.should;
delete obj.getShould;
but this is hard to do with nested objects etc. I have to say, this is pretty lame that should causes this, but maybe I am doing something wrong. How to fix this problem? I am writing a library and the user might require('should') so I have to protect against this type of issue.
Though with slightly different output, util.inspect() provides output without circular reference breaking it. Also it provides means to customize the object inspection. Will it work for you?
Should is not setting properies directly on the object, but rather on it's propotype:
Object.defineProperty(Object.prototype, 'should', {
set: function(){},
get: function(){
return should(this);
},
configurable: true
});
It must be something else that prevents an object from being serialized.

AdvancedDataGrid - access dataProvider

I have AdvancedDataGrid and I wanted to access dataProvider.getItemAt(i) in function in my view.
I'm not getting any errors nor warning and the code is compiling, but when I run this function I get this error:
Property getItemAt not found on mx.collections.HierarchicalCollectionView and there is no default value.
Why can't I do this? I saw some samples ane people was using this function.
This is how I call it:
var x:Object = _dg.dataProvider.getItemAt(i);
The AdvancedDataGrid's dataProvider is a generic object. That, basically, means the compiler will let any property/method access on it slide without issues.
The HierarchicalCollectionView does not have a getItemAt() method, which is why you get the runtime error. The Hierarchical collection, by nature, contains nested elements I'm not sure how you'd access a single element using a single index.
You probably want to use some form of getChildren() or getParentItem() method to get access to an individual node.
The places where you saw getItemAt() work were most likely using an ArrayCollection.

AMF as a REST format, using BlazeDS and AS3's URLLoader

I have a ColdFusion server with an HTTP API that's currently returning either JSON or XML formatted responses. Internally, all of these responses are represented using the ColdFusion 'struct' type, and then converted to the appropriate format before being presented to the requesting client.
The client team using this API has requested that in addition to JSON and XML, we also return AMF objects. Now, I've seen (and have myself made) arguments against using AMF as a 'returned format' in a REST scenario rather than as an RPC format. I'm not interested in comments about whether or not it's a good idea -- I'd just like to know if it will work. If not, I'm hoping for clear reasons why it won't. If it will work, I'd love some guidance on how to 'makeitgo'.
So, in the interest of achieving that proof of concept example, I'm trying to serialize a two-element ColdFusion Array using BlazeDS, then consume that serialized object in a Flash Player 10/AS3 test.
Here's what the code looks like on the server side:
//the test object I'm trying to return (keeping it simple)
var testArray = ArrayNew(1);
testArray[1]="test";
testArray[2]="monkey";
//set up output stream to requesting client
var pc = getPageContext();
var response = pc.getResponse();
var out = response.getOutputStream();
response.setHeader("Content-Type", "application/x-amf");
//not sure if AmfMessageSerializer is the appropriate class to be using here
var amfMessageSerializer = createObject("java", "flex.messaging.io.amf.AmfMessageSerializer");
var amfTrace = createObject("java", "flex.messaging.io.amf.AmfTrace"); //needed by initialize() method
amfMessageSerializer.initialize(variables.SerializationContext.getSerializationContext(), out, amfTrace);
amfMessageSerializer.writeObject(testArray);
out.close();
Now, this generates some kind of binary data. If I stick that in a .cfm and try to load the page, I get something I can read in a hex editor that looks like it contains the array members I set. One note here: part of the response message includes "flex.messaging.io.ArrayCollection." I'm not knowledgeable enough to know what this tells me yet: anyone who can provide details about typing between the two environments will have many thanks from me.
The next step is to try and consume this on the FlashPlayer side. Here's what the stripped down AS3 looks like:
myURLloader.dataFormat = URLLoaderDataFormat.BINARY;
myURLloader.addEventListener(Event.COMPLETE, completeHandler);
myURLloader.load(myURLRequest);
function completeHandler( event : Event) : void
{
var serverResponse : ByteArray = new ByteArray();
serverResponse = event.target.data;
//read the response into a generic object
var responseObject : Object = new Object();
responseObject = serverResponse.readObject(); //fails here: error #2006
}
As indicated by the comment, this fails with error #2006 "Supplied index is out of bounds." I've searched around for common causes of this error, but haven't found any clear answers. I've tried resetting the byteArray.position to both the beginning and the end of the byteArray before attempting readObject() -- changing it to the end spits out error #2030 "End of file was encountered" (as one might expect), but I've verified that the .position defaults to 0, which generates the #2006 error.
I'm pretty sure that the issue here lies with the choice of BlazeDS calls I've used; I think I might be serializing a message when I want to be serializing an object. Unfortunately, the JavaDoc autogenerated docs for BlazeDS are ... less than enlightening. All of the more readable resources I've found focus on Flash Remoting and RPC examples. Surprising, I know; but it is what it is. I'm using Adobe BlazeDS docs; if anyone else has a better resource I'd be quite appreciative.
As a reminder to anyone answering: I realize this isn't a typical use of AMF. I'm not interested in responses that suggest the typical RPC method or to switch to Flash Remoting rather than HTTP/GET. What I need is an AMF serialized response from an HTTP request which can be deserialized on a Flash Player client. I don't have a choice in this matter. I do need to know if this is possible, and if so I'm hoping for some guidance on how to make it work. I welcome any and all suggestions aside from "Just don't use AMF!" or "Just switch to Flash Remoting!"
Update: made a little bit of progress with this:
1) on the server side, I used the ASObject class of blazeDS to create a simple ASObject and populate it with a key-value pair.
2) on both the client and server side, I had to make sure to set the object encoding to AMF0. The same technique in AMF3 generates that #2006/Out of bounds error, and I'm not yet sure why.
Here's what the code now looks like on the server-side:
//set up output stream to requesting client
var pc = getPageContext();
var response = pc.getResponse();
var out = response.getOutputStream();
response.setHeader("Content-Type", "application/x-amf");
//not sure if AmfMessageSerializer is the appropriate class to be using here
var amfMessageSerializer = createObject("java", "flex.messaging.io.amf.AmfMessageSerializer");
amfMessageSerializer.setVersion(variables.MessageIOConstants.AMF0);
var amfTrace = createObject("java", "flex.messaging.io.amf.AmfTrace"); //needed by initialize() method
amfMessageSerializer.initialize(variables.SerializationContext.getSerializationContext(), out, amfTrace);
var ASObject = createObject("java", "flex.messaging.io.amf.ASObject");
ASObject.put("testKey", "testValue"); //simple key-value map to return to caller
amfMessageSerializer.writeObject(testArray);
out.close();
The primary difference here is that rather than trying to serialize a CF Array, I'm building a response object (of type ASObject) manually.
On the client side, the code now looks like this:
myURLloader.dataFormat = URLLoaderDataFormat.BINARY;
myURLloader.addEventListener(Event.COMPLETE, completeHandler);
myURLloader.load(myURLRequest);
function completeHandler( event : Event) : void
{
var serverResponse : ByteArray = new ByteArray();
serverResponse = event.target.data;
serverResponse.objectEncoding = ObjectEncoding.AMF0; //important
//read the response into a generic object
var responseObject : Object = new Object();
responseObject = serverResponse.readObject();
trace(responseObject.testKey); //displays "testValue", as expected
}
The difference here is that I've explicitly set the ObjectEncoding to AMF0 (defaults to AMF3).
If I switch the objectEncoding to AMF3 on both server and client, I'd expect things to work, but I still get the 2006: out of bounds error. The ByteArray.length property is the same in both the AMF0 and AMF3 cases, but the content of the returned object is different (when viewed in a hex editor).
Changing the objectEncoding in the first example I provided had no effect on the error that was being produced.
So, then, the issue seems to have been an attempt to serialize the ColdFusion array: the AMFSerializer doesn't know how to handle it. It needs to explicitly be built as an ASObject. I'll build a sanitize function to do the conversion between the two types.
I feel like progress has been made (and thanks for all the feedback in comments and answers), but I've still got a lot of unanswered questions. Does anyone have any input on why this might be failing when I try to encode in AMF3, but not for AMF0? I don't have any attachment to one or the other, but I don't like this 'throw things at the wall and see which ones stick' method of solving the problem... I'd like to know why it's failing =/
I did that a some time ago..you can check my blog post from here, maybe it can help you. I was using Java on the server side, not CF.

Modifying 'global' object in Node.js

Is there any reason why the following code:
global.myNamespace = {};
fails to add 'myNamespace' to the global object, i.e.
typeof global.myNamespace
returns
'undefined'
Node.Js 0.3.1-pre
You're probably trying this code in the node-repl. The repl is special in that every command submitted gets a new context. That means a brand new global object. Any of your variables in the old context can still be found, but all of the global js variables are replaced with brand new ones. That includes global, Object, Array, etc.
What you're doing will work fine in a script. Just not in the repl.