Flex 4 -- Call function when dataprovider changes - apache-flex

How can I set a function to be called when the length of a DataProvider changes?

Here is a good solution using the event "CollectionEvent.COLLECTION_CHANGE" :
http://blog.flexexamples.com/2008/12/16/detecting-when-the-data-provider-of-a-datagrid-control-changes-in-flex/

If you're working with an ICollectionView (aka ArrayCollection), you could add an event listener for the "collectionChange" event.
Docs: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/collections/ListCollectionView.html#event:collectionChange
If you are inside an MXML document the dataProvider property of the UI component should be a source of data binding. So you could just {myComponent.dataProvider.length} bind the value to something else if that is the use case.

The only way I could get thru it was making a binding in the actionscript code. Something like this:
protected function creationCompleteHandler(event:FlexEvent):void {
BindingUtils.bindSetter(myHandleFunction, myList, "dataProvider");
}
myHandleFunction receives by parameter an object with the type of the binded property.

Related

Help with containers

I am using view stack...so when view change like when we move from one page to another hide event is dispatched.So i am saving the information of last page in hide event before i go to next page.but thing is that if i change nothing still change on view hide event is invoked nd call go to backend...i just want do call only if sumthing change in the view..like sum text value...So i have two options
use event listener on each component if sumthing change its make the flag true...nd hide event check, if flag is true send call to backend.
event listener at container level ..if sumthing change in child componenet through bubbling container knows if sum event is dispatched.nd makes the flag true.
I have doubt with container...
Can i use container, and how?
Reason why I can't use container?
What are the pros and cons either way?
I would recommend using a dataProvider with the ability to compare them. For instance, if you are changing things with textinputs, you could basically do something like this:
[Bindable]
private var myDataProvider:Object = new Object();
private function creationCompleteHandler():void {
myDataProvider.updated = false;
myDataProvider.defaultValue = 'default';
myDataProvider.defaultValueTwo = 'default';
}
etc.
Then, in your mxml, you can have something like this:
<mx:TextInput id="myText" text="{myDataProvider.defaultValue}" change="myDataProvider.defaultValue=myText.text; myDataProvider.updated=true;" />
Lastly, in your hide event, you can do the following:
private function hideEventHandler( event:Event ):void {
if( myDataProvider.updated ){
// Call your RemoteServices (or w/e) to update the information
}
}
This way, when anything changes, you can update your dataProvider and have access to the new information each time.
Hope this helps!
I've used an approach similar to your first option in a couple of my past projects. In the change event for each of my form's controls I make a call to a small function that just sets a changesMade flag to true in my model. When the user tries to navigate away from my form, I check the changesMade flag to see if I need to save the info.
Data models are your friend!
If you get in the habit of creating strongly typed data models out of your loaded data, questions like this become very basic.
I always have a key binding set to generate a code snipit similar to this...
private var _foo:String;
public function get foo():String
{
return _foo;
}
public function set foo(value:String):void
{
if(_foo == value)
return;
var oldVal:String = _foo;
_foo = value;
this.invalidateProperty("foo", oldVal, value);
}
If your data used getters/setters like this, it would be very easy to validate a change on the model level, cutting the view out of the process entirely.

Listen to all event types of an EventDispatcher

