How do I get rid of the "multiple describeType entries" warning? - apache-flex

Does anyone know why when using BindingUtils on the selectedItem property of a ComboBox you get the following warning? Any ideas how to resolve the issue?
The binding still works properly, but it would be nice to get rid of the warning.
warning: multiple describeType entries for 'selectedItem' on type 'mx.controls::ComboBox':
<accessor name="selectedItem" access="readwrite" type="Object" declaredBy="mx.controls::ComboBase">
<metadata name="Bindable">
<arg key="" value="valueCommit"/>
</metadata>

It is better to override the property in question and declare it final.

Here is the code. It is basically a copy of BindingUtils.bindProperty that is setup for a ComboBox so that both the combo box and the model are updated when either of the two change.
public static function bindProperty2(site:Object, prop:String, host:Object, chain:Object, commitOnly:Boolean = false):ChangeWatcher
{
var cbx:ComboBox = null;
if ( site is ComboBox ) { cbx = ComboBox(site); }
if ( host is ComboBox ) { cbx = ComboBox(host); }
var labelField:String = "listID";
var w:ChangeWatcher = ChangeWatcher.watch(host, chain, null, commitOnly);
if (w != null)
{
var func:Function;
if ( site is ComboBox )
{
func = function(event:*):void
{
var dp:ICollectionView = ICollectionView(site.dataProvider);
var selItem:Object = null;
for ( var i:int=0; i<dp.length; i++ )
{
var obj:Object = dp[i];
if ( obj.hasOwnProperty(labelField) )
{
var val:String = String(obj[labelField]);
if ( val == w.getValue() )
{
selItem = obj;
break;
}
}
}
site.selectedItem = selItem;
};
w.setHandler(func);
func(null);
}
else
{
func = function(event:*):void
{
var value:Object = w.getValue();
if ( value == null )
{
site[prop] = null;
}
else
{
site[prop] = String(w.getValue()[labelField]);
}
};
w.setHandler(func);
func(null);
}
}
return w;
}

Related

Using multi filter datatables in asp.net MVC

I'm trying to implement the multiple filters in the datatables in asp.net, but the time I search a value, my table is not updated.
I followed the official example of the site, but it did not work. Here is the source code I'm using.
JS on VIEW
$('#students tfoot th').each( function () {
var title = $(this).text();
if (title !== "") {
$(this).html('<input type="text" class="form-control form-control-sm" style="width: 100%" placeholder="' + title + '" />');
} else {
$(this).html('<div class="text-center">-</div>');
}
} );
tabela.columns().every( function () {
var that = this;
$( 'input', this.header() ).on( 'keydown', function (ev) {
if (ev.keyCode == 13) { //only on enter keypress (code 13)
that
.search( this.value )
.draw();
}
} );
} );
ACTION on CONTROLLER
[HttpPost]
public JsonResult Listar2()
{
var search = Request.Form.GetValues("search[value]")?[0];
var list = db.Students;
if (!string.IsNullOrEmpty(search))
{
list = list.Where(m => m.name.ToLower().Contains(search.ToLower()) || m.class.ToLower().Contains(search.ToLower()));
}
var draw = Request.Form.GetValues("draw")?[0];
var start = Request.Form.GetValues("start")?[0];
var length = Request.Form.GetValues("length")?[0];
var width = length != null ? Convert.ToInt32(length) : 0;
var skip = start != null ? Convert.ToInt32(start) : 0;
var totalRecords = list.Count();
var resultFinal = list.Skip(skip).Take(width).ToList();
return Json(new
{
data = resultFinal,
draw,
recordsFiltered = totalRecords,
recordsTotal = totalRecords
});
}
I don't know what you want to accomplish. The official example uses JavaScript to sort the datatable which is inserted into HTML already. You should load all the entries first, pass them to the view and then this script should filter those entries

How to get format of current selection?

