I have couple of dropdownlist controls, that shares the same dataprovider(same reference).
I had overridden the set dataprovider method for a sort function.(code below). The issue is that, when I set this shared dataprovider to a new dropdownlist, all the existing dropdown contorls sharing the dataprvider gets unselected(loses its previously selected values).
override public function set dataProvider(value:IList):void{
if(value is ArrayCollection){
var sort:Sort=new Sort();
var sortField:SortField = new SortField();
sortField.numeric=false;
sort.fields=[sortField];
ArrayCollection(value).sort=sort;
ArrayCollection(value).refresh();
}
super.dataProvider=value;
}
There are a ton of isues sharing the dataProvider between components. We've run into this with a lot of clients using our AutoCompleteComboBox.
You can easily use the same source, but a different--separate--collection for each of your dataProviders.
var dataProvider1 :ArrayCollection = new ArrayCollection(someArray);
var dataProvider2 :ArrayCollection = new ArrayCollection(someArray);
var dataProvider3 :ArrayCollection = new ArrayCollection(someArray);
Each collection is just a wrapper around the base source. Sorting one will not affect any of the others, leaving your other ComboBoxes or DropDownLists untouched.
I did no research on this, but there are two issues/ideas coming up:
if you literally use the same reference to the same arraycollection, you do not need to sort this array more than once (and you actually do this by assigning the same arraycollection more than once)
if it about only single-selection dropdowns, then there is a simple solution:
var oldSelected : TypeOfItem = selectedItem as TypeOfItem;
// do the sort (like in your code)
super.dataProvider=value;
selectedIndex = getItemIndex(oldSelected);
Related
I have a problem with creating and applying displacement maps filters on a container Sprite. The setup is like this
public class ExplosionManager
{
[Embed...] // this is an image I tested, basically a spherical displacement
private var explodeDisplaceAsset:Class;
private var explodeDisplace:Bitmap;
private var displacementFilters:Array = new Array();
private var displacementMaps:Vector.<BitmapData> = new Vector.<BitmapData>();
private var unusedFilters:Vector.<DisplacementMapFilter> = new Vector.<DisplacementMapFilter>();
private var unusedMaps:Vector.<BirmapData> = new Vector.<BitmapData>();
public function ExplosionManager(container:Sprite)
{
explodeDisplace = new explodeDisplaceAsset();
container.filters = displacementFilters;
}
public function ExplodeAt(pos:Point, force:int) : void
{
var newDisplaceMap:BitmapData;
var newDisplaceFilter:DisplacementMapFilter;
if(unusedFilters.length == 0)
{
newDisplaceMap = new BitmapData(64,64,true, 0x808080);
newDisplaceMap.draw(explodeDisplace);
newDisplaceFilter = new DispalcementFilter(newDisplaceMap, pos, BitmapDataChannel.RED, BitmapDataChannel.GREEN, force, force);
}
else
{
newDisplaceMap = unusedMaps.pop();
newDisplaceFilter = unusedFilters.pop();
newDisplaceFilter.componentX = force;
newDisplaceFilter.componentY = force;
newDisplaceFilter.mapPoint = pos;
newDisplaceFilter.mapBitmap = newDisplaceMap;
}
displacementMaps.push(newDisplaceMap);
displacementFilters.push(newDisplaceFilter);
}
}
I'm trying to make an adaptive object pool that reuses and creates filters as needed, my initial thought was that if I have about 2-3 explosions tops it'd be more efficient to have 2-3 filters that only get applied to a part of the scene rather than have one filter with a single big bitmap that gets updated every frame.
The problem is that I can't see any displacement no matter what combination of parameters I try, is there something I'm doing wrong ?
PS: I'm sorry if the code has some typos, I'm not at my development machine right now, so I had to rewrite it, but from the algorithms' point of view that's exactly what I wrote.
It seems like you're assigning the array displacementFilters to the filters property within the constructor (at setup of the ExplosionManager). It then looks like you're adding and modifying filters within that array at a later date.
Unfortunately, changes made to the filters stored within the array you used as a source last time will not be applied to the object. This is because when you assign an array to filters, a copy of that array is actually created and used. From the documentation:
To modify an existing filter object, you must use the technique of
modifying a copy of the filters array:
Assign the value of the filters array to a temporary array, such as
one named myFilters.
Modify the property by using the temporary array,
myFilters. For example, to set the quality property of the first
filter in the array, you could use the following code:
myFilters[0].quality = 1;
Assign the value of the temporary array to
the filters array.
You will need to assign the updated displacementFilters array to filters whenever there are changes made.
I am new to ActionScript and Flex.I need to learn the application developed using Flex and ActionScript.I saw an ArrayCollection declaration :
[Bindable]
public var someThing:ArrayCollection = new ArrayCollection([[]]);
What does that declaration mean.Is it multi dimensional?What is it?
This would be an ArrayCollection which is a wrapper for an Array basically to give you sort and filter function capabilities (and other methods). The constructor optionally takes an Array as an argument, [] is a new array with no elements. [[]] is an array with one element in it that is an array with no elements in it. So this is saying make a new ArrayCollection with it's source as an array which in turn contains one element that is an empty array. Not sure why they would be doing this, but that's what it does.
To sum up, you can declare and instantiate an array in AS3 like:
var myArray:Array = [];
or
var myArray:Array = new Array();
To add since this is I believe ECMAScript specific as well you can instantiate an object similarly using {}. Such as:
var myObj:Object = {};
or
var myObj:Object = new Object();
Either of these sites is good reference material for AS3:
http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7ee5.html#WS5b3ccc516d4fbf351e63e3d118a9b90204-7ee1
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html
When I first got started with Flex (having a background in HTML/JS, C, C++, and Java) I found these videos to be really useful (if not always 100% correct/up to date, they explain the overarching concepts):
http://www.adobe.com/devnet/flex/videotraining.html
I use a Label component to display the length of an ArrayCollection. How do I get it to update when I add new items to the collection?
Here's the text field for the Label:
text="{model.meetingInfo.documentList.length}"
Here's the handler for adding a new item to the collection:
var attachmentProgressVO:AttachmentProgressVO = new AttachmentProgressVO();
attachmentProgressVO.fileReference = file as File;
newAttachmentList.addItem(attachmentProgressVO);
checkIfUpdate(file as File, attachmentProgressVO);
meetingInfo.docsAndAttachmentsList.addItem(attachmentProgressVO);
I tried adding these 2 lines but that didn't work:
meetingInfo.docsAndAttachmentsList.itemUpdated( attachmentProgressVO );
meetingInfo.docsAndAttachmentsList.refresh();
I also tried changing this:
public var docsAndAttachmentsList:ArrayCollection = new ArrayCollection();
to this:
private var _docsAndAttachmentsList:ArrayCollection = new ArrayCollection();
..with a getter and setter but that didn't work.
I'm not using the right approach, am I?
Generically, Binding only looks at a specific object; you can't drill down 4 objects deep to a specific property and expect binding to update values.
Changing the documentList does not change meetingInfo or Model, so binding will never be triggered. itemUpdated() and refresh() should update the list based class which displays the data; but will not affect your label displaying the count.
You need to listen on the collection for a collectionChange event and manually update the label's text in the collectionChange handler.
A question about ItemRenderers: let's say I have an ArrayCollection that is my application data sitting inside a global object. I them populate a sparks list with this data, setting the ArrayCollection as the dataProvider.
So each ItemRenderer gets a copy of an item sitting in the array. You can override the "set data" method to set the data something more domain-specific. The problem is that the data is a copy of the original item.
Now let's say we want to add some data to the item while inside the ItemRender. For example, it could call a method on the item telling it to load some details about itself, or maybe we allow the user to modify something on the item.
Obviously, we can't do any of this if we are operating on a copy because it will be thrown away as soon as the ItemRenderer is destroyed and the original object doesn't know anything about what happened.
So what's the best practice? Should I just use the itemIndex of the renderer to pull out the original item from my global array like this:
{globalArrayCollection}.getItemAt(this.itemIndex)
But it seems kind of clunky to me. Is there a best practice for dealing with this?
Not sure I'm following but it sounds like you're looking for a way to get at your item renderer to set/change a value.
You could go about accessing a method on the renderer directly.
In your renderer:
public function setSomeValue(aValue:String):void{
someString = aValue;
}
You would also set the data on your ArrayCollection as well.
To access this method you would use this:
var dataGroup:DataGroup = list.dataGroup;
var itemRenderer:YourItemRenderer = dataGroup.getElementAt(list.selectedIndex) as YourItemRenderer;
itemRenderer.setSomeValue("string");
Hmm, why do you think that original ArrayCollection won't change if you change values in itemRenderer? For me this works and initial ArrayCollection changes.
[Bindable]
protected var model:Model;
override public function set data(value:Object):void
{
super.data = value;
this.model = value as Model;
}
protected function changeValue():void
{
model.value = "newValue";
}
Or am I misunderstood something?
Should be easy. I have an object. I want to modify it, but before i do I want to save a copy of it that I can go back to. I tried setting copy = original but when i modify the attributes of the original the copy also shows the changes. I am assuming this is because in actionscript any time you assign, it really just stores a reference to the original object. So whats the best way for me to store a copy of the original object for later use?
var newObj:Object = Object(ObjectUtil.copy(oldObj));
"Copies the specified Object and returns a reference to the copy. The copy is made using a native serialization technique. This means that custom serialization will be respected during the copy.
This method is designed for copying data objects, such as elements of a collection. It is not intended for copying a UIComponent object, such as a TextInput control. If you want to create copies of specific UIComponent objects, you can create a subclass of the component and implement a clone() method, or other method to perform the copy."
http://livedocs.adobe.com/flex/3/langref/mx/utils/ObjectUtil.html#copy()
What you are looking for is a deep copy of the object rather then passing by reference. I found the answer here which uses the new ByteArray class in AS3:
http://www.kirupa.com/forum/showthread.php?p=1897368
function clone(source:Object):* {
var copier:ByteArray = new ByteArray();
copier.writeObject(source);
copier.position = 0;
return(copier.readObject());
}
Which you then use like this:
newObjectCopy = clone(originalObject);
Cheers!
// duplicate any given Object (not MCs)
Object.prototype.copy = function()
{
ASSetPropFlags(Object.prototype,["copy"],1);
var _t = new this.__proto__.constructor(this) //
for(var i in this){
_t[i] = this[i].copy()
}
return _t
};
Usage
x = ["1","2","3",[4,5],[{a:1,b:2}]]
y = x.copy()
y[0] = 0
y[3][0]="d"
trace(x)
trace(y)