I know an ItemRenderer is a ClassFactory and that you can use the newInstance method of ClassFactory to get an instance of the ItemRenderer. My question, however, is is it possible to use methods of the ItemRenderer without using ClassFactory.newInstance()?
In my case I can't use this newInstance method because it doesn't keep the state.
Is there any way I can do this? Thanks!
An ItemRenderer is a component, like any other. The itemRenderer property of a list based class has a value of a ClassFactory. If you have a reference to an instance of the itemRenderer component, you can call methods on it.
You cannot call a method on any component if an instance if that component instance has not been created yet. So to call a method on an itemRenderer without using ClassFactory.newInstance() you must manually create your own instance using the new keyword.
You might want to implement the ItemRenderer as smart as it is needed to recreate the state depending in the data being set. On the other hand, make sure that the data contains everything needed. You barely want to interact with the renderers in a different scope then the renderer itself.
If it should necessary, a DataGroup dispatches a RendererExistence event when a renderer is added.
private function newList():List {
const list:List = new List();
list.addEventListener(FlexEvent.INITIALIZE, list_initializeHandler);
return list;
}
private function list_initializeHandler(event:FlexEvent):void {
const listBase:ListBase = ListBase(event.target),
dataGroup:DataGroup = listBase.dataGroup;
dataGroup.addEventListener(RendererExistenceEvent.RENDERER_ADD, dataGroup_rendererAddHandler);
dataGroup.addEventListener(RendererExistenceEvent.RENDERER_REMOVE, dataGroup_rendererRemoveHandler);
}
private function dataGroup_rendererAddHandler(event:RendererExistenceEvent):void {
// renderer added
}
private function dataGroup_rendererRemoveHandler(event:RendererExistenceEvent):void {
// renderer removed
}
This is the way to go if you need to reference single item renderer instances.
Do you mean static functions and variables?
If you define a function (or variable, or const) as static, it is accessible via the class name, so you could define
class MyClass {
public static const className:String="MyClass.className (const)";
public static function getClassName():String {
return "MyClass.getClassName (function)";
}
}
trace(MyClass.className); //prints "MyClass.className (const)"
trace(MyClass.getClassName()); //prints MyClass.getClassName (function)
Related
I am having a little play with Flex and I'm curious as to a few things.
Firstly for my instance variables I can define something like
private var _count:int = 0;
It then seems that If I have a getter and setter for count e.g
public function get count():int
{
return _count;
}
public function set count(value:int):void
{
_count = count;
}
I can from within another function call something like
count++;
which in turn sets _count to increase by one.
I.E I can seemingly access count through count or _count because I have a getter and setter..
That is correct understanding?
For something like the above is good OOP practice to have the getter and setter or simply call _count++;
Thanks
I will point out that your set count method changes the variable _points. If that is a typo, then:
Yes; that is a correct understanding. It sounds like your tests already proved that.
The private var _count will not be accessible by other classes with a reference to an instance of your class; but the public 'count' will be.
Getter and Setters are useful for performing other functionality within the class. In the context of a Flex UI Component, you may dispatch an event, or invalidate the component through one of the Flex component invalidation methods.
Separating out the get and set methods also allow you to create properties that are read only, or properties that are write only, just by leaving out the respective get or set method.
IF that is not a typo; then I have no idea why count++ would change the _count variable at all; and something else is going on with the count that you haven't shown us.
I am new to Flex (got assigned to maintain an old project at work) and am having some trouble getting data binding to work correctly. I have a popup form class, AddOffer.mxml which uses a model AddOfferModel.as. On my popup form, I have the following component:
<mx:FormItem label="{getResource('addOffer.form.OFFER_DATE')}:"
labelWidth="90">
<views:OfferWindowDatesFragment
id="offerWindowField"
start="{model.offerStartDate}"
stop="{model.offerStopDate}" />
</mx:FormItem>
My AddForm.mxml file also has some embedded actionscript where I define my 'model' variable:
[Bindable]
public var model:AddOfferModel;
The model variables I am trying to bind to are standard getters/setters and look like this inside AddOfferModel.as:
[Bindable]
public function set offerStartDate(val:EditableInstant):void
{
_offerStartDate = val;
}
public function get offerStartDate():EditableInstant
{
return _offerStartDate;
}
private var _offerStartDate:EditableInstant;
[Bindable]
public function set offerStopDate(val:EditableInstant):void
{
_offerStopDate = val;
}
public function get offerStopDate():EditableInstant
{
return _offerStopDate;
}
private var _offerStopDate:EditableInstant;
Inside the OfferWindowDatesFragment component class, the start and stop variables look like this:
[Bindable]
public function set start(val:EditableInstant):void
{
_start = val;
}
public function get start():EditableInstant
{
return _start;
}
private var _start:EditableInstant;
[Bindable]
public function set stop(val:EditableInstant):void
{
_stop = val;
}
public function get stop():EditableInstant
{
return _stop;
}
private var _stop:EditableInstant;
Basically, I just want to bind the start and stop variables in my OfferWindowDatesFragment class to the offerStartDate and offerStopDate variables in the AddOfferModel.as file. Whenever I access the start/stop variables in functions inside the OfferWindowDatesFragment class, they are null.
I have an event listener function that gets triggered in OfferWindowDatesFragment anytime a user selects a new date, it looks like this:
private function changeOfferDate():void
{
start.currentValue = offerDateEditor.start;
stop.currentValue = offerDateEditor.stop;
}
Every time I reach this function, it throws up an error because 'start' and 'stop' are both null ... but should have been initialized and bound already. If I look at the variables in the debugger, I can confirm that values on the right side of the assignment expression are valid, and not what is causing the error.
I am not real familiar with how initialization works in Flex, and I assumed as long as I instantiated the component as seen in the first code snippet at the top of my post, it would initialize all the class variables, and setup the bindings. Am I missing something? Perhaps I am not properly initializing the model or class data for AddForm.mxml or AddFormModel.as, thereby binding null references to the start/stop fields in my OfferWindowDatesFragment class?
Any help would be greatly appreciated. Thanks!
EDIT:
I looked into this further and tried using Mate to inject the 'model' variable inside AddOffer.mxml with a valid AddOfferModel object:
<Injectors target="{AddOffer}" debug="{debug}">
<ObjectBuilder generator="{AddOfferModel}" constructorArguments="{scope.dispatcher}" cache="local"/>
<PropertyInjector targetKey="model" source="{lastReturn}" />
</Injectors>
I load the AddOffer.mxml dialog as the result of a button click event on another form. The function that pops it up looks like this:
public function addOffer():void
{
var addOfferDialog:AddOffer = new AddOffer();
addOfferDialog.addEventListener("addOffer", addOfferFromDialog);
modalUtil.popup(addOfferDialog);
}
It doesn't seem to be assigning anything to the 'model' variable in AddOffer.mxml. Does loading a view/dialog this way not trigger an injection from Mate by chance? (I realize this last part might belong in the Mate forums, but I'm hoping somebody here might have some insight on all of this).
In AddOffer.mxml, you have this code:
[Bindable]
public var model:AddOfferModel;
Is there something outside AddOffer.mxml that is setting this to a valid AddOfferModel? There should be. The nature of how the Flex component life cycle means that you can expect that things may be null at times as a View builds. So you should build your components to be able to "right themselves" after receiving bad data, if the data eventually comes good.
Data binding is one way to do this, but it may not paper over everything depending on what else is going on.
Have you verified that the model value you're getting is not null at the point where the user selects the date and that its offerStartDate and offerEndDate properties have been populated with valid EditableInstants? If both of those are correct, I'd start looking for pieces of the Views that expect to have stuff at a given instant and then don't recover if it is provided later.
I have a component where I expose the property 'questions' with the following code:
private var _questions:ArrayCollection;
private var questionsChanged:Boolean;
[Bindable("questionsChanged")]
public function get questions():ArrayCollection {
return _questions;
}
public function set questions(value:ArrayCollection):void {
if (_questions != value) {
_questions = value;
questionsChanged = true;
invalidateProperties();
dispatchEvent(new Event("questionsChanged"));
}
}
In this component, I use commitProperties() to implement my logic.
I use Cairngorm and the 'questions' is in the model and hence it's defined as a source for data binding.
When the 'questions' ArrayCollection's size changes elsewhere in the application, it is not invoking the setter method in the component that is destination for the data binding.
Could someone help me understand why this is the case?
You'll have to show the code where you are changing the array collection. But, this will fire the setter:
questions = somethingArrayCollection();
This will not:
questions.addItem(newQestion)
The questions variable is, basically, a pointer. Changing the thing that the variable points to does not need the set event.
I suggest you look at the CollectionChangeEvent, which the ArrayCollection fires when items are added to and from that. Listen to the event and perform your 'change' actions in the event handler. ( or tie into the lifecycle and invalidate some flag and perform your changes in commitProperties() )
Since I found the webpages explaning the bindable propety quite confusing,so I would like to post my question here,which is quite simple,if I declare a variable to be bindable,does that mean whenever I changed the value of this variable in another class,all appearence of this variable will be synchronized to be the same value at the same time?
Say,if boolean variable "select" is declared to be bindable in Class A and default to be false,and we have an if statement in class A like if(select).
Then in another class,we changed the value of "select" to be true,will that if(select) statement pass the test ?
Also,how about the following setter method that is defined to be bindable:
[Bindable]
public function set isShowingAvg(b:Boolean):void
{
_isShowingAvg = b;
hasChanged();
}
Does this code imply that changing the value of _isShowingAvg is also going to be broadcasted?
Thanks in advance.
Thanks for your idea.
Declaring a property as Bindable means that when you change the value, an event will get broadcasted. This event enables data binding, but it's not necessarily automatic.
If the consuming class is MXML and you use brackets, like this:
<mx:Button enabled="{selected}" />
Then the MXML compiler will generate the appropriate binding code and anytime selected changes, enabled will also get changed.
If you're using it outside MXML then you'll either subscribe to the event to detect changes or use BindingUtils.
In your example I think you need to mark the getter [Bindable] and not the setter.
example:
public static const SHOWING_AVG_CHANGED:String = "showingAvgChangedEvent";
[Bindable(event="showingAvgChangedEvent")]
public function get isShowingAvg():Boolean
{
return _isShowingAvg;
}
public function set isShowingAvg(isShowing:Boolean):void
{
_isShowingAvg = isShowing;
dispatchEvent(new Event(SHOWING_AVG_CHANGED));
}
I have a dynamic class that I have created
public dynamic class SiteZoneFileUploadVO
{
public var destination:String = "sitezone";
public var siteZoneId:uint;
public var fileType:String;
public var fileContents:String;
public function SiteZoneFileUploadVO()
{
}
}
when I try to iterate over this object's property names it only iterates the dynamically added properties.
parameters.dynVar= "value";
for(var name:String in parameters)
{
trace(name);
}
Even though the object has all the properties equal to a value (ive checked this in the debugger) the only property name that will be traced is dynVar.
How can I iterate over all the property names and not just the dynamically added ones?
You can use describeType() to get an XML with all methods and variables of your class and then filter out the properties you want to iterate over (e.g. all variables) and store them in an XMLList.
As the next step you would then iterate over the XMLList and use square bracket notation on your object to access the filtered properties by their names. However, you can only access public properties this way because describeType() won't look at private properties.
If you're running flex:
Looked at a few posts, ObjectUtil.toString was the most promising, then looked at the flex source code for it, it uses another method ObjectUtil.getClassInfo which is exactly what you need. If you just want property names:
ObjectUtil.getClassInfo(myClass).properties
returns an Array of QName objects, each has a localName property which will give you a string for each property name
Just use trace(ObjectUtil.toString(parameters)); That should give you your entire object.