In Flex, is it possible to listen to all event types of an object that's an IEventDispatcher? addEventListener's first parameter is the type, which is a string. In many cases the documentation is not clear what event type it fires. I'd like to attach a generic listener to inspect the events.
I think you have to derive from this class and override the dispatchEvent method like this:
override public function dispatchEvent(event:Event):Boolean
{
trace(event.type);
return super.dispatchEvent(event);
}
The short answer is no, there isn't any built-in way of generically listening for all event types. You would either have to develop a system for managing this or do something similar to what splash suggested. Personally, I would create a custom event, override dispatchEvent, and dispatch your own custom event while passing the 'type' of the original event.
override public function dispatchEvent(event:Event):Boolean
{
//Dispatch your custom event passing along with it the type of the original event.
super.dispatchEvent(new CustomEvent(CustomEvent.ALL, event.type);
return super.dispatchEvent(event);
}
Then you could simply setup one listener for your custom event and easily track when and what events are firing.
Hope that helps.

how to hide a row without deleting item from dataprovidor in DataGrid...AS3,Flex?

How we can hide a row at specific index of DataGrid in AS3 ?
If dataProvider of your DataGrid is ArrayCollection you can specify filterFunction property for it, something like that
dataProvider.filterFunction =
function (item:Object):Boolean{
if (dataProvider.getItemIndex(item)==indexOfRowYouWantToHide){
return false;
}
return true;
};
The item will still be in ArrayCollection but will be made invisible by the filter. Not the most efficient solution but it works. You need to call
dataProvider.refresh();
to apply the filter.
UPDATE: To access raw, unfiltered data of ArrayCollection you should use list property, so if you hid item at index 0 and still want to be able to access it you do that like this:
dataProvider.list.getItemAt(0);
No (easy) way. You can try to subclass DataGrid to add this functionality, but this will be really heavy task.

Adobe Flex3: Keyboard shortcuts when a view is visible?

I have a quite large Flex application with a large set of views and I ceratain views I'd like to add shortcuts.
And i'm looking for something like:
<mx:Vbox>
<foo:Shortcut keys="ctrl+s" action="{bar();}"/>
....
</mx:VBox>
Is there any framwork or component already done that does something like this? I guess it should be too difficult to build? When building this I only want the shortcuts to be active when the view is visible. How do I detect this? What base class is best to inherit from when working with non visual components?
I don't know of any framework component that does that already, but the examples above should get you started if you try to build your own.
There's no need to inherit from any component for a non-visual component like the one you've described here (your "foo" class needs no parents.) There's nothing in the Flex framework you need to inherit from for this.
However you architect it, your foo class is going to have to take in and parse keyboard codes to listen for and accept one or more methods to call. All you have to do is figure out when to add and remove the event listeners that will call the passed-in methods.
To handle turning your keyboard events on and off based on visibility, just have your foo component bind to the "visible" property of it's parent and add/remove event listeners accordingly.
You might also consider having the listeners added when the component that foo is nested in is on the display list rather than just visible. To do this, simply added and remove your event listeners in one of the component lifecycle methods - probably commitProperties is the most appropriate.
I don't think this solution answer your question directly but anyway, to help solve your problem here is an example.
For instance, I've extended the TextArea component like so. This is the best I can do so far, it can definitely be improved upon. Like, I don't know how to make the cursor go to the end after the next shortcut is pressed.
public class TextArea extends mx.controls.TextArea
{
// the keysmap is an example dictionary holding keycodes
private var keysmap:*={
112 = "some text for F1"
,113 = "the text for F2!"
//etc, etc
}
public var handleKeyDown:Boolean =false;
public function TextArea(){
if(handleKeyDown ==true){
this.addEventListener(KeyboardEvent.KEY_DOWN,this.keydownHandler);
}
}
public function keydownHandler(e:KeyboardEvent):void{
if(e.keyCode >= 112 && e.keyCode <= 123){
e.currentTarget["text"] += String(keysmap[e.keyCode]) +" ";
}//focusManager.setFocus(this);
}
}
I can't give you a solution using MXML, however my first thought would involve a singleton static class with a Dictionary that contains a list of objects as its keys and dynamically created dictionaries as the value pairing that contain keys denoting the desired key press with a function reference as the value.
So, say you had a Sprite and you wanted to capture ctrl+s for save when focus is on that object, I would get the instance of that Singleton, and call a function such as registerKeyBinding passing in the Sprite, the keyCode you want, and your pre-defined callback:
private var registeredObjects:Dictionary = new Dictionary(true);
public function registerKeyBinding(targetObject:Object, keyCode:int, callback:Function) {
if (registeredObjects[targetObject]) {
Dictionary(registeredObjects[targetObject])[keyCode] = callback;
}
else {
registeredObjects[targetObject] = new Dictionary();
Dictionary(registeredObjects[targetObject])[keyCode] = callback;
targetObject.addEventListener(KeyboardEvent.KEY_DOWN, keyDownListener);
}
}
private function keyDownListener(e:KeyboardEvent):void {
if (e.ctrlKey == true) {
//calls the function if that key exists.
Dictionary(registeredObjects[e.target])[e.keyCode];
}
}
Can't say I've tested this, but it was just the first thing that popped into my head. You could then setup functions to deregister and delete keys from the dictionaries, check states of the objects in addition to the keyCodes, remove old listeners, and delete entire dictionaries when there is no longer a need for them. Hopefully this is at least a tiny bit helpful.

Flex: Is there a way to bind ComboBox's selectedItem to a variable?

OK I have a ComboBox, the dataProvider is an array of objects with label properties that give the ComboBox the list of options.
Is there a way I can have a variable like mySelectedItem, and bind the ComboBox's selectedItem to it so that if it changes, the ComboBox's selectedItem will change to whatever it is?
I hope this makes sense.
Thanks!
Yes, ComboBox's selectedItem property is bindable.
It would go something like this:
<mx:ComboBox selectedItem="{mySelectedItem}">
</mx:ComboBox>
In your AS:
[Bindable]
var mySelectedItem:Object;
Changes to mySelectedItem should show up in ComboBox. You may get errors if the item referenced by mySelectedItem does not exist in the ComboBox's dataProvider.
On the surface, it's as simple as:
<mx:ComboBox id="myComboBox"
dataProvider="{myDataProvider}"
selectedItem="{defaultItem}"/>
When you set defaultItem (make sure it is [Bindable]) to one of the items in the data provider, it will update the control.
But there are problems with this approach. Unless currentDefaultItem always changes AFTER myDataProvider, the binding to dataProvider may undo the selection, reverting to the default (first item in the list).
One way around this is to force selectedItem to be rebound after dataProvider, by including dataProvider in the call providing the selectedItem.
<mx:ComboBox id="myComboBox"
dataProvider="{myDataProvider}"
selectedItem="{getSelectedItem(myComboBox.dataProvider, defaultItem)}"/>
What this does is ensure selectedItem will be rebound when either currentDefaultItem changes, or after the dataProvider changes. I'd be interested in other solutions myself.
Use an event listener for the Change event and do your processing there.
// update a label item's text with that of the Combobox's selectedItem
private function changeEvt(event:Event):void {
label.text =event.currentTarget.selectedItem.label + " " +
}
or, you could do something like this if you don't mind extending ComboBox;
This is pseudocode (sorry, identification of matches depends on the object type) - but you get the idea...
public class IndexRetainingComboBox extends ComboBox
{
public function IndexRetainingComboBox()
{
super();
}
override public function set dataProvider(value:Object):void
{
var originalSelection:Object = this.selectedItem;
super.dataProvider = value;
var newIdx:uint = [find originalSelection idx in combobox or return 0 ]
this.selectedIndex = newIdx;
}
}
I know this is how its described in the documentation.
As in a change to the selectedItem will fire the change listener. However for me, this does not happen. Anyone else encounter the same behavior?
This looks like a great approach: make the value attribute writeable:
http://flex.sys-con.com/node/312098

Resources