I'm debugging an issue where an ArrayCollection on a model isn't getting updated in the UI (even though I see it in the new data).
I was wondering if passing that model into other components, i.e. the top level component, causes problems.
For example, here's my model in the top level:
[Bindable]
private var meetingInfo:MeetingInfoModel;
Now here I am passing it into a component in the same class:
<meetingViewStack:MeetingViewStack id="mainPanelContainer"
newAttachmentsList="{meetingInfo.newAttachmentList}"
meetingInfo="{meetingInfo}"
currentState="{getPanelState(currentState)}"
inCreateMeeting="false"
includeIn="runSinglePanel, runDoublePanel"
height="100%"
width="100%"
/>
And here's how I have that property declared in that MeetingViewStack component:
[Bindable]
public var meetingInfo:MeetingInfoModel = MeetingInfoModel.getInstance();
Should binding work correctly in the MeetingViewStack? Even though that property was passed into it by another component.
I mean I really don't have a compelling need to pass it in. It's a model and I can declare it right there.
Thanks for any helpful tips!
UPDATE:
I have verified that the setter gets called when I updated the meetingInfo property. However, it does not get called when I update an array collection in the meetingInfo model, i.e.
meetingInfo.docsAndAttachmentsList.sort = nameSort;
meetingInfo.docsAndAttachmentsList.refresh();
How can I get that to work? That's what I'm really looking for.
Here's the MeetingInfoModel class:
package com.fmr.transporter.model
{
import com.fmr.transporter.events.CustomEvent;
import com.fmr.transporter.events.xmppServicesEvents.XMPPContactsLoadedEvent;
import com.fmr.transporter.services.httpservices.UserServices;
import com.fmr.transporter.services.xmppservices.XMPPServices;
import com.fmr.transporter.util.util;
import com.fmr.transporter.vo.ContactVO;
import com.fmr.transporter.vo.MeetingVO;
import com.fmr.transporter.vo.ParticipantVO;
import flash.events.EventDispatcher;
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
import org.igniterealtime.xiff.data.im.RosterItemVO;
[Bindable]
public final class MeetingInfoModel extends EventDispatcher
{
//Universal INFO
public var generalInfo:GeneralInfoModel;
public var meetingVO:MeetingVO = new MeetingVO();
public var meetingId:String;
public var bulletinBoardLiveMembers:ArrayCollection = new ArrayCollection();
public var xmppServices:XMPPServices;
public var declinedParticipantsGroup:ArrayCollection = new ArrayCollection();
public var notJoinedParticipantsGroup:ArrayCollection = new ArrayCollection();
public var conferenceRoomParticipantsGroup:ArrayCollection = new ArrayCollection();
public var otherLocationParticipantsGroup:ArrayCollection = new ArrayCollection();
public var documentList:ArrayCollection = new ArrayCollection();
public var newAttachmentList:ArrayCollection = new ArrayCollection();
public var docsAndAttachmentsList:ArrayCollection = new ArrayCollection();
public var bulletinBoardMsgList:ArrayCollection = new ArrayCollection();
private var _participantList:ArrayCollection = new ArrayCollection();
public var dismissedMeetingIDs:Array = [];
public var visibleToastWindows:Array = [];
public function MeetingInfoModel()
{
generalInfo = GeneralInfoModel.getInstance();
xmppServices = XMPPServices.getInstance();
_participantList.addEventListener(CollectionEvent.COLLECTION_CHANGE, allParticipantsChangeHandler);
bulletinBoardLiveMembers.addEventListener(CollectionEvent.COLLECTION_CHANGE, bulletinBoardLiveMembersChangeHandler);
}
private static var model:MeetingInfoModel = null;
public static function getInstance():MeetingInfoModel
{
if (model == null)
{
model = new MeetingInfoModel();
}
return model;
}
public function displayToastForThisMeeting(meetingID:Number):Boolean
{
//trace("model::meetingID = " + meetingID);
var doDisplayToast:Boolean = false;
var containsMeetingID:Boolean = false;
//the first one
if(dismissedMeetingIDs.length == 0)
{
//trace("dismissedMeetingIDs.length = 0");
doDisplayToast = true;
dismissedMeetingIDs.push(meetingID);
}
else
{
for(var i:int=0; i < dismissedMeetingIDs.length; i++)
{
//trace("dismissedMeetingIDs[" + i + "] = " + dismissedMeetingIDs[i]);
if(meetingID == dismissedMeetingIDs[i])
{ //this one has already been dismissed
doDisplayToast = false;
containsMeetingID = true;
break;
}
else
{
doDisplayToast = true;
containsMeetingID = false;
}
}
if(containsMeetingID == false)
{
dismissedMeetingIDs.push(meetingID);
}
}
return doDisplayToast;
}
public function setAllParticipants(value:ArrayCollection):void
{
_participantList = value;
dispatchEvent(new CustomEvent(CustomEvent.HAVE_PARTICIPANT_LIST));
calculateGroups();
}
public function getParticipant(loginName:String):ParticipantVO
{
for each (var item:ParticipantVO in _participantList)
{
if (item.loginName == loginName)
{
return item;
}
}
return null;
}
private function allParticipantsChangeHandler(event:CollectionEvent):void
{
calculateGroups();
}
private function bulletinBoardLiveMembersChangeHandler(event:CollectionEvent):void
{
calculateGroups();
}
private function isInRoster( loginName:String ):Boolean {
for each (var newContactVO:ContactVO in model.generalInfo.allGroup)
{
if ( newContactVO.profileVO.email == loginName ) {
return true;
}
}
return false;
}
public function calculateGroups():void
{
var allGroup:ArrayCollection = generalInfo.allGroup;
var participantsRosterGroup:ArrayCollection = new ArrayCollection();
var declinedParticipantsGroup:ArrayCollection = new ArrayCollection();
var notJoinedParticipantsGroup:ArrayCollection = new ArrayCollection();
var conferenceRoomParticipantsGroup:ArrayCollection = new ArrayCollection();
var otherLocationParticipantsGroup:ArrayCollection = new ArrayCollection();
var notDeclinedParticipantsGroup:ArrayCollection = new ArrayCollection();
for each (var item:Object in _participantList)
{
//because participant list contains both people and rooms, we must test to see if this is a participant
if(item is ParticipantVO)
{
var xmppLoginName:String = util.formatEmailToUserName(item.loginName);
for each (var newContactVO:ContactVO in allGroup)
{
if ( item.loginName != model.generalInfo.ownerUser.loginName ) {
var rosterVO:RosterItemVO = newContactVO.rosterItemVO;
if (rosterVO.jid.node == xmppLoginName)
{
try {
var contactVO:ContactVO = new ContactVO();
//add the photo to the roster entry for each person in the meeting
if ( newContactVO.profileVO ) {
rosterVO.photo = newContactVO.profileVO.photo;
contactVO.profileVO = xmppServices.findProfile(rosterVO.jid);
contactVO.profileVO = newContactVO.profileVO;
}
else {
rosterVO.photo = null;
}
contactVO.rosterItemVO = rosterVO;
}
catch (e:Error) {
trace(e.message);
}
if (item.status == "declined")
{
declinedParticipantsGroup.addItem(contactVO);
}
else
{
notDeclinedParticipantsGroup.addItem(contactVO);
}
break;
}
}
}
}
}
for each (var contact:ContactVO in notDeclinedParticipantsGroup)
{
var joined:Boolean = false;
if ( contact.rosterItemVO ) {
for each (var memberName:String in bulletinBoardLiveMembers)
{
if (contact.rosterItemVO.jid.node == memberName)
{
joined = true;
if (contact.rosterItemVO.jid.resource == "theconfroomimsittingin" )
{
conferenceRoomParticipantsGroup.addItem(contact);
}
else
{
otherLocationParticipantsGroup.addItem(contact);
}
//dispatchEvent "DW has joined the meeting"
break;
}
}
}
if (!joined)
{
notJoinedParticipantsGroup.addItem(contact);
}
}
this.notJoinedParticipantsGroup = notJoinedParticipantsGroup;
this.declinedParticipantsGroup = declinedParticipantsGroup;
this.otherLocationParticipantsGroup = otherLocationParticipantsGroup;
this.conferenceRoomParticipantsGroup = conferenceRoomParticipantsGroup;
}
public function clearMeeting():void
{
meetingId = "";
_participantList.removeAll();
docsAndAttachmentsList.removeAll();
documentList.removeAll();
newAttachmentList.removeAll();
bulletinBoardMsgList.removeAll();
bulletinBoardLiveMembers.removeAll();
}
[Bindable]
public function get participantList():ArrayCollection
{
return _participantList;
}
}
}
Think you have the binding the wrong way around.
At the top level it should be:
[Bindable] private var meetingInfo:MeetingInfoModel = MeetingInfoModel.getInstance();
And inside the MeetingViewStack component:
[Bindable] public var meetingInfo:MeetingInfoModel;
It may also depend on what properties in the MeetingInfoModel class are [Bindable].
Related
I'm trying to do do a BattleShip Flash game using ActionScript 3.
1- I draw a grid (class: com.Battleship.grid) using a gridCell:movieClip (class: com.battleship.GridCell)
2- I draw a ship (class: com.battleship.Bateau)
My objective is when I drag the ship to the grid the alpha cell under the mouse changes, and if I drop:
1- if the droptarget is a gridCell, the ship takes place (works fine)
2- if the droptarget is stage, the ship return to originPosition (not working)
My problem: after I used MouseEnabled= false, the ship can drop on the grid, but not on the stage and still dragging.
Here is my code:
var grid:Grid = new Grid(10,new Point(20,20));
var b1:Bateau = new Bateau();
b1.x = 490;
b1.y = 300;
b1.originPos = new Point(b1.x,b1.y);
addChild(b1)
addChild(grid);
package com.battleship {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
public class Bateau extends MovieClip {
private var _originPos:Point;
public function Bateau() {
originPos = new Point();
buttonMode = true;
addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
}
protected function onDrag(e:MouseEvent):void
{
e.currentTarget.parent.addChild(e.currentTarget);
e.currentTarget.startDrag();
e.currentTarget.mouseEnabled = false;
//e.currentTarget.mouseChildren = false;
addEventListener(MouseEvent.MOUSE_UP, onDrop);
parent.addEventListener(MouseEvent.MOUSE_UP, onDrop);
}
protected function onDrop(e:MouseEvent):void
{
e.currentTarget.mouseEnabled = true;
e.currentTarget.mouseChildren = true;
e.currentTarget.stopDrag();
if(dropTarget == null){
x = originPos.x;
y = originPos.y;
}else{
trace(e.currentTarget.name);
if(dropTarget.parent is GridCell)
{
x = dropTarget.parent.x+20;
y = dropTarget.parent.y;
}
}
}
public function get originPos():Point
{
return _originPos;
}
public function set originPos(originPos:Point):void
{
_originPos = originPos;
}
}
}
package com.battleship {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class GridCell extends MovieClip {
private var _row:int;
private var _col:int;
private var _val:int;
public function GridCell()
{
addEventListener(MouseEvent.CLICK,onClick);
addEventListener(MouseEvent.MOUSE_OVER,onMouseOver);
addEventListener(MouseEvent.MOUSE_OUT,onMouseOut);
}
public function onClick(e:MouseEvent)
{
//trace("(" + e.currentTarget.row+ ", " + e.currentTarget.col + ")");
trace(e.currentTarget.name);
}
public function onMouseOver(e:MouseEvent)
{
alpha = 0.6;
}
public function onMouseOut(e:MouseEvent)
{
alpha = 1;
}
public function get row():int
{
return _row;
}
public function set row(row:int):void
{
_row = row;
}
public function get col():int
{
return _col;
}
public function set col(col:int):void
{
_col = col;
}
public function get val():int
{
return _val;
}
public function set val(val:int):void
{
_val = val;
}
}
}
package com.battleship {
import flash.geom.Point;
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Grid extends Sprite {
private var _size:int;
private var _position:Point;
public function Grid(size:int,position:Point):void
{
_size = size;
_position = position;
var gridCells:Array = new Array(size,size);
var i,j:int;
for(i=0;i<size;i++)
{
gridCells[i] = new Array();
for(j=0;j<size;j++)
{
var cell:GridCell = new GridCell();
cell.row = j+1;
cell.col = i+1;
cell.x = this.position.x + cell.width * (i+1);
cell.y = this.position.x + cell.height * (j+1);
cell.name = "cell" + (j+1) + (i+1);
//cell.addEventListener(MouseEvent.CLICK,onClick);
gridCells[i][j] = cell;
this.addChild(gridCells[i][j]);
}
}
}
public function get size():int
{
return _size;
}
public function set size(size:int):void
{
_size = size;
}
public function get position():Point
{
return _position;
}
public function set position(position:Point):void
{
_position = position;
}
}
}
This is an example of one I found online and used (I'm new to object pooling). It works for a single object type but won't allow me to create a pool of different objects
package
{
import starling.display.DisplayObject;
public class SpritePool
{
private var pool:Array;
private var counter:int;
public function SpritePool(type:Class, len:int)
{
pool = new Array();
counter = len;
var i:int = len;
while(--i > -1)
pool[i] = new type();
}
public function getSprite():DisplayObject
{
if(counter > 0)
return pool[--counter];
else
throw new Error("You exhausted the pool!");
}
public function returnSprite(s:DisplayObject):void
{
pool[counter++] = s;
}
}
}
Here is an example of object pool without object count limit.
import flash.utils.Dictionary;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
public class ObjectPool {
public function ObjectPool()
{
throw new Error("don't create instance");
}
private static const objectDict:Dictionary = new Dictionary();
public static function getObject(c:Class):Object{
//if you want add a object count limit,try to check the count here
if (objectDict[c] == null) {
objectDict[c] = [];
}
var t:Array = objectDict[c] as Array;
if (t.length > 0) {
return t.shift();
} else {
return new c();
}
}
public static function putObject(obj:Object):void {
var c:Class = Class(getDefinitionByName(getQualifiedClassName(obj)));
if (objectDict[c] == null) {
return;
}
var t:Array = objectDict[c] as Array;
if (t && t.indexOf(obj) == -1) {
t.push(obj);
}
}
}
So I'm following the book Adobe Flex 4 Training From the Source by Michael Labriola, Jeff Tapper and Matthew Boles, for context.
I'm building a Shopping Cart Class that recieves a ShoppingCartItem object (which is just a POAO) from the mxml and adds it to an ArrayCollection via this public function:
private var $items:ArrayCollection = new ArrayCollection();
public function addItem(item:ShoppingCartItem):void
{
var inCart:Boolean = false;
var currentItem:ShoppingCartItem;
for(var i:int = 0; i < $items.length; i++)
{
currentItem = $items.getItemAt(i) as ShoppingCartItem;
if(item.$product == currentItem.$product)
{
inCart = true;
break;
}
}
if(inCart)
{
currentItem.$quantity++;
}
else
{
$items.addItem(item);
}
updateTotal();
$items.refresh();
}
According to the book, the same function can be achieved with an IViewCursor, like this.
public function addItem(item:ShoppingCartItem):void
{
var cursor:IViewCursor = $items.createCursor();
var inCart:Boolean = cursor.findFirst(item);
if(inCart)
{
var existing:ShoppingCartItem = cursor.current as ShoppingCartItem;
existing.$quantity++;
}
else
{
$items.addItem(item)
}
}
Problem is, when I use this function the item quantity is never updated. Then I have a Shopping cart with 2 entries of 1 product when I should have 1 entry of 2 products. Tracing the inCart boolean yields "false", no matter what I do. The first function works properly and as expected, so I have no idea why the data is not being updated correctly. Also, if I call $items.refresh(); at the end of the second function (for sorting), it throws a NullPointerException error.
Another thing to notice is that I'm using a book for Flex 4 when I'm using the 4.6.0. SDK, the last Adobe release before it was gifted to Apache. I don't know if this is of any importance.
Here's the code for ShoppingCartItem:
[Bindable]
public class ShoppingCartItem
{
public var $product:Product;
public var $quantity:uint;
public var $subtotal:Number;
public function getSubTotal():Number
{
calculateSubTotal();
return $subtotal;
}
public function toString():String
{
return "[ShoppingCartItem]"+$product.prodName+":"+$quantity;
}
public function calculateSubTotal():void
{
this.$subtotal = $product.listPrice*$quantity;
}
public function squeak():void
{
trace("squeak");
}
public function ShoppingCartItem(product:Product, quantity:uint = 1)
{
this.$product = product;
this.$quantity = quantity;
calculateSubTotal();
}
EDIT: More information request by Sunil D.
Product.as class:
[Bindable]
public class Product
{
public var catID:Number;
public var prodName:String;
public var unitID:Number;
public var cost:Number;
public var listPrice:Number;
public var description:String;
public var isOrganic:Boolean;
public var isLowFat:Boolean;
public var imageName:String;
public function toString():String
{
return "[Product]"+this.prodName;
}
public static function buildProductFromAttributes(data:XML):Product
{
var p:Product;
var isOrganic:Boolean = (data.#isOrganic == "Yes");
var isLowFat:Boolean = (data.#isLowFat == "Yes");
p = new Product(data.#catID,
data.#prodName,
data.#unitID,
data.#cost,
data.#listPrice,
data.#description,
isOrganic,
isLowFat,
data.#imageName);
return p;
}
public static function buildProduct(o:Object):Product
{
var p:Product;
p = new Product(o.catId,o.prodName,o.unitID,o.cost,o.listPrice,
o.description,(o.isOrganic == 'true'),
(o.isLowFat == 'true'),o.imageName);
return p;
}
public function Product(cid:Number, name:String, uid:Number, cost:Number, listp:Number, desc:String, iso:Boolean, ilf:Boolean, imn:String)
{
this.catID = cid;
this.prodName = name;
this.unitID = uid;
this.cost = cost;
this.listPrice = listp;
this.description = desc;
this.isOrganic = iso;
this.isLowFat = ilf;
this.imageName = imn;
}
}
ArrayCollection sorting sortfield is the Product POAO contained in the ShoppingCartItem Class. It's done within the constructor function of ShoppingCart like this:
public class ShoppingCart
{
[Bindable]
private var $items:ArrayCollection = new ArrayCollection();
public function ShoppingCart()
{
var prodSort:Sort = new Sort();
var sortField:SortField = new SortField("product");
prodSort.fields =[sortField];
$items.sort = prodSort;
$items.refresh();
}
The reason the viewcursor approach is not working is because the item (ShoppingCartItem) is not in the $items collection. This method compares object references and will hence not find your item if it is another instance of ShoppingCartItem.
In the first approach you are not comparing object references of ShoppingCartItem, but comparing the "product" property of the items.
Ok so my problem is this.
In my main class I have a Boolean type variable. In the external class I have a String type variable.
Is it possible to access the variable in my main class, by using the string value of the variable in my external class. Note that the string value of the external class property matches the main class variable.
I just tryed doing this:
Main class CardGame.as has a variable var slot1:Boolean.
In the external class there is the variable var slot:String = slot1;
I also have this line of code: CardGame['slot'] = false;
It doesn't seem to be working :( . Any help would be appreciated. Thanks
Part of the main class file:
function drawCard():void
{
var card:Card = new Card();
if(slot1 == false)
{
card.x = 30;
slot1 = true;
card.slot = "slot1";
}
else if(slot2 == false)
{
card.x = 190;
slot2 = true;
card.slot = "slot2";
}
else if(slot3 == false)
{
card.x = 350;
slot3 = true;
card.slot = "slot3";
}
else if(slot4 == false)
{
card.x = 510;
slot4 = true;
card.slot = "slot4";
}
else if(slot5 == false)
{
card.x = 670;
slot5 = true;
card.slot = "slot5";
}
else
{
card.x = 830;
slot6 = true;
card.slot = "slot6";
}
card.y = cardY;
cardContainer.addChild(card);
}
And the external file:
import flash.display.MovieClip;
import flash.events.MouseEvent;
import CardGame;
public class Card extends MovieClip
{
public var slot:String;
public function Card()
{
// constructor code
addEventListener(MouseEvent.CLICK, removeCard)
}
function removeCard(event:MouseEvent):void
{
this.parent.removeChild(this);
CardGame['slot'] = false;
}
}
You'll need a few lines of code in the external class:
// in CardGame.as
// declare slot1 as a public var right after the class declaration to insure the
// correct scope
public class CardGame extends MovieClip {
public static var slot1:Boolean;
....
// in external class
import CardGame // depends on where this is in relation to the external class
function theFunction():void {
// somewhere in your external class
var slot:String = CardGame.slot1.toString();
}
// Example classes that show how it works
// Main Class - instantiates ExtClass
package {
import flash.display.Sprite;
public class MainVar extends Sprite {
public static var slot1:Boolean;
private var extClass:ExtClass;
public function MainVar() {
slot1 = true;
this.extClass = new ExtClass();
}
}
}
// External Class accesses static var, modifies static var
package {
public class ExtClass {
public function ExtClass() {
var slot:String = MainVar.slot1.toString();
var index:String = "1";
var slotVar:String = "slot" + index;
trace(slot);
// get the value using a string
trace("String access: ", MainVar[slotVar])
MainVar.slot1 = false;
slot = MainVar.slot1.toString();
trace("Var access: ", slot);
// get the value using a string
trace("String access: ", MainVar[slotVar]);
}
}
}
I have the follow class :
package my.controls.charts.series
{
import mx.charts.series.LineSeries;
import mx.collections.ArrayCollection;
import mx.graphics.SolidColorStroke;
import my.controls.charts.ICommonCharts;
public class TimeLineSeries extends LineSeries implements ICommonCharts
{
[Bindable]
protected var dataProviderLineSeries : ArrayCollection;
public var rawData : Array;
public function TimeLineSeries( seriesName : String )
{
super();
this.displayName = seriesName;
this.yField = "value";
this.xField = "dateBegin";
this.sortOnXField = true;
this.filterData = true;
this.setStyle( "form", "segment" );
var stroke : SolidColorStroke = new SolidColorStroke();
stroke.color = 0xFF0000;
stroke.weight = 1;
this.setStyle( "lineStroke", stroke );
rawData = new Array();
dataProviderLineSeries = new ArrayCollection();
this.dataProvider = dataProviderLineSeries;
}
public function Clear() : void
{
rawData = [];
dataProviderLineSeries.removeAll();
}
public function ApplyData() : void
{
dataProviderLineSeries.removeAll();
dataProviderLineSeries = new ArrayCollection( rawData );
dataProviderLineSeries.refresh();
}
}
}
on the application i am trying the follow :
dinamicSeries : Array = new Array();
mySeries : TimeLineSeries = new TimeLineSeries( 'chronos' );
mySeries.rawData = randomData(); // it is a function which gain some random data
mySeries.ApplyData();
dinamicSeries.push( mySeries );
mainChart.series = dinamicSeries;
The new series name appear on the chart, but the data doest, and the chart always remains blank.
- What wrong I am doing ?
Did you affect a vertical axis to your newly created series ?
You need to make public var rawData into a getter/setter pair, so you can populate the ArrayCollection with it. So:
protected var _rawData:Array;
public function get rawData():Array {
return _rawData;
}
public function set rawData(value:Array):void {
if (value != _rawData) {
_rawData = value;
dataProviderLineSeries.source = value;
}
}