IconItemRender In Flex 4.5.1 With Dynamically Called Icon - apache-flex

Alright, simple item render, or so I thought... I have an some data loaded into a list, one of the fields is project_Type. It's a string that either says "RESIDENTIAL" or "COMMERCIAL". And based on that string, I just want to display a little house, or a little office building as the icon. So, I cobbled together my itemrender as follows:
<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
labelField="dateAdded"
messageField="builder_Name"
iconFunction="myiconfunction"
iconWidth="48" iconHeight="48"
decorator="#Embed('assets/Right-48x48.png')" >
<fx:Script>
<![CDATA[
// iconFunction="myiconfunction"
// iconWidth="32" iconHeight="32" -->
private function myiconfunction(data:Object):String{
var type:String;
var projectType:String = (data != null) ? data.project_Type : "QUESTION";
if (projectType == "RESIDENTIAL") {
type = "assets/House-48x48.png";
}
else if (projectType == "COMMERCIAL") {
type = "assets/Commercial-48x48.png";
}
else if (projectType == "QUESTION") {
type = "assets/Question-48x48.png";
}
return type;
}
]]>
</fx:Script>
</s:IconItemRenderer>
So, pretty straight forward there... But know custom icon.... No errors either though. What am I doing wrong guys?
Update
So, I changed the item renderer to the following, and still no icon... I've double checked the data and RESIDENTIAL and COMMERCIAL are both being passed...
<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
labelField="dateAdded"
messageField="builder_Name"
iconFunction="myiconfunction"
iconWidth="48" iconHeight="48"
decorator="#Embed('assets/Right-48x48.png')" >
<fx:Script>
<![CDATA[
[Embed(source="assets/House-48x48.png")]
public var residentialClass:Class;
[Embed(source="assets/Commercial-48x48.png")]
public var commercialClass:Class;
[Embed(source="assets/Question-48x48.png")]
public var questionClass:Class;
private function myiconfunction(data:Object):Object
{
var projectType:String = (data != null) ? data.project_Type : "QUESTION";
if (projectType == "RESIDENTIAL") {
return residentialClass;
}
else if (projectType == "COMMERCIAL") {
return commercialClass;
}
return questionClass;
}
]]>
</fx:Script>
</s:IconItemRenderer>
But alas, nothing...

These Mods usually work for me.
<?xml version="1.0" encoding="utf-8"?>
<s:IconItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
labelField="dateAdded"
messageField="builder_Name"
iconFunction="myiconfunction"
iconWidth="48" iconHeight="48"
decorator="#Embed('assets/Right-48x48.png')" >
<fx:Script>
<![CDATA[
private function myiconfunction(data:Object):String
{
var s:String = data.project_Type; //capture data for case match
switch (s.toUpperCase()) {
case "RESIDENTIAL":
return 'assets/House-48x48.png';
break;
case "COMMERCIAL":
return 'assets/Commercial-48x48.png';
break;
default:
return 'assets/Question-48x48.png';
break;
}
}
]]>
</fx:Script>
</s:IconItemRenderer>

Are you sure your icon is ever getting called? Are you sure the path to the icon is correct? Are you sure the icon assets are being embedded in your compiled app?
Instead of returning the path to the object from your function, I'd probably return a class object, not a string value. In half psuedo-code, something like this, which would be inside the renderer:
<fx:Script>
[Embed(source="assets/House-48x48.png")]
public resientialClass : Class;
[Embed(source="assets/Commercial-48x48.png")]
public commercialClass : Class;
[Embed(source="assets/Question-48x48.png")]
public questionClass : Class;
private function myiconfunction(data:Object):Object
var type:String;
var projectType:String = (data != null) ? data.project_Type : "QUESTION";
if (projectType == "RESIDENTIAL") {
return residentialClass;
}
else if (projectType == "COMMERCIAL") {
return commercialClass;
}
return questionClass;
}
</fx:Script>
Specify the renderer function the same way you do in your original code.

Extend the IconItemRenderer class
package {
import spark.components.IconItemRenderer;
public class CustomIconListItemRenderer extends IconItemRenderer
{
[Embed(source="assets/House-48x48.png")]
public resientialClass : Class;
[Embed(source="assets/Commercial-48x48.png")]
public commercialClass : Class;
[Embed(source="assets/Question-48x48.png")]
public questionClass : Class;
public function CustomIconListItemRenderer()
{
super();
iconFunction = iconFunc;
}
private function iconFunc(data:Object):Object
var type:String;
var projectType:String = (data != null) ? data.project_Type : "QUESTION";
if (projectType == "RESIDENTIAL") {
return residentialClass;
}
else if (projectType == "COMMERCIAL") {
return commercialClass;
}
return questionClass;
}
}
}
So then in your list you can assign it as itemRenderer="renderers.CustomIconListItemRenderer"

Related

Combobox filter is effected by its labelFunction flex

