Bindable vs dirty flag in commitProperties - actionscript-3

What is the best way to bind a property to a component in Flex?
Say I have to update the text field of a TextArea. We can do it in two ways:
1.
AS3:
[Bindable]
private var myText:String;
//setters getters
MXML:
<mx:TextArea id="description" text="{myText}"/>
2.
AS3
private var myText:String;
private var myTextChanged:Boolean;
public set myText(pText: String): void
{
if (myText != pText)
{
myText = pText;
myTextChanged = true;
invalidateProperties();
}}
override protected function commitProperties():void
{
//other code
if (myTextChanged)
{
description.text = myText;
myTextChanged = false;
}
MXML
<mx:TextArea id="description"/>
AFAIK, the second way is clean, but has lot of code and extra variables (dirty flag). But I am not sure about the first way as I see Bindable tag is not preferred for performance implications.
Anyone with any thoughts?
Thanks in advance.

In your particular lightweight example the answer is… there is no difference. But that's only because I know the TextInput.text property uses the second method and commitProperties.
If you set the TextInput.text property 1000 times it will only draw once.
Not all code functions this way even though the framework prescribes it… it does not enforce it and sometimes when you're setting a property with bindings it can kick off many other methods behind the simple property set and does not use commitProperties and invalidation to batch the updates.
Also the code that the compiler generates for binding is not efficient. If you have a mobile project I would avoid bindings.
Also you're not binding to an object and a property (i.e. myObject.myText) but a simple string. This is where binding is useful. You're example falls down in this case and would require dispatching a custom event from myObject when the myText property changes.
Binding is always inefficient in that the code that's generated is verbose and is not as simple as a callback or using invalidation. That being said it's almost always acceptable from a performance standpoint to use bindings in place of writing a bunch of code to do exactly the same thing.
Another gotcha is that bindings are also static in nature. In other words… they exist in the global scope and cause user interface elements to stick around and not be garbage collected. A good example of this is binding to the data property in an itemRenderer that get's recycled. It is always a bad idea to use data binding in an item renderer because of this. You should override the set data(v:Object):void and/or use commitProperties.
For the record… I like binding… I use it all the time. You just have to understand that:
There is a performance hit.
It doesn't obey Flex's invalidation model (i.e. commitProperties)
It occurs in the global scope and can cause objects to hang around.
If you want to have a look at the code the compiler generates you can add a compiler option:
-keep-generated-actionscript=true

Related

Polymer 1.0: Does <iron-meta> support binding to dynamic variables?

I can get my <iron-meta> instance to work properly when using a static value. But when I bind the value to a dynamic variable (using {{}}) it <iron-meta> no longer behaves as expected.
Does <iron-meta> support binding its value to dynamic variables?
<iron-meta id="meta" key="info" value="foo/bar"></iron-meta> // works
<iron-meta id="meta" key="info" value="{{str}}"></iron-meta> // fails
Previous work
This question is a refinement of this question in order to clarify that the ONLY thing causing the problem is the change from a static string value to a dynamic string value binding. I was getting a lot of other suggesting that had nothing to do with the change from static to dynamic so I thought it might be best to rewrite the question to clarify that. But the entire code context is contained in the links there if that would help.
Alternative solutions
There has been some recent chatter about using <iron-localstorage>. Perhaps that is the best way to go for dynamic binding essentially creating global variables?
Yes, <iron-meta> does support binding to variables, but perhaps not in the way you think.
Example: http://plnkr.co/edit/QdNepDrg9b3eCTWF6oRO?p=preview
I looked through your code here, here, and here but I'm not entirely clear what your expectations are. Hopefully my attached repro might shed some light. I see you have declaratively bound <iron-meta id="meta" key="route" xvalue="foo-bar" value="{{route}}"></iron-meta> which is fine - when route changes, iron-meta's key="route" will update accordingly.
However, be aware that in Polymer 1.0, <iron-meta> is in essence a one-way bind from parent to child in the sense that you set a meta key value dynamically by binding to a property; but to get that value, you'll have to get it imperatively via iron-meta's byKey() method.
<iron-meta> is just a simple monostate pattern implementation without an in-built path notification mechanism. What this means is value changes do not propagate upwards. Therefore, doing something like
<!-- this does not work like the way you think -->
<iron-meta id="meta" key="foo" value="{{bar}}">
in order to get the value of foo, or listen to changes to foo, does not work. This behaves more like a setter, where you set the value of foo based on your data-bound property bar.
From what I gather, it seems that you're trying to implement some sort of global variable functionality. A monostate implementation used to work in Polymer 0.5, but not in 1.0. Unfortunately, until Google endorses a "best-practice" pattern for this, suggestions till-date seems a bit speculative to me. You might find this (Polymer 1.0 Global Variables) helpful.
I have had success using <iron-signals> to communicate global information. I know there is a warning in the <iron-signals> documentation that discourages its use for related elements, but when broadcasting a shared resource it seems just the thing. For example:
// source element
var db = SomeDB.init();
this.fire('iron-signal', { name: 'database', data: db });
<-- sink element -->
<iron-signals on-iron-signal-database="dbChange"></iron-signals>
class SinkElement {
dbChange(e, detail) {
this.db = detail;
this.db.getSomeData();
}
}

as3 Variables changing impossibly

I'm having an issue with a "Point" type variable velocity changing without any calls to change it.
private function framecode(e:Event) {
trace(getVelocity().y);
tracks.gotoAndStop(2);
trace(getVelocity().y);
}
This code is part of a class called "tank" which extends the one that velocity is used in (my moving object class). velocity is a private point type variable and getVelocity() is a public access method. tracks is a named movieClip contained inside the one linked with tank. The event listener is ENTER_FRAME. There is no coding on the frames of tracks.
Somehow these two traces give different values (the first one being correct) and I can't figure out how the gotoAndStop() can possibly effect it (and hence how to fix it).
I've found that play() does not reproduce the bug but prevFrame() and nextFrame() do. As the variable is private this class should not even have access to it to change it.
Another strangeness is that if the event listener is changed to FRAME_CONSTRUCTED or EXIT_FRAME, there is massive lag and my movieClip randomly disappears after a few seconds.
Thank you for reading, any help would be appreciated.
Your velocity variable is private, so one one can access that outside of the class.
However, getVelocity() is returning a reference to your velocity variable. Once someone has that reference, they can change the values of it's properties: getVelocity().y = 3. So it's not impossible for this to happen.
One way to trouble shoot this is to add a trace() statement to/set a breakpoint in getVelocity() so you can see where it's being used.
You could do something similar w/the Point class, but you'll have to extend it, add getter/setter methods for y (that traces out when they are called), and modify your code to use the getter/setter. This might be worthwhile (its simple enough), and the act of modifying your code to use the getter might help you discover where the problem is.

dynamic class in AS3 : listening to property creation?

I'm currently working on a project that involve a re-implementation of the Array class.
This object needs to be an Array for compatibility reasons, while I also need to keep control of what is written in.
I cannot seem to find any way to check property creation inside of a dynamic object in AS3. Something that would work like the Event.ADDED_TO_STAGE but, like, ClassEvent.PROPERTY_ADDED.
I override methods like push, splice etc, but I cannot control direct assignation : MyArray[i] = ...
Is such a thing even possible ?
Of course, I could make some kind of validations elsewhere, but this would involve accessing a part of the code I cannot modify.
Thanks for your time !
I'm not sure I follow you entirely but you may be looking for the Proxy class:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Proxy.html
An example at the bottom shows you how you can override direct assignment:
override flash_proxy function setProperty(name:*, value:*):void {
_item[name] = value;
}
Using this you would be able to dispatch a custom event that would be fired any time an item was added to your ProxyArray

What is the data type from the source of an image

another flashbuilder brainbreaker for me...
I have a class with a contstructor that should only change the source of an image.
[Bindable]
[Embed(source='../pictures/test.jpg')]
private var _picture:Class;
public function Test(newSource:*****)
{
_picture.source = newSource;
}
(the image is not an image, but a class, I am aware of this, it is meant to be so :-) )
The problem is that when I call the constructor, let's say:
var test:Test = new Test(pictureAtStage.source);
Flashbuilder will give an error, becouse I can't tell the compiler what data type "newSource" at the constructor will have...
*edit:
When i use _picture.source, the embedded source does not seem to be changed...?
Anyone knows an answer?
Are we talking about mx.controls.Image? if so, then the source of an image can be: a Class, a Bitmap (not a BitmapData), a String (in which case it is assumed that you wanted to load it instead of using an embedded one). If you want to find a common denominator for all these, then Object is that class, however, I would rather limit it to something particular to your use case.
However, if I may advise anything... don't use mx.controls.Image, it's too bloated, even for Flex framework. If it must be a UIComponent - extend UIComponent and let the source be of type BitmapData - this way you will be able to manage resources better - you could reuse the same actual image for example. You could then use graphics property of the control to display the image.
Another advise, if you are still here :) Don't use [Bindable], especially the short version of it, especially not on a private variable - you will save yourself the frustration of countless hours of debugging it... Besides, in your case you aren't going to change the value of that variable anyway...
Are you still here? Well, don't use [Embed] on variables, use it on class definition - slightly more work for you, but this will, potentially, make your code more portable. If you embed on class the compiler will not generate a silly "something-something-Asset" class, it will use Bitmap or BitmapData - whichever your class extends. Thus, you will not introduce a dependency on Flex framework, and, in general, you will have more control over your code.
EDIT: the above was written assuming that _picture (class) variable and _picture (some variable used in a function) are not the same thing. But if they are the same thing, then Class class is dynamic, which means that you can add to it properties at runtime (don't know why, it's a design decision by Adobe...), however, the compiler will act as if it's not possible, so you would work around that by adding the property through reflection:
var _picture:Class = Sprite;
_picture["source"] = whatever;
trace(Sprite["source"]);
This is indeed slightly confusing, It will be of the type BitmapAsset which extends Bitmap. So any of those will work.
Since I'm very new to flashbuilder I didn't see the obvious solutions...
The solution for the first part of my question (before the edit):
Setting the data type to Object did the trick:
[Bindable]
[Embed(source='../pictures/test.jpg')]
private var _picture:Class;
public function Test(newSource:Object)
{
_pucture.source = newSource;
}

