Within an event handler I have an Alert.show(...) that prompts a user for confirmation. How can I capture the selection of the alert prompt and use it within the event handler. For example:
private function mainEvtHandler(event:DynamicEvent):void {
var alert:Alert = Alert.show("Are you sure?", "Confirmation", Alert.YES|Alert.NO, this, alertHandler);
// How can I retrieve the selection and use it within this event handler?
// i.e. if (alert == Alert.Yes) { ...
var index:int = arrayColl.getItemIndex(event.data)
...
...
You can declare the alertHandler as nested function ...
private function mainEvtHandler(event:DynamicEvent):void {
var alertResult: int = -1;
function alertHandler(evt:CloseEvent):void {
alertResult = evt.detail;
}
var alert:Alert = Alert.show("Are you sure?", "Confirmation", Alert.YES|Alert.NO, this, alertHandler);
if (alertResult == Alert.Yes) {
var index:int = arrayColl.getItemIndex(event.data);
...
}
... or you can use an anonymous function
private function mainEvtHandler(event:DynamicEvent):void {
Alert.show("Are you sure?", "Confirmation", Alert.YES|Alert.NO, this,
function (nestedCloseEvent:CloseEvent):void {
if (nestedCloseEvent.detail == Alert.Yes) {
var index:int = arrayColl.getItemIndex(event.data);
...
}
}
);
}
Related
I have a TextBox with AutoCompleteExtenderwhen the person starts typing in the TextBox List with City name Appear .This works fine but now I want to validate that if they just type in a textbox and don't select one from the list that it validates that City Is Not Exist In database.
I want to validate it Using Ajax And Without PostBack Before Final Submit of form.
Add new js file with content below and add add reference on it to ToolkitScriptManager's Scrips collection:
Type.registerNamespace('Sjax');
Sjax.XMLHttpSyncExecutor = function () {
Sjax.XMLHttpSyncExecutor.initializeBase(this);
this._started = false;
this._responseAvailable = false;
this._onReceiveHandler = null;
this._xmlHttpRequest = null;
this.get_aborted = function () {
//Parameter validation code removed here...
return false;
}
this.get_responseAvailable = function () {
//Parameter validation code removed here...
return this._responseAvailable;
}
this.get_responseData = function () {
//Parameter validation code removed here...
return this._xmlHttpRequest.responseText;
}
this.get_started = function () {
//Parameter validation code removed here...
return this._started;
}
this.get_statusCode = function () {
//Parameter validation code removed here...
return this._xmlHttpRequest.status;
}
this.get_statusText = function () {
//Parameter validation code removed here...
return this._xmlHttpRequest.statusText;
}
this.get_xml = function () {
//Code removed
}
this.executeRequest = function () {
//Parameter validation code removed here...
var webRequest = this.get_webRequest();
if (webRequest === null) {
throw Error.invalidOperation(Sys.Res.nullWebRequest);
}
var body = webRequest.get_body();
var headers = webRequest.get_headers();
var verb = webRequest.get_httpVerb();
var xmlHttpRequest = new XMLHttpRequest();
this._onReceiveHandler = Function.createCallback(this._onReadyStateChange, { sender: this });
this._started = true;
xmlHttpRequest.onreadystatechange = this._onReceiveHandler;
xmlHttpRequest.open(verb, webRequest.getResolvedUrl(), false); // False to call Synchronously
if (headers) {
for (var header in headers) {
var val = headers[header];
if (typeof (val) !== "function") {
xmlHttpRequest.setRequestHeader(header, val);
}
}
}
if (verb.toLowerCase() === "post") {
if ((headers === null) || !headers['Content-Type']) {
xmlHttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
if (!body) {
body = '';
}
}
this._started = true;
this._xmlHttpRequest = xmlHttpRequest;
xmlHttpRequest.send(body);
}
this.getAllResponseHeaders = function () {
//Parameter validation code removed here...
return this._xmlHttpRequest.getAllResponseHeaders();
}
this.getResponseHeader = function (header) {
//Parameter validation code removed here...
return this._xmlHttpRequest.getResponseHeader(header);
}
this._onReadyStateChange = function (e, args) {
var executor = args.sender;
if (executor._xmlHttpRequest && executor._xmlHttpRequest.readyState === 4) {
//Validation code removed here...
executor._responseAvailable = true;
executor._xmlHttpRequest.onreadystatechange = Function.emptyMethod;
executor._onReceiveHandler = null;
executor._started = false;
var webRequest = executor.get_webRequest();
webRequest.completed(Sys.EventArgs.Empty);
//Once the completed callback handler has processed the data it needs from the XML HTTP request we can clean up
executor._xmlHttpRequest = null;
}
}
}
Sjax.XMLHttpSyncExecutor.registerClass('Sjax.XMLHttpSyncExecutor', Sys.Net.WebRequestExecutor);
On a page:
<ajaxToolkit:ToolkitScriptManager runat="server" ID="ScriptManager1">
<Scripts>
<asp:ScriptReference Path="~/XMLHttpSyncExecutor.js" />
</Scripts>
</ajaxToolkit:ToolkitScriptManager>
Then, add CustomValidator for target TextBox and use function below for client validation:
<asp:TextBox runat="server" ID="myTextBox" Width="300" autocomplete="off" />
<asp:CustomValidator runat="server" ID="myTbCustomValidator" ControlToValidate="myTextBox"
Text="*" Display="Dynamic" ValidateEmptyText="false" ClientValidationFunction="validateTextBox"
OnServerValidate="ValidateTextBox" />
function validateTextBox(sender, args) {
if (args.Value.length > 0) {
var extender = $find("AutoCompleteEx"); // AutoComplete extender's BehaviorID
if (extender._completionListElement) {
var children = extender._completionListElement.childNodes;
var length = extender._completionListElement.childNodes.length;
for (var i = 0; i < length; i++) {
if (children[i].innerHTML == args.Value) {
args.IsValid = true;
return;
}
}
}
var request = new Sys.Net.WebRequest();
request.set_url('<%= ResolveClientUrl("~/AutoComplete/AutoComplete.asmx/Validate") %>');
var body = Sys.Serialization.JavaScriptSerializer.serialize({ value: args.Value });
request.set_body(body);
request.set_httpVerb("POST");
request.get_headers()["Content-Type"] = "application/json; encoding=utf-8";
request.add_completed(function (eventArgs) {
var result = Sys.Serialization.JavaScriptSerializer.deserialize(eventArgs.get_responseData());
args.IsValid = result.d;
});
var executor = new Sjax.XMLHttpSyncExecutor();
request.set_executor(executor);
request.invoke();
}
}
The main idea of code above is to check suggested items at first for entered text and if there aren't any concidence then to do synchronous AJAX call to Validate method of web service or page method. That method should have such signature: public bool Validate(string value)
P.S. Code for XMLHttpSyncExecutor taken here: Using Synchronous ASP.Net AJAX Web Service Calls and Scriptaculous to Test your JavaScript
I have taken this code from one of my friend,but in real it is totally mess there are plenty of error i am getting by running this code,i have some question
How i can use this code in mxml application,as we know we can not use public class in mx script so what are the way to do that
as you can see .mx_internal,i am getting error on that saying'define object before dot' as i remove mx_internal and tried using import mx.binding.mx_internal and use namespace mx_internal application not desplaying anything
now you will tell me ther are easy methods are ther to solve problem but my whole project is on this method only
thanks for help in advance
i am trying to solve this problem from last 15 days ,with no success,pls help me below is code
package components
{
import flash.events.*;
import flash.utils.*;
import mx.binding.*;
import mx.containers.*;
import mx.controls.*;
import mx.core.*;
import mx.events.*;
import mx.styles.*;
public class DialogTitle extends HBox implements IBindingClient
{
private var _110371416title:String = "Dialog Title";
public var _DialogTitle_Image1:Image;
public var _DialogTitle_Image2:Image;
public var _DialogTitle_Label1:Label;
var _bindingsBeginWithWord:Object;
private var _1859425293showCloseButton:Boolean = false;
var _bindingsByDestination:Object;
var _watchers:Array;
var _bindings:Array;
private var _documentDescriptor_:UIComponentDescriptor;
private static var _watcherSetupUtil:IWatcherSetupUtil;
public function DialogTitle()
{
_documentDescriptor_ = new UIComponentDescriptor({type:HBox, propertiesFactory:function () : Object
{
return {height:27, childDescriptors:[new UIComponentDescriptor({type:Spacer, propertiesFactory:function () : Object
{
return {width:5};
}// end function
}), new UIComponentDescriptor({type:Image, id:"_DialogTitle_Image1"}), new UIComponentDescriptor({type:Spacer, propertiesFactory:function () : Object
{
return {width:5};
}// end function
}), new UIComponentDescriptor({type:Label, id:"_DialogTitle_Label1", stylesFactory:function () : void
{
this.fontSize = 14;
this.color = 16777215;
this.fontWeight = "bold";
return;
}// end function
}), new UIComponentDescriptor({type:Spacer, propertiesFactory:function () : Object
{
return {percentWidth:100};
}// end function
}), new UIComponentDescriptor({type:Image, id:"_DialogTitle_Image2", events:{click:"___DialogTitle_Image2_click"}, propertiesFactory:function () : Object
{
return {useHandCursor:true, buttonMode:true, mouseChildren:false, toolTip:"Close"};
}// end function
}), new UIComponentDescriptor({type:Spacer, propertiesFactory:function () : Object
{
return {width:13};
}// end function
})]};
}// end function
});
_bindings = [];
_watchers = [];
_bindingsByDestination = {};
_bindingsBeginWithWord = {};
mx_internal::_document = this;
if (!this.styleDeclaration)
{
this.styleDeclaration = new CSSStyleDeclaration();
}
this.styleDeclaration.defaultFactory = function () : void
{
this.backgroundColor = 9947478;
this.horizontalGap = 0;
this.verticalAlign = "middle";
this.verticalGap = 0;
return;
}// end function
;
this.height = 27;
this.percentWidth = 100;
return;
}// end function
private function _DialogTitle_bindingExprs() : void
{
var _loc_1:* = undefined;
_loc_1 = CustomEmbeddedAssets.logoImageSmall;
_loc_1 = title;
_loc_1 = EmbeddedAssets.dialogClose;
_loc_1 = showCloseButton;
return;
}// end function
public function get showCloseButton() : Boolean
{
return this._1859425293showCloseButton;
}// end function
override public function initialize() : void
{
var target:DialogTitle;
var watcherSetupUtilClass:Object;
.mx_internal::setDocumentDescriptor(_documentDescriptor_);
var bindings:* = _DialogTitle_bindingsSetup();
var watchers:Array;
target;
if (_watcherSetupUtil == null)
{
watcherSetupUtilClass = getDefinitionByName("_components_DialogTitleWatcherSetupUtil");
var _loc_2:* = watcherSetupUtilClass;
_loc_2.watcherSetupUtilClass["init"](null);
}
_watcherSetupUtil.setup(this, function (param1:String)
{
return target[param1];
}// end function
, bindings, watchers);
var i:uint;
while (i < bindings.length)
{
Binding(bindings[i]).execute();
i = (i + 1);
}
mx_internal::_bindings = mx_internal::_bindings.concat(bindings);
mx_internal::_watchers = mx_internal::_watchers.concat(watchers);
super.initialize();
return;
}// end function
public function get title() : String
{
return this._110371416title;
}// end function
private function _DialogTitle_bindingsSetup() : Array
{
var binding:Binding;
var result:Array;
binding = new Binding(this, function () : Object
{
return CustomEmbeddedAssets.logoImageSmall;
}// end function
, function (param1:Object) : void
{
_DialogTitle_Image1.source = param1;
return;
}// end function
, "_DialogTitle_Image1.source");
result[0] = binding;
binding = new Binding(this, function () : String
{
var _loc_1:* = title;
var _loc_2:* = _loc_1 == undefined ? (null) : (String(_loc_1));
return _loc_2;
}// end function
, function (param1:String) : void
{
_DialogTitle_Label1.text = param1;
return;
}// end function
, "_DialogTitle_Label1.text");
result[1] = binding;
binding = new Binding(this, function () : Object
{
return EmbeddedAssets.dialogClose;
}// end function
, function (param1:Object) : void
{
_DialogTitle_Image2.source = param1;
return;
}// end function
, "_DialogTitle_Image2.source");
result[2] = binding;
binding = new Binding(this, function () : Boolean
{
return showCloseButton;
}// end function
, function (param1:Boolean) : void
{
_DialogTitle_Image2.visible = param1;
return;
}// end function
, "_DialogTitle_Image2.visible");
result[3] = binding;
return result;
}// end function
public function set showCloseButton(param1:Boolean) : void
{
var _loc_2:* = this._1859425293showCloseButton;
if (_loc_2 !== param1)
{
this._1859425293showCloseButton = param1;
this.dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, "showCloseButton", _loc_2, param1));
}
return;
}// end function
public function ___DialogTitle_Image2_click(event:MouseEvent) : void
{
dispatchEvent(new Event("onCancel"));
parent.visible = false;
return;
}// end function
public function set title(param1:String) : void
{
var _loc_2:* = this._110371416title;
if (_loc_2 !== param1)
{
this._110371416title = param1;
this.dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, "title", _loc_2, param1));
}
return;
}// end function
public static function set watcherSetupUtil(param1:IWatcherSetupUtil) : void
{
DialogTitle._watcherSetupUtil = param1;
return;
}// end function
}
}
Just throw this code out. This code was generated automatically by mxmlc compiler from MXML class and can't be used in production. It is for computer, not for humans. Write the right code by yourself. I hope it will be clearer and maintainable. And yes, this code wasn't written by your friend :)
This file is decompiled from a .mxml file, which use tags to describe layout. However, some decompiler can't convert it completely, and you will see file like this.
As you see, the argument of UIComponentDescriptor is an object, which contains a lot of key-val pairs. It has some type of keys:
type:Class --> this is the type of this component, which is the node tag of .mxml file
id:String --> this is the ID of a node, which is also the variable name you can use in <fx:Script> tag
event:Object --> events that the component will trigger
stylesFactory:Function --> component's styles setting
propertiesFactory:Function --> contains some properties and child nodes
code like this:
<mx:Canvas id="mainCanvas" borderStyle="none" label="main">
<mx:Button click="onClick(event)" />
</mx:Canvas>
will be converted into:
new UIComponentDescriptor({
"type":Canvas,
"id":mainCanvas,
"styleFactory":function():void {
this.borderStyle="none";
},
"propertiesFactory":function():Object {
return({
"label":"main"
"childDescriptors":[new UIComponentDescriptor({
// button's code in here
});
]
})
}
})
For those events:
As you can write click event in mxml tags both like btnOnClick() and btnOnClick(event), the compiler need to do something to ensure the event handler accept a right argument. So, for the Button tag I just mention, the
value corresponding to key"event" will be like this: {"click":"__on_click"}. Then the compiler will create a new function call __on_click, which may like this:
public function __on_click(event:MouseEvent):void {
onClick(event);
}
Obviously, after you convert the UIComponentDescriptor into .mxml, you should replace the events function.
For the constructor:
.mxml file can not has a constructor, but the compiler will create one in .as file, which contains the UIComponentDescriptor. The constructor will also do some initialization for it's variables. When converting to .mxml file, you need to do this initialization after the variable's declaration.
For example:
public function MyCanvas(){
this._documentDescriptor_ = new UIComponentDescriptor({
//……
});
this.myArray = new Array();
}
you should convert it into this:
<fx:Script><![CDATA[
var myArray:Array = new Array();
]]></fx:Script>
So the heaviest work is to convert UIComponentDescriptor into .mxml tags. And here is a simple python script that can help you do it:
UIComponentDescriptor2XML
i want to know what i should put befor .mx_internal
override public function initialize() : void
{
var target:DialogButtons;
var watcherSetupUtilClass:Object;
.mx_internal::setDocumentDescriptor(_documentDescriptor_);
var bindings:* = _DialogButtons_bindingsSetup();
var watchers:Array;
target;
if (_watcherSetupUtil == null)
{
watcherSetupUtilClass = getDefinitionByName("_components_DialogButtonsWatcherSetupUtil");
var obj1:* = watcherSetupUtilClass;
obj1.watcherSetupUtilClass["init"](null);
}
_watcherSetupUtil.setup(this, function (param1:String)
{
return target[param1];
}// end function
, bindings, watchers);
var i:uint;
while (i < bindings.length)
{
Binding(bindings[i]).execute();
i = (i + 1);
}
mx_internal::_bindings = mx_internal::_bindings.concat(bindings);
mx_internal::_watchers = mx_internal::_watchers.concat(watchers);
super.initialize();
return;
}// end function
mx_internal should be without dot.
You don't have to reference the mx_internal namespace every time you access it. You can just import it into the class. Use statements like this:
import mx.core.mx_internal;
use namespace mx_internal;
Then re-write your code like this:
override public function initialize() : void
{
var target:DialogButtons;
var watcherSetupUtilClass:Object;
// line commented to snow the mx_internal less code
// .mx_internal::setDocumentDescriptor(_documentDescriptor_);
setDocumentDescriptor(_documentDescriptor_);
var bindings:* = _DialogButtons_bindingsSetup();
var watchers:Array;
target;
if (_watcherSetupUtil == null)
{
watcherSetupUtilClass = getDefinitionByName("_components_DialogButtonsWatcherSetupUtil");
var obj1:* = watcherSetupUtilClass;
obj1.watcherSetupUtilClass["init"](null);
}
_watcherSetupUtil.setup(this, function (param1:String)
{
return target[param1];
}// end function
, bindings, watchers);
var i:uint;
while (i < bindings.length)
{
Binding(bindings[i]).execute();
i = (i + 1);
}
// lines commented to snow the mx_internal less code
// mx_internal::_bindings = mx_internal::_bindings.concat(bindings);
// mx_internal::_watchers = mx_internal::_watchers.concat(watchers);
_bindings = _bindings.concat(bindings);
_watchers = _watchers.concat(watchers);
super.initialize();
return;
}// end function
I have a standard combobox that dispatches a collection event when the dataprovider finishes initializing:
my_cb.addEventListener( CollectionEvent.COLLECTION_CHANGE, getMyStuff );
Then I have a custom component that also has a dataProvider. How do I get it to dispatch a collection change event when its dataprovider finishes loading?
From what I've read, I can't do it. Will dispatching a propertychangeevent work?
Thanks for any helpful tips!
UPDATE:
I have a custom component that I call 'SortingComboBox' but it is not a ComboBox at all; it extends Button and I set is dataProvider property to my arraycollection, model.product (which is an arraycollection).
And here is how I use the dataProvider in that component:
code
[Bindable]
private var _dataProvider : Object;
public function get dataProvider() : Object
{
return _dataProvider;
}
public function set dataProvider(value : Object) : void
{
_dataProvider = value;
}
code
In the createChildren() method of this component, I use this:
BindingUtils.bindProperty(dropDown, "dataProvider", this, "dataProvider");
The dropDown is a custom VBox that I use to display labels.
When you call the setter, you have to make sure
1) that you actually are changing the value with the setter. So even if you are inside the class, call this.dataProvider = foo instead of _dataProvider = foo
2) The binding will not trigger unless you actually change the value. If you trace you'll see that the setter actually calls the getter, if the values of what you pass into the setter and the getter are the same, the binding will not occur.
Your other option is to put an event on the getter, then just call it to trigger the binding.
[Bindable( "somethingChanged" )]
public function get dataProvider() : Object
{
return _dataProvider;
}
dispatchEvent( new Event( "somethingChanged" ) );
Make your dataprovider bindable
[Bindable]
protected var _dataProvider:ArrayCollection ;
Data binding is something unique to ActionScript/Flex.
Among other things it will dispatch change events.
Maybe if you post your code for the custom component I can be more specific.
Actually can you explain what your goal is you are trying to achieve?
All I can tell is you are trying to make a button have a drop down.
Why?
this is the custom component just to give you a better idea.
code
package com.fidelity.primeservices.act.components.sortingcombobox
{
import com.fidelity.primeservices.act.events.component.ResetSortEvent;
import com.fidelity.primeservices.act.events.component.SortEvent;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import mx.binding.utils.BindingUtils;
import mx.controls.Button;
import mx.core.UIComponent;
import mx.effects.Tween;
import mx.events.FlexMouseEvent;
import mx.managers.PopUpManager;
import mx.events.PropertyChangeEvent;
import mx.events.PropertyChangeEventKind;
public class SortingComboBox extends Button
{
private const MAX_LABEL_LENGTH : int = 400;
private const ELIPSES : String = "...";
[Bindable]
private var _dataProvider : Object;
private var dropDown : SortingDropDown;
private var inTween : Boolean;
private var showingDropdown : Boolean;
private var openCloseTween : Tween;
public var noSelectionLabel : String = "No Filter";
public var noSelectionData : String = "ALL";
public function get dataProvider() : Object
{
return _dataProvider;
}
public function set dataProvider(value : Object) : void
{
_dataProvider = value;
}
private function collectionEvent(e : Event):void
{
trace(new Date(), e);
}
public function SortingComboBox()
{
super();
this.buttonMode = true;
this.useHandCursor = true;
inTween = false;
showingDropdown = false;
addEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
}
override protected function createChildren() : void
{
super.createChildren();
dropDown = new SortingDropDown();
dropDown.width = 240;
dropDown.maxHeight = 300;
dropDown.visible = false;
BindingUtils.bindProperty(dropDown, "dataProvider", this, "dataProvider");
dropDown.styleName = "sortingDropDown";
dropDown.addEventListener(SortEvent.CLOSE_SORT, closeDropDown);
dropDown.addEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE, dropdownCheckForClose);
dropDown.addEventListener(FlexMouseEvent.MOUSE_WHEEL_OUTSIDE, dropdownCheckForClose);
dropDown.addEventListener(SortEvent.UPDATE_SORT, onSortUpdate); //this event bubbles
dropDown.addEventListener(ResetSortEvent.RESET_SORT_EVENT, onSortUpdate);
PopUpManager.addPopUp(dropDown, this);
this.addEventListener(MouseEvent.CLICK, toggleDropDown);
// weak reference to stage
systemManager.addEventListener(Event.RESIZE, stageResizeHandler, false, 0, true);
}
private function stageResizeHandler(evt : Event) : void
{
showingDropdown = false;
dropDown.visible = showingDropdown;
}
private function toggleDropDown(evt : MouseEvent) : void
{
if(!dropDown.visible)
{
openDropDown(evt);
}
else
{
closeDropDown(evt);
}
}
private function openDropDown(evt : MouseEvent) : void
{
if (dropDown.parent == null) // was popped up then closed
{
PopUpManager.addPopUp(dropDown, this);
}
else
{
PopUpManager.bringToFront(dropDown);
}
showingDropdown = true;
dropDown.visible = showingDropdown;
dropDown.enabled = false;
var point:Point = new Point(0, unscaledHeight);
point = localToGlobal(point);
point = dropDown.parent.globalToLocal(point);
//if the dropdown is larger than the button and its
//width would push it offscreen, align it to the left.
if (dropDown.width > unscaledWidth && point.x + dropDown.width > screen.width)
{
point.x -= dropDown.width - unscaledWidth;
}
dropDown.move(point.x, point.y);
//run opening tween
inTween = true;
// Block all layout, responses from web service, and other background
// processing until the tween finishes executing.
UIComponent.suspendBackgroundProcessing();
dropDown.scrollRect = new Rectangle(0, dropDown.height, dropDown.width, dropDown.height);
openCloseTween = new Tween(this, dropDown.height, 0, 250);
}
private function closeDropDown(evt : Event) : void
{
//dropDown.visible = false;
showingDropdown = false;
//run closing tween
inTween = true;
// Block all layout, responses from web service, and other background
// processing until the tween finishes executing.
UIComponent.suspendBackgroundProcessing();
openCloseTween = new Tween(this, 0, dropDown.height, 250);
}
private function dropdownCheckForClose(event : MouseEvent) : void
{
if (event.target != dropDown)
// the dropdown's items can dispatch a mouseDownOutside
// event which then bubbles up to us
return;
if (!hitTestPoint(event.stageX, event.stageY, true))
{
closeDropDown(event);
}
}
public function refresh():void
{
onSortUpdate(null);
}
private function onSortUpdate(evt1 : Event) : void
{
//update the label
var dpLength : int = this.dataProvider.length;
var nextLabel : String = "";
var nextData : String = "";
for (var i : int = 0; i < dpLength; i++)
{
if (this.dataProvider[i].selected == true)
{
nextLabel += this.dataProvider[i].label + ", ";
if (this.dataProvider[i].data != null)
{
nextData += this.dataProvider[i].data + ", ";
}
}
}
if (nextLabel.length > 0)
{
// remove extra comma at end
nextLabel = nextLabel.substr(0, nextLabel.length - 2);
}
if (nextData.length > 0)
{
nextData = nextData.substr(0, nextData.length - 2);
}
if (nextLabel.length > MAX_LABEL_LENGTH)
{
// limit label to MAX_LABEL_LENGTH + ... REASON: tooltips with lots of characters take a long time to render
nextLabel = nextLabel.substr(0, MAX_LABEL_LENGTH) + ELIPSES;
}
if (nextLabel.length == 0)
{
nextLabel = noSelectionLabel;
//nextLabel = "No Filter";
}
if (nextData.length == 0)
{
nextData = noSelectionData;
//nextData = "ALL";
}
label = nextLabel;
data = nextData;
toolTip = label;
if (evt1 is SortEvent)
{
trace("sort event");
var temp:Object = this.dataProvider;
this.dataProvider = null;
this.dataProvider = temp;
this.refresh();
}
else
{
trace("not dispatching");
}
}
public function onTweenUpdate(value:Number):void
{
dropDown.scrollRect = new Rectangle(0, value, dropDown.width, dropDown.height);
}
public function onTweenEnd(value:Number) : void
{
// Clear the scrollRect here. This way if drop shadows are
// assigned to the dropdown they show up correctly
dropDown.scrollRect = null;
inTween = false;
dropDown.enabled = true;
dropDown.visible = showingDropdown;
UIComponent.resumeBackgroundProcessing();
}
private function removedFromStage(event:Event):void
{
if(inTween)
{
openCloseTween.endTween();
}
// Ensure we've unregistered ourselves from PopupManager, else
// we'll be leaked.
PopUpManager.removePopUp(dropDown);
}
}
}
Ok this code here
[Bindable]
private var _dataProvider : Object;
public function get dataProvider() : Object
{
return _dataProvider;
}
public function set dataProvider(value : Object) : void
{
_dataProvider = value;
}
is no different then
[Bindable]
public var _dataProvider : Object;
Since objects are passed by reference you are not protecting it in anyway and the setter and getter are pointless.
On the other hand you made the source _dataProvider Bindable so anytime the data changes it will dispatch a CollectionEvent.COLLECTION_CHANGE
I've a tree control with checkboxes that uses the control from http://www.sephiroth.it/file_detail.php?id=151#
Somehow I can't get the control to update when I change the dataProvider (i.e. by clicking a checkbox) the only way I can get it to update is to use the scrollbar. How do I force the update? I've tried all possible methods I can figure out? (see update below)
Also how can I reset the Tree (collpasing all nodes, scroll to the top in a large tree)?
package offerta.monkeywrench.components
{
import offerta.monkeywrench.components.componentClasses.TreeCheckBoxItemRenderer;
import mx.collections.ArrayCollection;
import mx.events.TreeEvent;
public class WatchTree extends TreeCheckBox
{
public var idProperty:String;
public var watchFactory:Function;
private var _wSet:Boolean = false;
/* clientId: */
private var _clientId:String;
[Bindable]
public function get clientId():String
{
return _clientId;
}
public function set clientId(value:String):void
{
this._clientId = value;
}
/* //clientId */
/* watching: */
private var _watching:ArrayCollection;
[Bindable]
public function set watching(value:ArrayCollection):void
{
this._watching = value;
}
public function get watching():ArrayCollection
{
return this._watching;
}
/* //watching */
override public function initialize() :void
{
super.initialize();
addEventListener("itemCheck", onItemCheck, false, 0, true);
}
private function isWatching(id:String):Boolean
{
for each(var w:Object in this._watching)
{
if(w[this.idProperty]==id) return true;
}
return false;
}
private function onItemCheck(event:TreeEvent):void
{
var item:Object = event.item as Object;
var currentValue:uint = (event.itemRenderer as TreeCheckBoxItemRenderer).checkBox.checkState;
if(item.children==null)
{
currentValue==2 ? addWatch(item.Id) : removeWatch(item.Id);
}
else
{
for each(var x:Object in item.children)
{
currentValue==2 ? addWatch(x.Id) : removeWatch(x.Id);
}
}
updateParents(item, currentValue);
updateChilds(item, currentValue);
this.dataProvider.refresh();
super.invalidateProperties();
super.invalidateDisplayList();
super.updateDisplayList(this.unscaledWidth, this.unscaledHeight);
}
private function updateParents(item:Object, value:uint):void
{
var checkValue:String = (value == ( 1 << 1 | 2 << 1 ) ? "2" : value == ( 1 << 1 ) ? "1" : "0");
var parentNode:Object = item.parent;
if(parentNode)
{
for each(var x:Object in parentNode.children)
{
if(x.checked != checkValue)
{
checkValue = "2"
}
}
parentNode.checked = checkValue;
updateParents(parentNode, value);
}
}
private function updateChilds(item:Object, value:uint):void
{
var middle:Boolean = (value&2<<1)==(2<<1);
if(item.children!=null && item.children.length>0&&!middle)
{
for each(var x:Object in item.children)
{
x.checked = value == (1<<1|2<<1) ? "2" : value==(1<<1) ? "1" : "0";
updateChilds(x, value);
}
}
}
private function addWatch(id:String):void
{
if(isWatching(id)) return;
this._watching.addItem(this.watchFactory(id, this.clientId));
}
private function removeWatch(id:String):void
{
for(var i:int=0, n:int=this._watching.length; i<n; ++i)
{
if(this._watching[i][this.idProperty]==id)
{
this._watching.removeItemAt(i);
return;
}
}
}
public function update(__watching:ArrayCollection, __clientId:String):void
{
clientId = __clientId;
watching = __watching;
if(this.dataProvider!=null)
{
var ws:ArrayCollection = ArrayCollection(this.dataProvider);
for each(var group:Object in ws)
{
var count:int = 0;
for each(var child:Object in group.children)
{
if(isWatching(child.Id))
{
child.checked = "1";
count++;
}
}
group.checked = (count==0 ? "0" : (count==group.children.length ? "1" : "2"));
}
this._wSet = false;
var dp:ArrayCollection = ArrayCollection(this.dataProvider);
dp.refresh();
super.invalidateProperties();
super.invalidateDisplayList();
super.updateDisplayList(this.unscaledWidth, this.unscaledHeight);
//scroll up the list???
//collapse? (doesn't work)
this.expandItem(null, false);
}
}
}
}
I've found the Tree control a little touchy in Flex. The way I ended up forcing a redraw was to disconnect the dataProvider and reconnect it, then force validation, something a bit like this :
private function forceRedraw(tree:Tree, dataProvider:Object):void
{
var scrollPosition:Number = tree.verticalScrollPosition;
var openItems:Object = tree.openItems;
tree.dataProvider = dataProvider;
tree.openItems = openItems;
tree.validateNow();
tree.verticalScrollPosition = scrollPosition;
}
I guess this incidentally answers the second part of your question since all you'd have to do is null out the openItems collection and set the verticalScrollPosition to 0.
You might have another problem: whenever you check an item the tree scrolls to the top and this is just annoying. To solve this problem you should update the TreeCheckBox.as file this way:
in function checkHandler:
private function checkHandler( event: TreeEvent ): void;
comment the commitProperties(); call.
Now it should work well.
Cheers.
I've had some minor problem with this solution, var scrollPosition:Number = tree.verticalScrollPosition; is constantly 0??