Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Adobe AIR Development

Reply
New Contributor
Posts: 9
Registered: ‎02-09-2011
My Device: Not Specified
Accepted Solution

Reflecting an SQL insert in a List

Hello,

My app has a List on the main sprite.  The data source of that sprite comes from a class that manages an SQLite DB.  There is a function in that class that returns a dataProvider.  In initializeUI() of the main sprite, I contactList.dataProvider = contactSQLData.getTableData();

 

There is another sprite that is loaded at app startup and hidden off the screen.  When the user hits the Add button, that other sprite slides in with a tweener.  The user fills out the form and hits save.  I'm passing the contactList and contactSQLData over to the second sprite via a couple public objects assigned from the main sprite after initialization.

 

When the save button is pressed, I run an insert statement and then tweener the sprite off the screen.  Now back to the main sprite with the list. I want that insert to show up in the list.  BTW the list uses a custom renderer to skin the list cells.

 

To get the insert to show up I've tried, in the Save function:

 

//insert into DB
contactSQLData.addData(time.text, opname.text, notes.text);
//reload dataProvider and assign to list
contactList.dataProvider = contactSQLData.getTableData();
//redraw list on main sprite
contactList.invalidate(InvalidationType.ALL, false);

 

 

Invalidating the list is the only way I can get it to show any type of update, but it seems to only invalidate certain cells.  When I first create the DP in the SQL class I add a header line to it first, then loop through sql results and add them to the DP.  The invalidate on the List put the header line next to last and the new item I just added last and all previous entries are before that.

 

In doing traces I see that the items are added to the DP in the correct order, as they're pulled out of the DB.  But when the list is invalidated, it seem not all of them are being redrawn.

 

Any ideas?

 

Thank you,

Nick

 

 

 

 

Developer
Posts: 2,462
Registered: ‎11-04-2010
My Device: Bold 9700

Re: Reflecting an SQL insert in a List

[ Edited ]

hey nwgarner,

 

the list class is a rough class to get around but we've come a long ways hah. try changing that block of code to the following:

 

 

//insert into DB
contactSQLData.addData(time.text, opname.text, notes.text);

//reload dataProvider and assign to list contactList.dataProvider.setItems(contactSQLData.getTableData().data, true);
//redraw list on main sprite (no need for this line) //contactList.invalidate(InvalidationType.ALL, false);

 

we've found that simply setting a new data provider doesnt do enough so updating the data provider with a new array (via the .data property of the dataprovider you are returning) does the trick. let me know if that does it. good luck!

 

Edit: i also forgot to mention you dont need hte .invalidate() method there either. since we are passing a true value in the setItems() method of the dataprovider, it will refresh the list for us too!

J. Rab (Blog) (Twitter)
--
1. If you liked my post or found it useful please click on the thumbs up and provide a Like!
2. If my post solved your problem please click on the Accept as Solution button. Much appreciated!

Approved Apps: OnTrack | ssShots | Hangman
New Contributor
Posts: 9
Registered: ‎02-09-2011
My Device: Not Specified

Re: Reflecting an SQL insert in a List

[ Edited ]

Hi JRab,

Thank you for your suggestion.  I have implemented this and am still experiencing the problem.  It turns out the problem is with the renderer.  I modified the data being returned in the dataProvider to include a label: and removed the skin from the list, now everything is working.  However, I can't display my data unless I make a big string with spaces in it.

 

In my renderer, I'm using your suggestion of using drawLabel() to handle creating the cell, rather than onAdded(), since the data from the provider is null at that point.

 

In doing some more traces, whenever I save the new contact, the renderer isn't being called for all items in the DP, it's only being called for the LAST item in the DP.  I discovered this when I realized that it was adding the SQL result with ID 1 to the end of the table while I'm sorting results from SQL in descending order.  I changed it to ascending and now I see it adding the new entry to the end of the table.

 

Here's what the table looks like when the app starts.

beforeadd.png

 

I click add, fill in some fields and hit save.

afteradd.png

 

Notice the previous rows 1-3 are now reversed and the new entry is added to the bottom.  If my change my SQL statement to return in DESC order I get this.