I had a comboBox for which I implemented custom filter and the combobox code looks like this
<fx:Declarations>
<s:ArrayCollection id="arrC">
<vo:ValueObject firstValue="430" secondValue="sampath"/>
<vo:ValueObject firstValue="105" secondValue="New York"/>
<vo:ValueObject firstValue="896" secondValue="Xerox"/>
</s:ArrayCollection>
</fx:Declarations>
private function combineFunction(item:Object):String {
return item.firstValue+"-"+item.secondValue;
}
<local:AwadComboBox x="325" y="212" id="cb" dataProvider="{arrC}" labelFunction="combineFunction"/>
the combobox is implememted using a custom filter which extends the combobox
private var unfilteredDataProvider : IList;
override public function set dataProvider(value:IList):void {
super.dataProvider = value;
unfilteredDataProvider = value;
}
override protected function textInput_changeHandler(event:TextOperationEvent):void {
super.textInput_changeHandler(event);
if (unfilteredDataProvider is ArrayCollection) {
ArrayCollection(unfilteredDataProvider).filterFunction = filterMatches;
ArrayCollection(unfilteredDataProvider).refresh();
super.dataProvider = new ArrayCollection(unfilteredDataProvider.toArray());
}
}
protected function filterMatches(item:Object):Boolean {
if (item is String) {
if(String(item).toLowerCase().indexOf(
textInput.text.slice(0,
textInput.selectionAnchorPosition).toLowerCase())>-1)
return true;
}
else if (labelField && labelField!= "") {
if(item.hasOwnProperty(labelField) &&
String(item[labelField]).toLowerCase().indexOf(
textInput.text.slice(0,
textInput.selectionAnchorPosition).toLowerCase())>-1)
return true;
}
return false;
}
In this combobox, watever the character you enter, if that character is in the dropdown list, that value should be filtered but there is a bug in my code, can someone please fix this for me.
Thanks!

Add feature to spark combobox to allow better binding

