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

Native Development

Reply
Developer
jan_macura
Posts: 20
Registered: ‎08-02-2012
My Device: -
Accepted Solution

ListView with custom headers (sections)

Hi,

 

I need custom headers (basically something like sections in QML native ListView component http://doc.qt.nokia.com/4.7-snapshot/qml-listview.html#section.criteria-prop) in my ListView. In my case I have list of comments that I want to be sorted by DateTime and contain headers: "Today, Yesterday, Last 7 days, Older". Source of the ListView is GroupDataModel (QVariantList from SqlDataAccess).

 

Any Ideas?

 

Thanks,

Jan

 

 

Developer
nicklas
Posts: 150
Registered: ‎02-01-2009
My Device: Torch, PlayBook and Dev Alpha

Re: ListView with custom headers (sections)

As far as I'm concerned I think that it isn't possible !

 

Same, you can't sort on key in ASC and on a second key in DESC.

 

Moreover the title of header section is the value used for sort data :smileysad:

 

So in waiting, I have add a prefix to my sort field and in the QML, I re-format the text.

 

In your case, I do "1-Today", "2-Yesterday","3-Last..." ; then I sort on this key ; and in QML I do value.substring(.....)

To remove my prefix.

 

Nicolas

 

Developer
jan_macura
Posts: 20
Registered: ‎08-02-2012
My Device: -

Re: ListView with custom headers (sections)

Thanks, I had the same idea, but was looking for some better way.

 

Jan

BlackBerry Development Advisor (Retired)
smacmartin
Posts: 499
Registered: ‎05-07-2012
My Device: developer

Re: ListView with custom headers (sections)

You may just want your own data model to sort and feed the data you want displayed.

See: http://supportforums.blackberry.com/t5/Cascades-Development-Knowledge/Using-your-own-DataModel/ta-p/...

 

Stuart

Developer
nicklas
Posts: 150
Registered: ‎02-01-2009
My Device: Torch, PlayBook and Dev Alpha

Re: ListView with custom headers (sections)

attachedObjects: [
    GroupDataModel {
        id: groupDataModel
        objectName: "groupDataModel"
  
        sortingKeys: ["groupid", "name"]
  
        grouping: ItemGrouping.ByFullValue
    }
]
  
ListView {
    id: myList
    objectName: "myList"

    dataModel: groupDataModel

    listItemComponents: [
        ListItemComponent {
            type: "header"
            Container {
                Label {
                    text: {
                        ListItemData.groupname           // Impossible !!! we have to write only "ListItemData" :(
                    }
                }
            }
        },
        ListItemComponent {
            type: "item"
            Container {
                Label {
                    text: {
                        ListItemData.name                // OK - Why is it different of Group item ???
                    }
                }
            }
        }
    ]
  
    function itemType(data, indexPath) {
        if (indexPath.length == 1)
            return "header";
        else
            return "item";
    }
}

 

Above, what we should be able to write.

 

Then, in C++ we populate the datamodel :

{

 // groupid, groupname, name

  { 1, "France", "Paris" },

  { 1, "France", "Lyon" },

  { 2, "Canada", "Vancouver" },

....

}

 

Use our own data model, it's quiet complex to do only this... So RIM should add this as a standard feature.

 

Note: in heaer item, we can't write "ListItemData.groupname" (only ListItemData). RIM should change it also. So as to be able to write in header field several labels :

 

        ListItemComponent {
            type: "header"
            Container {
                Label {
                    text: {
                        ListItemData.groupname
                    }
                }
                Label { 
text: {
ListItemData.anotherfield
}
}
},

 

Nicolas

 

BlackBerry Development Advisor (Retired)
smacmartin
Posts: 499
Registered: ‎05-07-2012
My Device: developer

Re: ListView with custom headers (sections)

[ Edited ]

GroupDataModel sorts the sort keys to present the headers.  So I can't quite wrap my head around displaying some field that isn't derived from the sort key.  It seems inherently dangerous to me.

 

I can see what you are trying to do, but it makes me uncomfortable for the data model to expect the data field to be marked correctly.  A small error in the XML would not be easily detected, and you are repeating the sort order of the field in each line.  This should be under the control of the data model.

 

So here are two other ideas:

  1. Can you not have a sort key that you use to look up the text of the header you want?  e.g. in your case, use a function that returns "France" for 1, "Canada" for 2.   I could then easily change the ordering without changing the sort keys to place Canada #1.  This is essentially what Nicklas suggests.
  2. I think the feature you really want is something to support: "these are the sort keys, but here is my comparitor".   i.e. you want it to use the sort keys {Canada, France, USA} but you want so sort them in some other order.  That seems safer than artificially adding a sort key field in the XML and opening up XmlDataModel to display any arbitrary field.  This would be some extension of ItemGrouping::Type, perhaps.  To support the original problem, the trick here is to define the feature so that items can be merged into the appropriate headers, e.g. merge Canada and USA into a header called North America.  And make the feature easy to define and easy to use.

 

As for writing your own data model: if you are comfortable with C++ then this should be straight-forward.  The hardest part is dealing with QVariant.  But if you find this daunting then it's probably not the right approach for you. OTOH, it gives you complete flexibility of how to organize your data for display.

 

Stuart

BlackBerry Development Advisor (Retired)
smacmartin
Posts: 499
Registered: ‎05-07-2012
My Device: developer

Re: ListView with custom headers (sections)

[ Edited ]

As for the original question, I wouldn't hesitate much before writing my own data model to sort into the appropriate categories, as tomorrow my display will be different than today's display for the same data.  It's the display that is changing, not the data.

 

But if a feature allowed me to provide my own sort into header buckets, I'd probably use that.

 

Stuart

Developer
nicklas
Posts: 150
Registered: ‎02-01-2009
My Device: Torch, PlayBook and Dev Alpha

Re: ListView with custom headers (sections)

I understand your point of view.

 

But, in the header container, we might to want to show several info. Today, we can only show one information.

 

Sample, if I want to do an UI for a mail client :

 

header1 == Today (3 messages unread)

item1_1 == subject 1

item1_2 == subject 2 (in bold)

item1_3 == subject 3 (in bold)

item1_4 == subject 4

item1_5 == subject 5 (in bold)

header2 == Yesterday (all messages read)

item2_1 == ...

item2_2 == ...

item2_3 == ...

item2_4 == ...

header3 == 7 days ago

....

header4 == 1 month ago

...

 

etc,

 

So need to sort on key and show an other field (and even several data) in the header container is usefull !

 

 

For the moment, I do in one field "key;value1;value2;value3" then, in javascript (embedded in qml) I split the string :smileysad:

 

 

Nicolas

 

 

BlackBerry Development Advisor (Retired)
smacmartin
Posts: 499
Registered: ‎05-07-2012
My Device: developer

Re: ListView with custom headers (sections)

If you have a great idea for a feature for GroupDataModel that leads to strong designs and is easy to explain and use, of course submit a feature request!  A strong design would allow the same data to be displayed differently today than tomorrow (the original problem), and would allow the same data to be organized and displayed differently in different lists.

 

What you want is a way to specify:

- what header a record belongs to

- what that header text should be

- how to sort the headers

- how to sort the items within that header.

 

A frequently useful extension to GroupDataModel that would allow this without requiring the display information to be included in the data xml could make a good feature request.

 

However, consider your latest scenario.

 

You're now asking for the header text to depend not only on the sort keys but the number of children under the header, or the number of children under the header with a specific attributes set.   Someone else is looking for a way to display only a subset of the data.  Considering how easy it is to make your own data model to sort, create headers of whatever name you like, or filter the data, are you sure you don't just want the flexibility of your own data model?

 

Stuart

 

 

 

Developer
nicklas
Posts: 150
Registered: ‎02-01-2009
My Device: Torch, PlayBook and Dev Alpha

Re: ListView with custom headers (sections)

Here, an example :

 

import bb.cascades 1.0


// In my sample, I create a mail subject list grouping by date 
// (usefull to write a mail client)
//
// list structs :
// + Today (3/4 unread mails)
//   - *subject1
//   - *subject2
//   - *subject3
//   - subject4
// + Yesterday (1/5 unread mail)
//   - subject1
//   - *subject2
//   - subject3
//   - subject4
//   - subject5
// + One week ago (15 mails)
//   - subject1
//   - subject2
//   - subject3
//   - ...
//   - subject15
// ....
//
// So I define 2 JSON/XML "data" model :
// + header model
//   [ group=1 ; name=Today ; unread=3 ]
//   [ group=2 ; name=Yesterday ; unread=1 ]
//   [ group=3 ; name=One week ago ; unread=0 ]
// + data model
//   [ group=1 ; name=subject1 ; read=false ; date=2012-08-09 11:25:00 ]
//   [ group=1 ; name=subject2 ; read=false ; date=2012-08-09 10:12:00 ]
//   [ group=1 ; name=subject3 ; read=false ; date=2012-08-09 09:00:00 ]
//   [ group=1 ; name=subject4 ; read=true ; date=2012-08-09 08:00:00 ]
//   [ group=2 ; name=subject1 ; read=true ; date=2012-08-08 21:00:00 ]
//   [ group=2 ; name=subject2 ; read=false ; date=2012-08-08 20:00:00 ]
//   [ group=2 ; name=subject3 ; read=true ; date=2012-08-08 19:00:00 ]
//   [ group=2 ; name=subject4 ; read=true ; date=2012-08-08 17:00:00 ]
//   [ group=2 ; name=subject5 ; read=true ; date=2012-08-08 15:00:00 ]
//   [ group=3 ; name=subject1 ; read=true ; date=2012-08-03 14:00:00 ]
//   [ group=3 ; name=subject2 ; read=true ; date=2012-08-02 13:00:00 ]
//   [ group=3 ; name=subject3 ; read=true ; date=2012-08-01 12:00:00 ]
//   [ ... ]
//   [ date=3 ; name=subject15 ; read=true ; date=2012-07-25 01:00:00 ]
//
// /!\ : I have ordered the data only to be easy to read ; but of course, we can 
//       shuffle data

Container {
	attachedObjects: [
		// Define the header model
		GroupHeaderModel {
			id: groupHeaderModel
			objectName: "groupHeaderModel"

			// Set the field used to group the data
			groupingKey: ["group"]

			// Define an option "autohide" = true / false
			//   . true : if there isn't items, the group is hidden
			//   . false : if there isn't items, the group is shown

			// Define option "stick" = true / false
			//   . true : the header is always shown while items during the scroll
			//   . false : the header scroll with the items
		},

		GroupDataModel {
			id: groupDataModel 
			objectName: "groupDataModel"

			// Set the field used to sort items (into a group)
			sortingKeys: ["date", "name"]
		}
	]
    
    ListView {
        id: myList
        objectName: "myList"
    
		layout: StackListLayout {
		}

        layoutProperties: StackLayoutProperties {
        }
    
		headerModel: groupHeaderModel
		dataModel: groupDataModel

        listItemComponents: [
            // First level - header
            ListHeaderComponent {
                type: "header"
                Container {
					Label {
						// We can access to each element of JSON/XML stream
						// ListItemsNumbers is built by system to return the items numbers
						text: writeHeader(ListHeaderData.name, ListHeaderData.unread, ListItemsNumbers)
					}
                }
            },
            // Second level - item
            ListItemComponent {
                type: "item"
                Container {
					// Work as the current implementation :)
// Add built-in variables as to know (i ; j) coordinate in the list / gridlist.
// ListItemX : int = line index
// ListItemY : int = column index
// With these values, we can know if it's an odd or even lines to skin the background line :)
 } } ] function writeHeader(name, unread, total) { if (ListHeaderData.unread > 0) info = ListHeaderData.unread + "/" + total + " unread"; else info = total + " mails"; return title + info; } } }