afteradddesc.png

 

Very funky.  If I restart the app at this point, everything looks correct.

 

If I remove the contactList.setSkin(ContactsCellRenderer); everything works perfectly.

 

Here's what the cell renderer looks like:

 

package ContactsCellRenderer
{
	import flash.display.Shape;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	
	import qnx.ui.core.Container;
	import qnx.ui.core.ContainerFlow;
	import qnx.ui.listClasses.CellRenderer;
	import qnx.ui.text.Label;

	public class ContactsCellRenderer extends CellRenderer
	{
		private var cellBackground:Shape;

		private var idLabel:Label;
		private var timeLabel:Label;
		private var opnameLabel:Label;
		private var notesLabel:Label;
		private var modeLabel:Label;
		
		private var LABEL_HEIGHT:int = 30;
		
		public function ContactsCellRenderer()
		{
			super();
			
			cellBackground = new Shape();

			idLabel = new Label();
			timeLabel = new Label();
			opnameLabel = new Label();
			notesLabel = new Label();
			modeLabel = new Label();
		}
		
		override protected function init():void 
		{
			super.init();
		}

		
		override protected function onAdded():void
		{
			super.onAdded();
			removeChild(label);
			this.cellBackground.graphics.beginFill(0xBBBBBB, 1);
			this.cellBackground.graphics.drawRect(0, 0, 900, LABEL_HEIGHT);
			this.cellBackground.graphics.endFill();
			this.addChild(this.cellBackground);
		}
		
		override protected function drawLabel():void
		{
			trace("drawLabel()");
			if (this.data)
			{
				var headerFormat:TextFormat = new TextFormat();
				headerFormat = new TextFormat();
				headerFormat.color = 0xFFFFFF;
				headerFormat.bold = true;
				
				/*
				* Sometimes this function is called prematurely when there
				* is no data object available and it is null so we only 
				* do our custom label when there is a data object available
				*/
				this.idLabel.text = this.data.id;
				this.idLabel.width = 30;
				this.idLabel.x = 0;
				
				this.timeLabel.text = this.data.time;
				this.timeLabel.width = 250;
				this.timeLabel.x = 20;;
				
				this.opnameLabel.text = this.data.opname;
				this.opnameLabel.width = 100;
				this.opnameLabel.x = this.timeLabel.width + 30;
				
				this.notesLabel.text = this.data.notes;
				this.notesLabel.width = 100;
				this.notesLabel.x = this.timeLabel.width + this.opnameLabel.width+ 30;
				
				this.modeLabel.text = this.data.mode;
				this.modeLabel.width = 100;
				this.modeLabel.x = this.timeLabel.width + this.opnameLabel.width + this.notesLabel.width + 30;
				
				if (this.data.id == "0")
				{
					this.timeLabel.format = headerFormat;
					this.opnameLabel.format = headerFormat;
					this.notesLabel.format = headerFormat;
					this.modeLabel.format = headerFormat;
				}

				trace("Adding id cell: " + this.data.id);
				this.addChild(idLabel);
				this.addChild(timeLabel);
				this.addChild(opnameLabel);
				this.addChild(notesLabel);
				this.addChild(modeLabel);
			}
		}

		
		override protected function onRemoved():void
		{
			trace("onRemoved");
			super.onRemoved();
			
			//undo the add child
			removeChild(this.cellBackground);
			removeChild(this.idLabel);
			removeChild(this.timeLabel);
			removeChild(this.opnameLabel)
			removeChild(this.notesLabel);
			removeChild(this.modeLabel);
			
		}

	}
}

 What do you think?

 

Thank you for all of your help JRab, you're a great resource in this community from what I've seen when trying to find answers.

 

Nick

 

Developer
Posts: 2,462
Registered: ‎11-04-2010
My Device: Bold 9700

Re: Reflecting an SQL insert in a List

hey nwgarner,

 

the pictures havent been approved so wont be able to see them until they are. however, i think you might be running into a problem in the cell renderer's drawLabel() method. that is only called once when the list is first created. so what you want to do is update your labels when new data is inserted into the cell renderer. to do that you will have to override the set data() setter function as well. that way your custom cell renderer will be able to handle new data when it comes. so to do this, implement the following modified cell renderer:

 