Is there a way to get the format of the current selection? Here is what I have so far:
var currentFormat:TextLayoutFormat;
var selectionStart:int;
var selectionEnd:int;
var operationState:SelectionState;
var editManager:IEditManager;
if (richEditableText.textFlow && richEditableText.textFlow.interactionManager is IEditManager) {
editManager = IEditManager(richEditableText.textFlow.interactionManager);
selectionStart = Math.min(richEditableText.selectionActivePosition, richEditableText.selectionAnchorPosition);
selectionEnd = Math.max(richEditableText.selectionActivePosition, richEditableText.selectionAnchorPosition);
if (operationState == null) {
operationState = new SelectionState(richEditableText.textFlow, selectionStart, selectionEnd);
}
// this does not work
currentFormat = editManager.getCommonCharacterFormat(operationState);
}
I couldn't find anything so here is what seems to work:
/**
* Get format of element range
**/
public static function getElementRangeFormat(elementRange:ElementRange):TextLayoutFormat {
var leaf:FlowLeafElement = elementRange.firstLeaf;
var attr:TextLayoutFormat = new TextLayoutFormat(leaf.computedFormat);
for (;;)
{
if (leaf == elementRange.lastLeaf)
break;
leaf = leaf.getNextLeaf();
attr.concatInheritOnly(leaf.computedFormat);
}
return Property.extractInCategory(TextLayoutFormat, TextLayoutFormat.description, attr, Category.CHARACTER, false) as TextLayoutFormat;
}
Inspired by ElementRange.getCommonCharacterFormat().

In AS3/Flex, how can I get from flat data to hierarchical data?

I have some data that gets pulled out of a database and mapped to an arraycollection. This data has a field called parentid, and I would like to map the data into a new arraycollection with hierarchical information to then feed to an advanced data grid.
I think I'm basically trying to take the parent object, add a new property/field/variable of type ArrayCollection called children and then remove the child object from the original list and clone it into the children array? Any help would be greatly appreciated, and I apologize ahead of time for this code:
private function PutChildrenWithParents(accountData : ArrayCollection) : ArrayCollection{
var pos_inner:int = 0;
var pos_outer:int = 0;
while(pos_outer < accountData.length){
if (accountData[pos_outer].ParentId != null){
pos_inner = 0;
while(pos_inner < accountData.length){
if (accountData[pos_inner].Id == accountData[pos_outer].ParentId){
accountData.addItemAt(
accountData[pos_inner] + {children:new ArrayCollection(accountData[pos_outer])},
pos_inner
);
accountData.removeItemAt(pos_outer);
accountData.removeItemAt(pos_inner+1);
}
pos_inner++;
}
}
pos_outer++;
}
return accountData;
}
I had a similar problem with a hierarchical task set which was slightly different as it has many root elements, this is what i did, seems good to me:
public static function convertFlatTasks(tasks:Array):Array
{
var rootItems:Array = [];
var task:TaskData;
// hashify tasks on id and clear all pre existing children
var taskIdHash:Array = [];
for each (task in tasks){
taskIdHash[task.id] = task;
task.children = [];
task.originalChildren = [];
}
// loop through all tasks and push items into their parent
for each (task in tasks){
var parent:TaskData = taskIdHash[task.parentId];
// if no parent then root element, i.e push into the return Array
if (parent == null){
rootItems.push(task);
}
// if has parent push into children and originalChildren
else {
parent.children.push(task);
parent.originalChildren.push(task);
}
}
return rootItems;
}
Try this:
AccountData:
public class AccountData
{
public var Id:int;
public var ParentId:int;
public var children:/*AccountData*/Array;
public function AccountData(id:int, parentId:int)
{
children = [];
this.Id = id;
this.ParentId = parentId;
}
}
Code:
private function PutChildrenWithParents(accountData:ArrayCollection):AccountData
{
// dummy data for testing
//var arr:/*AccountData*/Array = [new AccountData(2, 1),
// new AccountData(1, 0), // root
// new AccountData(4, 2),
// new AccountData(3, 1)
// ];
var arr:/*AccountData*/Array = accountData.source;
var dict:Object = { };
var i:int;
// generate a lookup dictionary
for (i = 0; i < arr.length; i++)
{
dict[arr[i].Id] = arr[i];
}
// root element
dict[0] = new AccountData(0, 0);
// generate the tree
for (i = 0; i < arr.length; i++)
{
dict[arr[i].ParentId].children.push(arr[i]);
}
return dict[0];
}
dict[0] holds now your root element.
Maybe it's doesn't have the best possible performance but it does what you want.
PS: This code supposes that there are no invalid ParentId's.
Here's what I ended up doing, apparently you can dynamically add new properties to an object with
object['new_prop'] = whatever
From there, I used a recursive function to iterate through any children so you could have n levels of the hierarchy and if it found anything it would pass up through the chain by reference until the original function found it and acted on it.
private function PutChildrenWithParents(accountData : ArrayCollection) : ArrayCollection{
var pos_inner:int = 0;
var pos_outer:int = 0;
var result:Object = new Object();
while(pos_outer < accountData.length){
if (accountData[pos_outer].ParentId != null){
pos_inner = 0;
while(pos_inner < accountData.length){
result = CheckForParent(accountData[pos_inner],
accountData[pos_outer].ParentId);
if ( result != null ){
if(result.hasOwnProperty('children') == false){
result['children'] = new ArrayCollection();
}
result.children.addItem(accountData[pos_outer]);
accountData.removeItemAt(pos_outer);
pos_inner--;
}
pos_inner++;
}
}
pos_outer++;
}
return accountData;
}
private function CheckForParent(suspectedParent:Object, parentId:String) : Object{
var parentObj:Object;
var counter:int = 0;
if ( suspectedParent.hasOwnProperty('children') == true ){
while (counter < suspectedParent.children.length){
parentObj = CheckForParent(suspectedParent.children[counter], parentId);
if (parentObj != null){
return parentObj;
}
counter++;
}
}
if ( suspectedParent.Id == parentId ){
return suspectedParent;
}
return null;
}