What I try todo...
I am trying to implement a more advanced dropDownList component. I added a new property selectedValue which can basically take any value. At the moment the component only tries to match the selectedValue with "id" of dataprovider items. When i debug the sample it looks fine, the selectedIndex gets set based on selectedValue.
Problem...
The selectedItem does not show up in dropDownList after startUp, it only appears if i click the dropdown button. Means it is selected but not represented in view.
After application startup...
click to see image
When i click the arrow button on custom component...
click to see image
And here is the code...
MAIN.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:components="ch.fa.ed.ui.components.*"
width="100%" height="100%" >
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private var _dpList : ArrayCollection;
public function get dpList() : ArrayCollection {
if (_dpList == null) {
_dpList = new ArrayCollection();
// create items
var person1 : Object = new Object();
person1.id = 10;
person1.name = "Bush";
var person2 : Object = new Object();
person2.id = 12;
person2.name = "Obama";
var person3 : Object = new Object();
person3.id = 30;
person3.name = "Clinton";
_dpList.addItem(person1);
_dpList.addItem(person2);
_dpList.addItem(person3);
}
return _dpList;
}
public function set dpList(dpList : ArrayCollection) : void {
_dpList = dpList;
}
]]>
</fx:Script>
<s:VGroup>
<s:DropDownList id="ddList" dataProvider="{dpList}" labelField="name" selectedIndex="2"/>
<components:EdDropDownList id="ddList2" dataProvider="{dpList}" labelField="name" selectedValue="30"/>
</s:VGroup>
</s:Group>
EdDrowDownList.as
package ch.fa.ed.ui.components {
import mx.collections.IList;
import spark.components.DropDownList;
/**
* #author Michael Wittwer <michael.wittwer#falution.ch>
* #date 20.09.2012
*/
public class EdDropDownList extends DropDownList {
/* ******************************************************************************************************
* fields *
****************************************************************************************************** */
private var _selectedValue : *;
/* ******************************************************************************************************
* member variables *
****************************************************************************************************** */
private var selectedValueChanged : Boolean;
private var dataProviderChanged : Boolean;
public function EdDropDownList() {
super();
}
/*
* overriding the commitProperties method to make sure the selectedValue field gets represented in ui
*/
override protected function commitProperties() : void {
super.commitProperties();
if (selectedValueChanged && dataProviderChanged) {
// find the item mathing selectedValue and set index
if (selectedValue != null && dataProvider != null) {
for (var i : int = 0; i < dataProvider.length; i++) {
var item : * = dataProvider.getItemAt(i);
if (item.id == selectedValue) {
selectedIndex = i;
break;
}
}
}
dataProviderChanged = false;
selectedValueChanged = false;
}
if (selectedValueChanged) {
selectedValueChanged = false;
// find the item mathing selectedValue and set index
if (selectedValue != null && dataProvider != null) {
for (var i : int = 0; i < dataProvider.length; i++) {
var item : * = dataProvider.getItemAt(i);
if (item.id == selectedValue) {
selectedIndex = i;
break;
}
}
}
}
if (dataProviderChanged) {
dataProviderChanged = false;
// find the item mathing selectedValue and set index
if (selectedValue != null && dataProvider != null) {
for (var i : int = 0; i < dataProvider.length; i++) {
var item : * = dataProvider.getItemAt(i);
if (item.id == selectedValue) {
selectedIndex = i;
break;
}
}
}
}
}
/* ******************************************************************************************************
* getter and setter methods *
****************************************************************************************************** */
[Bindable]
public function get selectedValue() : * {
return _selectedValue;
}
public function set selectedValue(selectedValue : *) : void {
_selectedValue = selectedValue;
selectedValueChanged = true;
invalidateProperties();
}
[Bindable]
override public function set dataProvider(value : IList) : void {
super.dataProvider = value;
dataProviderChanged = true;
invalidateProperties();
}
}
Any ideas how to fix this?
The finally solution is pretty easy. Just put the super.commitProperties(); at the end of the overriding commitProperties() method.
It makes absolutely sence. Because we are manipulating a property (selectedIndex) in our own commitProperties() which was already handled in the super method. So the updates on selectedIndex will not be visible until commitProperties() gets called for the next time.
so commitProperties() looks like this for a working component:
override protected function commitProperties() : void {
if (selectedValueChanged && dataProviderChanged) {
// find the item mathing selectedValue and set index
updateSelectedIndex();
dataProviderChanged = false;
selectedValueChanged = false;
}
if (selectedValueChanged) {
selectedValueChanged = false;
// find the item mathing selectedValue and set index
updateSelectedIndex();
}
if (dataProviderChanged) {
dataProviderChanged = false;
// find the item mathing selectedValue and set index
updateSelectedIndex();
}
super.commitProperties();
}
private function updateSelectedIndex() : void {
if (selectedValue != null && dataProvider != null) {
for (var i : int = 0; i < dataProvider.length; i++) {
var item : * = dataProvider.getItemAt(i);
if (item.id == selectedValue) {
selectedIndex = i;
break;
}
}
}
}
Hope this helps.
The <s:ComboBox> has several bugs including issues which affect binding (as noted in the topic above) and custom text entry. As a work-around, there is an ActionScript, Flex, spark only combo box which fixes many of these issues, it is available as open source.

How to get a view to read data

I need to convert a lot of stuff in my profession - so I'm building a conversion tool for my phone with some of the conversions I use a lot.
Now, I want to be able to build this properly. So far, here's my code:
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Length">
<fx:Script>
<![CDATA[
protected function button1_clickHandler(event:MouseEvent):void
{
var Result:String;
var Finish:Number;
var Start:Number = parseFloat(Input.text);
Finish = Start * convert.selectedItem.data;
Result = String(Finish);
answer.text = Result;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:TextInput id="Input" x="20" y="46"/>
<s:SpinnerListContainer x="140" y="122" width="200" height="200">
<s:SpinnerList id="convert" height="100%" width="100%" labelField="label" selectedIndex="1">
<s:ArrayList>
<fx:Object label="km to mi" data="0.62137119224"></fx:Object>
<fx:Object label="km to yd" data="1093.6132983 "></fx:Object>
<fx:Object label="km to ft" data="3280.839895"></fx:Object>
<fx:Object label="km to in" data="39370.07874"></fx:Object>
<fx:Object label="km to m" data="1000"></fx:Object>
<fx:Object label="km to cm" data="100000"></fx:Object>
<fx:Object label="km to mm" data="1000000"></fx:Object>
</s:ArrayList>
</s:SpinnerList>
</s:SpinnerListContainer>
<s:Label id="answer" x="66" y="533" width="348" text="Answer"/>
<s:Button x="66" y="377" width="338" click="button1_clickHandler(event)" label="Button"/>
</View>
As you can see, I'm going to run into some problems with this:
1) Everything is hard-coded, and if I want to add, remove or change the elements in the array, it's going to be a bit of a pain.
2) I have a view that is essentially the same for my volume and weight conversions. With the same problem.
What I'd like to do, but I'm having some trouble understanding, is getting all that hard-coded stuff in one place and having the same view show it based on my previous view which is just a plain, hard-coded list.
I'm thinking of something like an xml sheet, and adding a category = "length" or category = "weight" element to the objects, so that I can show the category from the xml in the List, then when I click "length" it reads the label + data from this list. Is that a good solution? And how exactly do I get the selectedItem to remember which part of the xml list the view should be populated from?
Would it be better to have several xml files? But that still would mean I have to update a whole bunch of places when I need it.
Basically, I need assistance with:
So - Now the question is two-fold:
1) How to keep a connection to xml/db open across multiple views?
2) How to populate the end-view from information from the db?
Thanks for the advice and help.
I just finished an app about a month ago that's uses what I think would be the most "Flex"ible solution. (hehehehe)
(First Answer:)
If you're into/familiar with (good) database design, you could design a SQLite db that allows you to add to & modify all the data you're working with.
(If not, I'd recommend either:
http://www.amazon.com/The-Art-SQL-Stephane-Faroult/dp/0596008945/ref=sr_1_14?s=books&ie=UTF8&qid=1336262973&sr=1-14
or
http://www.amazon.com/SQL-Demystified-Andrew-Oppel/dp/0072262249/ref=sr_1_1?s=books&ie=UTF8&qid=1336263052&sr=1-1
...this post is going to take longer than I anticipated! hehehhehee ;P =D )
Basically what it'd be is:
Tables for categories (e.g. Volume, Length, etc.) and another for specific name/value pairs ("km to mi" = 0.62137119224 [each in separate columns]) with a category id column to.
Then on your home page you have your init() create an DAO (Data Access Object [research if you don't know already]) for the categories table, then fetch the categories into an ArrayCollection and set it as the dataProvider on your category list (on the home view -- or wherever).
(Second Answer:)
Have your change handler for the category list grab the selectedItem and pass it as the second param in navigator.pushView(). That will send the VO (Value Object -- another to research if you don't know it) to the new View as the "data" property.
In the "pushed view," use your creationComplete handler to "catch" (use) the data variable, which will contain the category's name and id. Create a new DAO for the values table and then use the data.id value to load all your values with that category id. Then set your new ArrayCollection as the dataProvider of your value list.
Then create another View for choosing values to edit in the same way. Except the final view in that "flow" would be a form with inputs for category, name, & value (with save & cancel buttons) that would get populated with the appropriate data too. (Note: use a category DAO to get the names of the categories so that the category names & ids are available if you change a category.
...Then it's just a matter of implementing insert & update methods on that View and the SQL & methods needed in each DAO.
You can use Lita (http://www.dehats.com/drupal/?q=node/58) build, design, pre-populate your database.
...I may come back with some nice example code/files (if I remember)
I made some examples for those who were reading and hoped I would...
//////////////////////////////////////
//VO (Value Object)
//Category.as
//////////////////////////////////////
package dao
{
[Bindable]//Makes all public properties bindable
public class Category
{
import mx.collections.ArrayCollection;
public var id:int = -1;
public var categoryName:String;
private var categoryDao:CategoryDAO;
public function Category() {}
public function get exists():Boolean {
return this.id > -1;
}
//"Super" convenient methods
//Not really part of Value Objects / Value Object Pattern
//May actually be a bad practice if you have many VO instances,
//you have the potential for a DAO instance in each
//when only one instance could be used.
public function insert():void {
if( !categoryDao ){ categoryDao = new CategoryDAO;}
categoryDao.insert( this );
}
public function update():void {
if( !categoryDao ){ categoryDao = new CategoryDAO;}
categoryDao.update( this );
}
public function deleteRow():void {
if( !categoryDao ){ categoryDao = new CategoryDAO;}
categoryDao.deleteRow( this );
}
}
}
//////////////////////////////////////
//DAO (Data Access Object)
//CatagoryDAO.as
//////////////////////////////////////
package dao
{
import flash.data.SQLConnection;
import flash.data.SQLStatement;
import flash.filesystem.File;
import mx.collections.ArrayCollection;
public class CategoryDAO
{
public static var _sqlConnection:SQLConnection;
public var failed:Boolean;
public var errorMessage:*;
public function CategoryDAO() {
}
public function getAll():ArrayCollection
{
var sql:String = "SELECT * FROM categories"
+ " ORDER BY categoryName ASC";
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = sqlConnection;
stmt.text = sql;
stmt.execute();
var result:Array = stmt.getResult().data;
if( result ){
var list:ArrayCollection = new ArrayCollection();
for (var i:int=0; i < result.length; i++){
list.addItem( buildVO( result[i] ) );
}
return list;
} else {
return null;
}
}
public function getByCategoryId(id:int):Category
{
var sql:String = "SELECT * FROM categories WHERE id=?";
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = sqlConnection;
stmt.text = sql;
stmt.parameters[0] = id;
stmt.execute();
var result:Array = stmt.getResult().data;
if( result && result.length == 1 ){
return buildVO( result[0] );
} else {
return null;
}
}
public function insert(category:Category):void
{
var sql:String =
"INSERT INTO categories ( categoryName )" +
" VALUES ( :name )";
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = sqlConnection;
stmt.text = sql;
stmt.parameters[":name"] = category.categoryName;
this.execute( stmt );
}
public function update(category:Category):void
{
var sql:String =
"UPDATE categories" +
" SET categoryName = :name" +
" WHERE id = :id";
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = sqlConnection;
stmt.text = sql;
stmt.parameters[":name"] = category.categoryName;
stmt.parameters[":id"] = category.id;
this.execute( stmt );
}
public function deleteRow(category:Category):void {
var sql:String =
"DELETE FROM categories" +
" WHERE id = :id";
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = sqlConnection;
stmt.text = sql;
stmt.parameters[":id"] = category.id;
this.execute( stmt );
}
protected function execute(stmt:SQLStatement):void {
try {
stmt.execute();
} catch(error:Error) {
this.failed = true;
this.errorMessage = error.message;
}
}
protected function buildVO(o:Object):Category
{
var category:Category = new Category();
category.id = o.id;
category.categoryName = o.categoryName;
return category;
}
public function get sqlConnection():SQLConnection
{
if (_sqlConnection) return _sqlConnection;
var file:File =
File.documentsDirectory.resolvePath(DbUtility.DB_FILE_NAME);
var fileExists:Boolean = file.exists;
_sqlConnection = new SQLConnection();
_sqlConnection.open(file);
return _sqlConnection;
}
}
}
//////////////////////////////////////
//CategoryView.mxml
//////////////////////////////////////
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:dao="dao.*"
opaqueBackground="#111111"
title="All Categorys"
creationComplete="init()">
<fx:Script>
<![CDATA[
import dao.DbUtility;
import dao.DropPoint;
import dao.Category;
import dao.CategoryDAO;
protected var dbVerifyUtil:DbUtility
protected function init():void
{
dbVerifyUtil = new DbUtility;
dbVerifyUtil.confirmDb();
if( dbVerifyUtil.dbExists() ){
var categorysDAO:CategoryDAO = new CategoryDAO;
categoryList.dataProvider = categorysDAO.getAll();
}
}
protected function categorySelected():void
{
navigator.pushView( CategoryListView,
categoryList.selectedItem );
}
protected function newCategory():void
{
navigator.pushView( EditCategoryView );
}
protected function viewCategory():void
{
navigator.pushView( CategoryListView,
categoryList.selectedItem );
}
]]>
</fx:Script>
<s:List id="categoryList"
left="10" right="10" top="10" bottom="85"
change="viewCategory()"
dataProvider="{data}"
itemRenderer="irs.CategoryIR">
</s:List>
<s:Button label="Add Category"
left="104" bottom="10" height="43"
click="newCategory()"/>
<s:Label text="Touch a category to view or edit it."
y="326" horizontalCenter="0"/>
</s:View>
//////////////////////////////////////
//CategoryListView.mxml
//////////////////////////////////////
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:dao="dao.*"
creationComplete="init()">
<fx:Script>
<![CDATA[
import dao.Value;//Value VO
import dao.Category;//Category VO
import mx.collections.ArrayCollection;
import spark.events.IndexChangeEvent;
private var category:Category;
protected function init():void
{
var category:Category = data as Category;
listValues.dataProvider =
valueDAO.getByCategoryId(
category.id );
}
protected function editValue():void
{
navigator.pushView( EditValueView,
listValues.selectedItem );
}
protected function editCategory():void
{
navigator.pushView( EditCategoryView, category );
}
]]>
</fx:Script>
<s:viewMenuItems>
<s:ViewMenuItem label="Edit Category"
click="editCategory()"
icon="#Embed('assets/edit.png')"/>
<s:ViewMenuItem label="Add Location"
click="addLocation()"
icon="#Embed('assets/plus.png')"/>
</s:viewMenuItems>
<s:List id="listValues"
left="10" right="10" top="10" bottom="60"
labelFunction="labelValue"
change="editValue()"
itemRenderer="irs.ValueIR">
</s:List>
</s:View>
Have you looked at using resource bundles? Or LSOs?
When persisting Flex data, you have 4 main options.
Relational Databases (seems like overkill here)
XML (which you already seem comfortable with)
Resource Bundles
Local Shared Objects
The LSO example, linked above (#4), gives a potential solution to your question:
... how exactly do I get the selectedItem to remember which part of the xml list the view should be populated from?
snippet:
public function initApp():void {
mySO = SharedObject.getLocal("mydata");
if (mySO.data.visitDate==null) {
welcomeMessage = "Hello first-timer!"
} else {
welcomeMessage = "Welcome back. You last visited on " +
getVisitDate();
}
}
private function getVisitDate():Date {
return mySO.data.visitDate;
}
private function storeDate():void {
mySO.data.visitDate = new Date();
mySO.flush();
}
private function deleteLSO():void {
// Deletes the SharedObject from the client machine.
// Next time they log in, they will be a 'first-timer'.
mySO.clear();
}
I'd recommend using either a combination of XML and LSOs or resource bundles and LSOs--where your XML/RB stores non-changing, static data and your LSO keeps track of dynamic data (view settings, etc).
Data retrieve
As I understand your problem, you don't have to keep a connection open.
Retrieve the data from your database
Parse and store the retrieved
data in a collection ideally an ArrayCollection (you don't want to
handle XML based objects, they're fine when manipulating String
values, but they instantly become a pain in the .as when you want to
perform type-conversion and advanced add and remove operations)
Generic conversion
Then, with binding as in the following sample, all you have to do is always have two conversions when you convert a value from an unit to another :
conversion into a defined unit (ideally the SI unit, as in my
example)
conversion from the SI unit to the desired unit.
Sample
<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="400" minHeight="300">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var unitz:ArrayCollection = new ArrayCollection([
{
label:"Length",
units: new ArrayCollection([
{label: "meter", toSI: 1},
{label: "kilometer", toSI: 1000},
{label: "inch", toSI: 0.0254}
])
},
{
label:"Temperature",
units: new ArrayCollection([
{label: "kelvin", toSI: 1},
{label: "celsius", toSI: 274.15},
{label: "farenheit", toSI: 255.927778}
])
}
]);
private function resetFields():void
{
fromValue.text = "";
toValue.text = "";
}
private function onInputChange():void
{
var fu:Object = fromUnitCB.selectedItem;
var tu:Object = toUnitCB.selectedItem;
toValue.text = (Number(fromValue.text)*fu.toSI/tu.toSI).toString();
}
]]>
</fx:Script>
<s:HGroup width="100%" height="40">
<s:ComboBox
id="categoryCB"
dataProvider="{unitz}"
change="resetFields()"
/>
<s:ComboBox id="fromUnitCB" dataProvider="{categoryCB.selectedItem.units}"/>
<s:ComboBox id="toUnitCB" dataProvider="{categoryCB.selectedItem.units}"/>
</s:HGroup>
<s:HGroup width="100%">
<s:TextInput id="fromValue" change="onInputChange()"/>
<s:Label id="toValue"/>
</s:HGroup>
</s:Application>

Flex 3: Strange behavior when function does a simple math operation

So, in one of my modules, a variable named numDays is created by looping through some XML data and finding the maximum value of an xml field calls days. After the numDays variable is found, I use it to find the width of a canvas by doing:
wrapper.width = numDays * parentApplication.oneDay;
(oneDay is a value determined by dividing the width of the window by 14)
So, now that I know how wide the wrapper canvas is, I can start to fill it. I have four items that are going into the wrapper: 1) Role description, 2) left controller, 3) name textbox (auto suggest component), 4) right controller. The width of the role description is 30px. The left and right controllers are 20 px each. So in order to get the width of the name textbox, I have a function that does the following:
nameTextbox.width = wrapper.width - 70;
for some reason when I do this, the application doesn't load fully. It pretty much stalls out. I have 30 "projects" with 15 "positions" within each of them. the wrapper.width is describing the width of a position, so there are 450 name textboxes trying to be figured out. Is this why it's messing up?
EDIT
So, from the main application, the project module is called. From within the project module, a list is created with a datasource of "positionsAC":
<mx:List id="wholePosition" dataProvider="{positionsAC}" width="100%" height="100%" paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0" backgroundAlpha="0" verticalScrollPolicy="off" itemRenderer="modules.position" useRollOver="false" selectable="false">
Below is a c/p of the position module in it's entirety
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:components="com.hillelcoren.components.*" dataChange="allData = data as Array" layout="absolute" creationComplete="init();" horizontalScrollPolicy="off">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable] public var positionInfo:Array;
[Bindable] public var wholePositionID:Number;
[Bindable] public var allData:Array;
[Bindable] public var positions:XML;
[Bindable] public var startOffset:Number;
[Bindable] public var numDays:Number;
[Bindable] public var role:String;
[Bindable] public var studentID:Number;
[Bindable] public var conflict:Number;
[Bindable] public var studentType:String;
[Bindable] public var showInPrinciple:Number;
[Bindable] public var positionX:Number = 0;
[Bindable] public var positionWidth:Number = 0;
[Bindable] public var sName:String = new String;
[Bindable] public var asAC:ArrayCollection = new ArrayCollection;
[Bindable] public var conflictBG:uint = 0xffffff;
[Bindable] public var roleColor:uint = 0x000000;
private function init():void
{
if (allData)
{
getInfo(allData);
setBGColor();
getPositionX();
getPositionWidth();
getRightStudents();
}
}
private function getInfo(a:Array):void
{
var tempArray:Array = new Array;
startOffset = Number(a[0]);
numDays = Number(a[1]);
positionWidth = parentApplication.oneDay * numDays;
setStudentNameW();
role = a[2];
studentID = Number(a[3]);
tempArray = parentApplication.studentsDBIDDict[String(studentID)] as Array;
conflict = Number(a[4]);
studentType = a[5];
sName = "test";
showInPrinciple = a[6];
}
private function setStudentNameW():void
{
if (numDays == 1)
{
studentName.width = 55;
studentName.x = 37;
contractLeft.visible = false;
contractRight.visible = false;
}
else if (numDays == 2)
{
Alert.show("HI");
studentName.width = 133;
}
else if (numDays == 3)
studentName.width = 230;
else if (numDays == 4)
studentName.width = 330;
if (numDays > 1)
{
studentName.x = 47;
contractLeft.visible = true;
contractRight.visible = true;
}
}
public function setBGColor():void
{
if (conflict == 1)
conflictBG = parentApplication.errorColor;
else if (conflict == 2)
conflictBG = parentApplication.okErrorColor;
else
conflictBG = 0xFFFFFF;
}
private function getPositionX():void
{
positionX = parentApplication.oneDay * startOffset - 1;
}
private function getPositionWidth():void
{
positionWidth = parentApplication.oneDay * numDays;
}
private function getRightStudents():void
{
if (studentType == "freshman")
makeASAC(parentApplication.freshmanAC);
else if (studentType == "bfa1")
makeASAC(parentApplication.bfa1AC);
else if (studentType == "bfa2")
makeASAC(parentApplication.bfa2AC);
else if (studentType == "bfa3")
makeASAC(parentApplication.bfa3AC);
else if (studentType == "mfa1")
makeASAC(parentApplication.mfa1AC);
else if (studentType == "mfa2")
makeASAC(parentApplication.mfa2AC);
else if (studentType == "mfa3")
makeASAC(parentApplication.mfa3AC);
else if (studentType == "mfaw1")
makeASAC(parentApplication.mfaw1AC);
else if (studentType == "mfaw2")
makeASAC(parentApplication.mfaw2AC);
else if (studentType == "mfaw3")
makeASAC(parentApplication.mfaw3AC);
}
private function makeASAC(students:ArrayCollection):void
{
for (var i:int = 0; i < students.length; i++)
asAC.addItem(parentApplication.getStudentName(students.getItemAt(i)));
}
private function posLength(whichSide:String, expandContract:String):void
{
if (whichSide == 'l')
{
if (expandContract == 'e')
{
if (startOffset > 0)
{
numDays++;
startOffset--;
getPositionX();
getPositionWidth();
}
}
else if (expandContract == 'c')
{
if (numDays > 1)
{
numDays--;
startOffset++;
getPositionX();
getPositionWidth();
}
}
}
else if (whichSide == 'r')
{
if (expandContract == 'e')
{
if (numDays + startOffset < parentDocument.projectLength)
{
numDays++;
getPositionX();
getPositionWidth();
}
}
else if (expandContract == 'c')
{
if (numDays > 1)
{
numDays--;
getPositionX();
getPositionWidth();
}
}
}
//parentApplication.conflicts();
}
]]>
</mx:Script>
<mx:Canvas id="positionWrapper" width="{positionWidth}" height="25" backgroundColor="#ffffff" horizontalScrollPolicy="off" borderColor="#000000" borderStyle="solid" borderThickness="1">
<mx:Text id="roleText" text="{role}" width="25" y="3" color="{roleColor}" fontSize="11" fontWeight="bold" click="parentApplication.getDictLen(parentApplication.studentsDBIDDict)" />
<mx:Canvas id="leftSide" x="25" width="22" height="100%" mouseOver="expandLeft.visible = true; contractLeft.visible = true;" mouseOut="expandLeft.visible = false; contractLeft.visible = false;" backgroundColor="{conflictBG}" horizontalScrollPolicy="off">
<mx:Image id="expandLeft" source="images/addRed.png" y="5" click="posLength('l', 'e')" mouseOver="parentApplication.switchCursor(true);" mouseOut="parentApplication.switchCursor(false);" visible="false" />
<mx:Image id="contractLeft" source="images/minusRed.png" x="10" y="5" click="posLength('l', 'c')" mouseOver="parentApplication.switchCursor(true);" mouseOut="parentApplication.switchCursor(false);" visible="false" />
</mx:Canvas>
<components:AutoComplete id="studentName" textAlign="center"
dataProvider="{asAC}"
x="47" y="3"
/>
<mx:Image id="showSNW" source="images/searchicon.png" x="{(studentName.width + studentName.x) - 12}" y="5" visible="false" mouseOver="parentApplication.switchCursor(true); studentName.enabled = false;" mouseOut="parentApplication.switchCursor(false); studentName.enabled = true; showSNW.visible = false;" />
<mx:Canvas id="rightSide" x="{positionWrapper.width - 22}" width="20" height="100%" mouseOver="expandRight.visible = true; contractRight.visible = true;" mouseOut="expandRight.visible = false; contractRight.visible = false;" backgroundColor="{conflictBG}" horizontalScrollPolicy="off">
<mx:Image id="contractRight" source="images/minusRed.png" y="5" click="posLength('r', 'c')" visible="false" mouseOver="parentApplication.switchCursor(true);" mouseOut="parentApplication.switchCursor(false);" />
<mx:Image id="expandRight" source="images/addRed.png" x="10" y="5" click="posLength('r', 'e')" visible="false" mouseOver="parentApplication.switchCursor(true);" mouseOut="parentApplication.switchCursor(false);" />
</mx:Canvas>
</mx:Canvas>
Best to get a debugger. Flash Builder 4 is a pretty decent one, and they even give out free standard licenses to
Students, faculty and staff of eligible educational institutions
Software developers who are affected by the current economic condition and are currently unemployed
Event attendees who receive a special promotional code at their event
Check this out
Also, get debugger versions of the latest Flash Player here
The free standard might take some time to come, but you can always use the free trial in the meanwhile.
When you debug, check that nameTextBox is not null.