ContactsCellRenderer.as:

 

 

package ContactsCellRenderer
{
import flash.display.Shape;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;

import qnx.ui.core.Container;
import qnx.ui.core.ContainerFlow;
import qnx.ui.listClasses.CellRenderer;
import qnx.ui.text.Label;

public class ContactsCellRenderer extends CellRenderer
{
private var cellBackground:Shape;

private var idLabel:Label;
private var timeLabel:Label;
private var opnameLabel:Label;
private var notesLabel:Label;
private var modeLabel:Label;

private var LABEL_HEIGHT:int = 30;

public function ContactsCellRenderer()
{
super();

cellBackground = new Shape();

idLabel = new Label();
timeLabel = new Label();
opnameLabel = new Label();
notesLabel = new Label();
modeLabel = new Label();
}

override protected function init():void
{
super.init();
}


override protected function onAdded():void
{
super.onAdded();
removeChild(label);
this.cellBackground.graphics.beginFill(0xBBBBBB, 1);
this.cellBackground.graphics.drawRect(0, 0, 900, LABEL_HEIGHT);
this.cellBackground.graphics.endFill();
this.addChild(this.cellBackground);
}

override protected function drawLabel():void
{
trace("drawLabel()");
if (this.data)
{
var headerFormat:TextFormat = new TextFormat();
headerFormat = new TextFormat();
headerFormat.color = 0xFFFFFF;
headerFormat.bold = true;

/*
* Sometimes this function is called prematurely when there
* is no data object available and it is null so we only
* do our custom label when there is a data object available
*/

this.idLabel.width = 30;
this.idLabel.x = 0;

this.timeLabel.width = 250;
this.timeLabel.x = 20;;

this.opnameLabel.width = 100;
this.opnameLabel.x = this.timeLabel.width + 30;

this.notesLabel.width = 100;
this.notesLabel.x = this.timeLabel.width + this.opnameLabel.width+ 30;

this.modeLabel.width = 100;
this.modeLabel.x = this.timeLabel.width + this.opnameLabel.width + this.notesLabel.width + 30;

if (this.data.id == "0")
{
this.timeLabel.format = headerFormat;
this.opnameLabel.format = headerFormat;
this.notesLabel.format = headerFormat;
this.modeLabel.format = headerFormat;
}

trace("Adding id cell: " + this.data.id);
this.addChild(idLabel);
this.addChild(timeLabel);
this.addChild(opnameLabel);
this.addChild(notesLabel);
this.addChild(modeLabel);
}
}


override protected function onRemoved():void
{
trace("onRemoved");
super.onRemoved();

//undo the add child
removeChild(this.cellBackground);
removeChild(this.idLabel);
removeChild(this.timeLabel);
removeChild(this.opnameLabel)
removeChild(this.notesLabel);
removeChild(this.modeLabel);

}

override public function set data(data:Object):void
{
super.data = data;

if (this.data)
{
this.idLabel.text = this.data.id;
this.timeLabel.text = this.data.time;
this.opnameLabel.text = this.data.opname;
this.notesLabel.text = this.data.notes;
this.modeLabel.text = this.data.mode;
}
}

}
}

 

 

So now we are updating the labels with the new set of data whenever there is a change. everything else i think we can leave intact as is and shouldnt be a problem. so re-apply your cellrenderer and see what happens.

 

thanks for the appreication, it's always welcome ! im just glad i can be of some help, the playbook needs all it can get from its third party developers like yourselves in order to succeed. my theory is more quality apps the better it will do over its competition! good luck and let me know how it turns out!

J. Rab (Blog) (Twitter)
--
1. If you liked my post or found it useful please click on the thumbs up and provide a Like!
2. If my post solved your problem please click on the Accept as Solution button. Much appreciated!

Approved Apps: OnTrack | ssShots | Hangman
Highlighted
New Contributor
Posts: 9
Registered: ‎02-09-2011
My Device: Not Specified

Re: Reflecting an SQL insert in a List

You're the best JRab!  All is working.

 

Thanks so much for your help,

Nick