AS3 override addChild(), test for type

this works for me, but does it look correct in terms of as3 best practices. is it correct to return null if it fails?
override public function addChild(child:DisplayObject):DisplayObject {
if(child is Screen) {
super.addChild(child);
return child;
}
return null;
}
I don't see why not. I've never actually used a return value of addChild in practice. You'd need some way of knowing if the child had been added so you could then use:
if (!addChild(child))
{
//couldn't be added
}
instead of
if (child is Screen)
{
addChild(child);
}
else
{
// couldn't be added
}
Or you could instead throw an error in your override and catch that if it's not an instance of Screen.
I don't think it's a best practice issue at all if it works for you.
I see a couple of options and none feels completely "right".
The best solution, as I see it, is not possible in Actionscript (I think this is allowed in other languages). That is, declare that you will accept only instances of Screen:
override public function addChild(child:Screen):Screen {
return super.addChild(child);
}
Since that's not possible, the other options I can think of would be:
1) Throwing an Error.
I'm generally not very fond of throwing Errors, but a pro here is that it matches the behaviour of the extended class. If you pass a non valid display object to addChild, it will throw. On the other hand, this is valid given that the method signature tells you that you have to pass a DisplayObject. In this case, your method is "lying", in a way, because it says it accepts DisplayObjects but it really only accepts instances of Screen. So you are relying in documentation (hopefully) rather on the type system to tell the user code how it's supposed to use your function.
2) Adding an addScreen method that calls addChild.
public function addScreen(child:Screen):Screen {
return super.addChild(child) as Screen;
}
This is somewhat more typesafe, but you lose some of the advatanges of polymorphism (and perhaps it's not possible / feasible in your code). Maybe if we had method overloading... but we don't so, again, I guess it's a tradeoff.
3) Runtime type checking and returning null on failure.
This is what your code does. It could be just fine. What I don't like about it is what I mentioned above: that your method is kind of "lying". I don't expect a method that takes a DisplayObject to fail because I passed a DisplayObject. But well, sometimes, this is not a big deal.
I'm afraid I can't really give a definite answer on this. If possible, I think I'd probably go with option 2), but all these options seem equally valid. At some point you have to settle for the one that makes more sense for you and your project, I guess.
There is no good way to do, what you want to. If you want the desired behaviour, you are to use composition instead of inheritance. What you're trying to do is violating the Liskov substitution principle.