Befor posting this I've been looking up in here as in many other places, but I can get to have this working fully.
All I need is to be able to save some custom properties in all the shapes. The properties are : uuid, and rt_attributes.
Therefore, as by manual I added this code :
fabric.Object.prototype.toObject = (function(toObject) {
console.log(toObject)
return function() {
return fabric.util.object.extend(toObject.call(this), {
uuid: this.uuid,
rt_attributes: this.rt_attributes
});
};
})(fabric.Object.prototype.toObject);
which does work fine, up to a certain degree.
the problem comes when I serialize in json and load back.
the custom attributes are in , but shapes like the IText raise an exception such as :
fabric.js:22199 Uncaught TypeError: Cannot read property 'split' of undefined
Looking into the dumped json I can see the .text attribute is not exported. So My fear is that overriding the toObject I lose some of the custom attributes of the default object.
Of course I can redefine it in my toObject function with all the missing trims, but I though that
fabric.util.object.extend
would have done that for me.
Can someone point me on what I'm doing wrong ?
thanks.
L.
p.s
here is a snippet of the outcome json:
{"type":"i- text","originX":"left","originY":"top","left":29,"top":677,"width":107,"height":22.6,"fill":"rgba(255,255,255,1)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"uuid":"04af6ab4-4eb1-432b-f46a-93b11a92292d","rt_attributes":[["fontFamily","text"],["fontSize","int"],["fill","color"],["opacity","float"],["top","int"],["left","int"]],"styles":{}},
as you can see there's no text field., but uuid and rt_attributes are in.
Finally found the proper way:
fabric.Object.prototype.toObject = (function (toObject) {
return function (propertiesToInclude) {
propertiesToInclude = (propertiesToInclude || []).concat(
['uuid','rt_attributes']
);
return toObject.apply(this, [propertiesToInclude]);
};
})(fabric.Object.prototype.toObject);
Related
I am using a control of Telerik (AutoCompleteBox) which contains an embedded dropdown control that can be accessed through the property _dropDown. I am using the dropDownItemDataBound event to trigger the following code:
var autoComplete = $find("<%= RadAutoCompleteBox1.ClientID %>");
console.log(autoComplete._dropDown._items);
When I click over the [] in the console I get this (that is expected):
[]
0: b.RadAutoCompleteBox.DropDownItem
_attributes: c.AutoCompleteBoxAttributeCollection {_data: {…}, _keys: Array(0)}
_element: null
_template: null
_text: "Chevrolet TRAVERSE "
_value: "GM1"
Thus I supposed that I could do this:
var autoComplete = $find("<%= RadAutoCompleteBox1.ClientID %>");
console.log(autoComplete._dropDown._items[0]._text); // Chevrolet TRAVERSE
console.log(autoComplete._dropDown._items[0]._value); // GM1
Instead I get:
Uncaught TypeError: Cannot read property '_text' of undefined
It doesn't make sense to me because since autoComplete._dropDown._items is obviously an array (and it's NOT undefined!) I should be able to access it by indexing it and get the property contents. Not?
EDIT:
Following the suggestion of #ChrisG that mentioned that perhaps the arry was STILL empty when I tried to log the data to the console, I changed my code into the event to this (to give it a little time and see what happens):
waitAndDisplay();
function waitAndDisplay(timeout = 50) {
setTimeout(function () {
var autoComplete = $find("<%= RadAutoCompleteBox1.ClientID %>");
console.log(autoComplete._dropDown._items[0]._text);
}, timeout);
}
Indeed it worked however it doesn't seem to be a safe approach. Any idea on how to ENSURE that the data is fully loaded before to try to read it?
SOLUTION:
I was after the suggestion of #ChrisG on use a callback to data loaded and figured that I goofed in the documentation of the control because in fact there IS an event that triggers after the dropdown is fully loaded, so I will post the solution here. This way the callback function to be used is OnClientRequested and not the dropDownItemDataBound as I did initially:
function OnClientRequested(sender, eventArgs) {
var myarray = eventArgs.get_data();
console.log(myarray[0].Text);
console.log(myarray[0].Value);
}
It will return the proper data.
I have overridden magento SwatchRenderer.js file in app\code\Mydirectory\CustomSwatches\view\frontend\web\js\SwatchRenderer.js.
My problem is I get an error in my product page load:
Uncaught TypeError: Cannot read property 'updateData' of undefined
I found out that data('gallery') on SwatchRenderer.js's following function is undefined.
updateBaseImage: function (images, context, isProductViewExist) {
var justAnImage = images[0];
if (isProductViewExist) {
context
.find('[data-gallery-role=gallery-placeholder]')
.data('gallery')
.updateData(images);
} else if (justAnImage && justAnImage.img) {
context.find('.product-image-photo').attr('src', justAnImage.img);
}
}
I checked a Magento 2 demo site. On that site the above data attribute is set as a JavaScript object. The target element is a div with the above attribute. But in my site it is undefined and obviously I think that data attribute is not set on my site. Can anyone help me to find the setter function/view/file for above element? Any help would be appreciated. Thanks.
What theme was used in your Magento instance? Did you rename the container class names?
One interesting piece of code is found on line 202 of the SwatchRenderer.js file. Under the _create function you will find the initialization of the gallery variable as seen here
You will notice that it finds the element with the data-gallery under the .column.main element. Thus, as missing column main element would return an empty response.
I found a pretty efficient way to fix this:
Copy the /vendor/magento/module-swatches/view/frontend/web/js/swatch-renderer.js-file to app/design/YourName/YourTheme/Magento_Swatches/web/js/swatch-renderer.js and replace the code inside updateBaseImage() (line ~1152) with the following:
updateBaseImage: function (images, context, isInProductView, eventName) {
var gallery = context.find(this.options.mediaGallerySelector).data('gallery');
if (eventName === undefined && gallery !== undefined) {
this.processUpdateBaseImage(images, context, isInProductView, gallery);
} else {
context.find(this.options.mediaGallerySelector).on('gallery:loaded', function (loadedGallery) {
loadedGallery = context.find(this.options.mediaGallerySelector).data('gallery');
this.processUpdateBaseImage(images, context, isInProductView, loadedGallery);
}.bind(this));
}
},
The trick is: this method doesn't wait for the gallery to be fully loaded, while this event (gallery:loaded) is readily available. By adding this to the method, it works fine.
I just hope that the Magento Dev's pick up on this and implement this in the core-code.
Trying to create query object on clicks on various buttons by sending attributes on html called "attr-{{foo}}" which get their name from an ng-repeat or some other means. I wanted on controller that first tests if the element has all attributes that map onto the keys of the query object in the scope, and continue this if else chain down to having only one attribute; however, when I tried this, I would get the error "cannot find .value of 'null'", as I was testing with
(below you will find a snippet that is representative of my controller)
vm.openFoos = function (event) {
if (event.target.attributes.getNamedItem('attr-foo').value &&
!event.target.attributes.getNamedItem('attr-bar').value) {
var obj = {
foo: event.currentTarget.attributes.getNamedItem('attr-foo').value,
name: $routeParams.name
} else if {
(event.target.attributes.getNamedItem('attr-foo').value &&
event.target.attributes.getNamedItem('attr-bar').value) {
var obj = {
foo: event.currentTarget.attributes.getNamedItem('attr-foo').value,
name: $routeParams.name,
bar: event.currentTarget.attributes.getNamedItem('attr-bar').value
}
}
data.getReviews(obj)
.success(function (data){$log.debug(data)}).error(function(e){$log.debug(e)});
};
This works if I click on elements with both attr-foo and attr-bar (as by the convention of this testing from most strict case of having attributes to least, I know if I had written the if statements in reverse I would get the error "cannot find value of null". Sample HTML:
<span class="one" ng-click="vm.openFoos($event) attr-foo="foooo">Click FOOO</span>
<span class="two" ng-click="vm.openFoos($event) attr-foo="fo" attr-bar="bar">Click FOO BAR</span>
Clicking span.one throws the error "cannot find value of null" but clicking span.two works fine.
I do not want to write a controller for each instance of the combinations of keys in my query appearing on various html attributes; however, I'm getting this error.
instead of using
if (event.currentTarget.attributes.getNamedItem('attr-thing').value ....
use
if (event.currentTarget.attributes.getNamedItem('attr-thing') ....
When
event.currentTarget.attributes.getNamedItem('attr-thing')
does not exist, obviously one cannot take the value of it!
Could you be looking for hasOwnProperty?
object.hasOwnProperty("attrname"); // Yields true or false.
As stated in the title, I cannot get animation to work. I'm pretty sure I'm missing something in my code because it works here, but not where I'm testing.
I create the animation object in playerCharacter.js with
this.init = function(){
for (var k in this.mesh.material.materials) {this.mesh.material.materials[k].skinning = true;}
this.animation = new THREE.Animation(this.mesh, this.mesh.geometry.animations[0].name);
this.animation.play();
}
In the update function I use:
this.animation.update(0.017);
And when I look at the console log I get:
Uncaught TypeError: Cannot read property 'length' of undefined
So it seems that in THREE.AnimationHandler, data.hierarchy is undefined, so I'm guessing that if I can somehow make it defined, the problem will be fixed. Except I don't know how, or even why it is not defined. Any help?
You are passing only the animation's name, not the whole data object. Use this instead:
this.animation = new THREE.Animation(this.mesh, this.mesh.geometry.animations[0]);
So, I've created a function to do some error checking on an XML file that I recieve from an AJAX call. Part of the validation is that the function then builds out an object for easy access while I process that data into a form. In FF, works like a charm. IE dies with the error:
Object doesn't support this property or method
Here is the function (minus the un-important bits):
function checkReceiveXMLTagString( doc, messageObject, tag ) {
var tag_nodes = doc.getElementsByTagName( tag );
...do some error checking...
messageObject[tag] = tag_str; <-- error occurs on this line
return true;
}
Here is an example of how the function is call:
if ( checkReceiveXMLTagString( messageObject.Name[0], messageObject.Name[0], "First" ) ) {
...process messageObject.Name[0].First...
}
Like I said, FF has no issues. Safari loads the pages as well. IE has issues.
Thanks!
Looks like something is making messageObject be null or undefined
If the error is on this line:
messageObject[tag] = tag_str;
Then, the only two ways I know of that that can cause an error are:
messageObject is not an object that you can set properties on (null or undefined are the most likely ways that would happen)
tag is null or undefined
Since I see that your code calls this function hundreds of times so you can't effectively just break on it, I'd suggest you put in some defensive coding to check for those conditions and output something to the debug console to identify what the state is when the problem occurs. You can even trigger a conditional breakpoint with code like this:
if (!messageObject || !tag) {
debugger;
}
In the toughest cases, you can put an exception handler around it and break when the exception is thrown:
try {
messageObject[tag] = tag_str;
} catch(e) {
debugger;
}
Both of these will allow you to capture the condition in the debugger and examine all your parameters at the time of the error.