Is it possible to make an item in a Flex List control not selectable?

Is it possible to make an item in a List control not selectable? If so, how would this be accomplished?
I've tried one thing so far. What I did was use a custom item renderer that checks for a value in the data property upon a FlexEvent.DATA_CHANGE event. If that value is not set, I tried setting the item renderer's selectable property to false. This, unfortunately, does not seem to work.
Any ideas?
So I came upon a solution of my own. Its similar to yours, and seems to do the trick and cover all the bases apart from hacking the page up and page down keys. I say hack, because I'm not sure it handles the increase or decrease in the caretIndex the same way as the List control. Basically it just manually sets the caretIndex to an index before what the next selectable item is and changes the keycode to a simple up or down.
protected function disabledFilterFunction( data:Object ):Boolean
{
return ( data != null && data.data == null );
}
override protected function mouseEventToItemRenderer( event:MouseEvent ):IListItemRenderer
{
var item:IListItemRenderer = super.mouseEventToItemRenderer( event );
if( item && item.data && disabledFilterFunction( item.data ) )
return null;
return item;
}
override protected function moveSelectionVertically( code:uint, shiftKey:Boolean, ctrlKey:Boolean ):void
{
var i:int;
var newIndex:int;
switch( code )
{
case Keyboard.UP:
newIndex = getPreviousUnselectableIndex( caretIndex - 1 );
break;
case Keyboard.DOWN:
newIndex = getNextUnselectableIndex( caretIndex + 1 );
break;
case Keyboard.HOME:
newIndex = getFirstSelectableIndex();
code = Keyboard.UP;
break;
case Keyboard.END:
newIndex = getLastSelectableIndex();
code = Keyboard.DOWN;
break;
case Keyboard.PAGE_UP:
{
newIndex = Math.max( getFirstSelectableIndex(), getPreviousUnselectableIndex( caretIndex - ( rowCount - 2 ) ) );
code = Keyboard.UP;
break;
}
case Keyboard.PAGE_DOWN:
{
newIndex = Math.min( getLastSelectableIndex(), getNextUnselectableIndex( caretIndex + ( rowCount - 1 ) ) );
code = Keyboard.DOWN;
break;
}
}
if( newIndex > -1 && newIndex < collection.length )
{
caretIndex = newIndex;
super.moveSelectionVertically( code, shiftKey, ctrlKey );
}
}
private function getFirstSelectableIndex():int
{
var result:int = -1;
for( var i:int = 0; i < collection.length; i++ )
{
if( !disabledFilterFunction( collection[i] ) )
{
result = i + 1;
break;
}
}
return result;
}
private function getLastSelectableIndex():int
{
var result:int = -1;
for( var i:int = collection.length - 1; i > -1; i-- )
{
if( !disabledFilterFunction( collection[i] ) )
{
result = i - 1;
break;
}
}
return result;
}
private function getPreviousUnselectableIndex( startIndex:int ):int
{
var result:int = -1;
for( var i:int = startIndex; i > -1; i-- )
{
if( !disabledFilterFunction( collection[i] ) )
{
result = i + 1;
break;
}
}
return result;
}
private function getNextUnselectableIndex( startIndex:int ):int
{
var result:int = collection.length;
for( var i:int = startIndex; i < collection.length; i++ )
{
if( !disabledFilterFunction( collection[i] ) )
{
result = i - 1;
break;
}
}
return result;
}
I was able to fix the problem of first/last items being non-selectable by simply doing this verticalScrollPosition++ and verticalScrollPosition-- right before caretIndex++ and caretIndex-- respectively (in the example that Michael linked to up above) . I couldn't believe that the fix was so easy, but it was!
I was able to do this to add a separator component, following this ComboBox example. Here's an example with the renderer logic stripped out and the selectability logic left in:
package com.example.ui {
import flash.events.MouseEvent;
import flash.ui.Keyboard;
import mx.controls.List;
import mx.controls.listClasses.IListItemRenderer;
public class MyList extends List
{
public function MyList()
{
super();
}
/** Override mouse navigation */
protected override function mouseEventToItemRenderer(event:MouseEvent):IListItemRenderer {
var row:IListItemRenderer = super.mouseEventToItemRenderer(event);
if (row != null && isSelectable(row.data)) {
return null;
}
return row;
}
/** Override keyboard navigation */
protected override function moveSelectionVertically(code:uint, shiftKey:Boolean, ctrlKey:Boolean):void {
super.moveSelectionVertically(code, shiftKey, ctrlKey);
if (code == Keyboard.DOWN && isSeparatorData(selectedItem)) {
caretIndex++;
}
if (code == Keyboard.UP && isSeparatorData(selectedItem)) {
caretIndex--;
}
finishKeySelection();
}
/**
* Define this mechanism in a way that makes sense for your project.
*/
protected function isSelectable(data:Object):Boolean {
return data != null && data.hasOwnProperty("type") && data.type == "separator";
}
}
}
An alternative (still imperfect) that deals better with scrollable lists and consecutive separators:
protected override function moveSelectionVertically(code:uint, shiftKey:Boolean, ctrlKey:Boolean):void {
super.moveSelectionVertically(code, shiftKey, ctrlKey);
var newCode:uint = singleLineCode(code);
var item:Object = selectedItem;
var itemChanged:Boolean = true;
while (!isNaN(newCode) && itemChanged && isSeparatorData(item)) {
super.moveSelectionVertically(newCode, shiftKey, ctrlKey);
itemChanged = (item === selectedItem);
item = selectedItem;
}
}
private function singleLineCode(code:uint):uint {
switch (code) {
case Keyboard.UP:
case Keyboard.PAGE_UP:
return Keyboard.UP;
break;
case Keyboard.DOWN:
case Keyboard.PAGE_DOWN:
return Keyboard.DOWN;
break;
default:
return NaN;
break;
}
return code;
}
Just thought I'd add my two sense. I was wondering the same thing (how to I set a list to not selectable) and I realized that the spark component datagroup would do exactly that. of course you need to be using flex 4, but if you are, and are wondering can I set my list to not selectable, I'd suggest using the datagroup.
I was looking for a solution myself and here's the solution I came up with. Note that I'm using a spark list. I hope someone finds this helpful.
Implement both event handlers for change and changing
Set the selection to -1 and requireSelection to false so that nothing is selected
When you build your dataprovider, enable/disable items as desired
Provide some logic in the changing handler to call 'preventDefault' on the event if it isn't enabled, or shouldn't be selected.
Example: cribbed from my implementation where I build my own items and use a Tile Layout
<s:List id="myListView"
itemRenderer="spark.skins.spark.DefaultComplexItemRenderer"
horizontalCenter="0"
verticalCenter="0"
borderVisible="false"
dataProvider="{myItems}"
change="changeHandler(event)" changing="changingHandler(event)"
requireSelection="false"
selectedIndex="-1" >
<s:layout>
<s:TileLayout verticalGap="0" />
</s:layout>
</s:List>
<fx:script>
<![CDATA[
import mx.collections.ArrayCollection;
import spark.events.IndexChangeEvent;
[Bindable]
public var myItems = new ArrayCollection;
protected function startup():void {
// Here's where you'd build up your items if they
// need to be built dynamically.
}
protected function changeHandler(event:IndexChangeEvent):void
{
var currentIndx:int = event.currentTarget.selectedIndex;
var selectedItem:UIComponent = event.currentTarget.selectedItem as UIComponent;
// Do whatever you need to do on selection here
}
protected function canMicrophoneChange(event:IndexChangeEvent):void
{
var currentIndx:int = event.currentTarget.selectedIndex;
var selectedItem:UIComponent = event.currentTarget.selectedItem as UIComponent;
// This will cancel the select if the item was not enabled.
if (selectedItem.enabled == false) event.preventDefault();
}
]]>
</fx:script>

Flex: Updating a Tree control

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??

Resources