Add "New item Label" to Spark ComboBox

I have a Custom Spark ComboBox which contains a list of items. I want to Add a new Item to the ComboBox stating the text "Add new Item", which on selecting popup a window to do some operations.
I have achieved this by creating a new object of the same type of the entities in the data provider, with the LabelField of the new object having the text "Add new Item". I have override the set dataProvider method and in the custom combobox.
But this adds the values to the Actual List which is binded to the DataProvider. The list is used in the business logics. So i do not want this to happen. I have lot of Entity Classes. i could not change all the objects.
All i want is to achieve the same functionality in my custom component without changing the other code. I have also tried to create a new instance of dataProvier but i noticed that the binding of the List and dataprovider is lost when i created a new instance.
Kindly help.!!
Edited:
ExtendedComboBox.as
package components
{
import flash.utils.getDefinitionByName;
import mx.collections.ArrayCollection;
import mx.collections.IList;
import spark.components.ComboBox;
import spark.events.DropDownEvent;
public class ExtendedComboBox extends ComboBox
{
private var _addItem:Boolean = false;
private var _addItemLabel:String = "Create New Item" ;
private var _dropDownClass:String = null ;
private var originalDP:IList ;
private var dpEdited:Boolean = false;
public function ExtendedComboBox()
{
super();
this.addItem = true;
this.addEventListener(DropDownEvent.CLOSE, dropDownCloseEventListner );
this.addEventListener(DropDownEvent.OPEN, openDropDownEvent );
}
public function get dropDownClass():String
{
return _dropDownClass;
}
public function set dropDownClass(value:String):void
{
_dropDownClass = value;
}
public function get addItemLabel():String
{
return _addItemLabel;
}
public function set addItemLabel(value:String):void
{
_addItemLabel = value;
}
public function get addItem():Boolean
{
return _addItem;
}
public function set addItem(value:Boolean):void
{
_addItem = value;
}
private function dropDownCloseEventListner(event:DropDownEvent):void{
}
protected function openDropDownEvent(event:DropDownEvent):void{
if(addItem)
{
// if(value) value = new ArrayCollection();
var value:IList ;
if(originalDP == null) value = new ArrayCollection ;
else value = new ArrayCollection( originalDP.toArray() ) ;
var tempObj:Object;
var createItemPresent:Boolean =false ;
if(dropDownClass != null)
{
var TempClass = flash.utils.getDefinitionByName(dropDownClass) as Class;
tempObj = new TempClass();
if(value.length >0)
{
// trace(value.getChildAt(0)[this.labelField]) ;
if(value.getItemAt(0)[this.labelField] == addItemLabel)
createItemPresent = true ;
}
if(!createItemPresent)
{
tempObj[this.labelField] = addItemLabel ;
var sort = (value as ArrayCollection).sort ;
value.addItemAt(tempObj, 0);
(value as ArrayCollection).sort = sort ;
dpEdited = true;
}
}
}
super.dataProvider = value;
}
override public function set dataProvider(value:IList):void{
if(!dpEdited)
{
originalDP = value;
dpEdited = true;
}
/*if(addItem)
{
// if(value) value = new ArrayCollection();
var tempObj:Object;
var createItemPresent:Boolean =false ;
if(dropDownClass != null)
{
var TempClass = flash.utils.getDefinitionByName(dropDownClass) as Class;
tempObj = new TempClass();
if(value.length >0)
{
if(value.getItemIndex(0)[this.labelField] == addItemLabel)
createItemPresent = true ;
}
if(!createItemPresent)
{
tempObj[this.labelField] = addItemLabel ;
var sort = (value as ArrayCollection).sort ;
value.addItemAt(tempObj, 0);
(value as ArrayCollection).sort = sort ;
}
}
}*/
super.dataProvider = value;
}
}
}
MyEntityObj.as
package entity
{
public class MyEntityObj
{
private var _name:String ;
private var _age:int ;
private var _company:String;
public function MyEntityObj()
{
}
public function get company():String
{
return _company;
}
public function set company(value:String):void
{
_company = value;
}
public function get age():int
{
return _age;
}
public function set age(value:int):void
{
_age = value;
}
public function get name():String
{
return _name;
}
public function set name(value:String):void
{
_name = value;
}
}
}
And Implementation Sample - ComboImpl.mxml
<?xml version="1.0" encoding="utf-8"?>
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
import mx.events.FlexEvent;
[Bindable]
private var samplDP:ArrayCollection;
protected function application1_initializeHandler(event:FlexEvent):void
{
samplDP = new ArrayCollection ;
samplDP.addEventListener(CollectionEvent.COLLECTION_CHANGE, changeHandlerFunc );
var sampVO:MyEntityObj;
for(var i:int = 0; i<5;i++)
{
sampVO = new MyEntityObj;
sampVO.name = "Name " + i;
sampVO.age = i;
sampVO.company = "Company " + i;
samplDP.addItem(sampVO);
}
}
protected function changeHandlerFunc(event:CollectionEvent):void{
var nameList:String = "" ;
for each(var myObj:* in samplDP)
{
nameList += myObj.name + ", " ;
}
changeHandler.text = nameList ;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:VGroup>
<s:Label id="changeHandler" />
<components:ExtendedComboBox dataProvider="{samplDP}" labelField="name" addItem="true" dropDownClass="entity.MyEntityObj" addItemLabel="Create Sample" />
</s:VGroup>
As commented in the set DataProvider Overridden method and the in the DropDownClose events addition of the new item directly affects the original List. i do not want this to happen.
Note that its just a sample implementation. The component creation in my project actually happens in the action script class dynamically.
Kindly help.!!
It sounds to me like:
You're going to have to extend the ComboBox (If you drill down into how it's implemented, possibly the DataGroup) to include your extra "Add New Item" item w/o it being in the dataProvider.
I expect this to be very difficult, but have not reviewed the code for this purpose.

Resources