How to: Two-Level List


#1

I am trying to display a list of items that fit within categories. So this would be a list with two levels. How do I do this in Nativescript Angular?

For example, let’s say the list contains different continents, and each continent has its own countries. So I would want to display a list like:

Europe:
–France
–Germany
–Belgium

North America:
–Canada
–US
–Mexico

Africa:
–Nigeria
–Congo

Asia:
–Thailand
–China

The data has the form: continents = [{continentName: Europe, countries: {France, Germany,…}}, {continentName: North America, countries: {Canada, US,…}}, etc…}]

I am able to get the TS file to work fine (I am able to create the data–I know because the data shows up properly when I print to the console).

But I am not yet able to get the UI to display the items.

Using RadListView, here is one unsuccessful attempt:

<GridLayout>
    <RadListView [items]="continents" (itemTap)="selectItem($event)">
        <ng-template tkListItemTemplate let-continent="item" class="marginTop">
            <Label text="{{continent.continentName}}"></Label>
            <StackLayout *ngFor="let country of continent.countries">
                <Label [text]="country"></Label>
            </StackLayout>
        </ng-template>
    </RadListView>
</GridLayout>

This results just in displaying the continent names:

Europe
US
Africa
Asia

I have tried a few different things, like having RadListView within RadListView (instead of *ngfor), but nothing works yet–either just shows continents, shows blank screen, or throws error.

What would be the way to do this?

(I have simplified the data above–in my actual case, each country has its own attributes, like name, population, size, etc.–but thought it would be easier to understand in the simplified form above.)


#2

Because your template’s parent is not a layout, wrap Label and StackLayout with a layout that suits your requirement.


#3

Thanks, but I don’t follow (I am still figuring out Nativescript UI). Can you give a simple example?


#4

Bump. What I am trying to do UI-wise is, I expect, fairly basic, but I do not find any code examples out there. Here’s another way to put it:

The listview UI “deep dive” that Nativescript provides is here: https://www.nativescript.org/blog/a-deep-dive-into-telerik-ui-for-nativescripts-listview

The example that is used in this deep dive is a list like the kind I am describing. The ui there displays a “two-level” list:
Desserts:
–chocolate cake
–cream

Paleo
–Pork Steak
–Homemade Ham

What would be sample code to allow what they are doing in the “ListView” example with NativeScript Angular? The source code to this example is in XML (ie, not NativeScript Angular).


#5

Look for the grouping function here (there’s also a screenshot of what it will look like): http://docs.telerik.com/devtools/nativescript-ui/Controls/NativeScript/ListView/data-operations


#6

Thanks. Seems promising–but is there an html example?

It also seems like there is a lot going on here. In Angular or ionic, this would essentially be like:

<div class="categoryStyling" *ngFor="let category of categories">
  <div>{{category.name}}</div>
  <div class="subGroupStyling" *ngFor="let food of category.foods">
      <div>{{food}}</div>
  </div>
<div>

And…that’s it. There has got to be a comparably straight-forward way to do it in Nativescript Angular (or at least in the ballpark?)


#7

Yeah it’s in the menu: http://docs.telerik.com/devtools/nativescript-ui/Controls/Angular/ListView/data-operations

You can probably copy-paste most of this stuff.


#8

Thanks. With the docs at the link you provided I was able to get this two-level list (aka “grouping” list, I guess) to work. http://docs.telerik.com/devtools/nativescript-ui/Controls/Angular/ListView/data-operations

The code used in the example in the docs had a lot going on–observables, getter/setters, and a very particular type of data being used. Here is my attempt to boil it down and give an example as simple as possible of a two level list (ie, groupingfunction). It is currently working for me, at least on the ios simulator:

html:


  <GridLayout>
      <RadListView [items]="groupItems" (itemTap)="selectItem($event)" >
          <ng-template tkListItemTemplate let-groupItem="item" [groupingFunction]="myGroupingFunc(groupItem)">
              <StackLayout>
                  <Label [text]="groupItem.name"></Label>
                  <Label [text]="groupItem.description"></Label>
              </StackLayout>
          </ng-template>
      </RadListView>
  </GridLayout>

ts:

   export class [YOUR CLASS] {
      private groupItems = [
           {category:'person', name: 'jim', description: 'a very nice person'}, 
           {category:'jungle animal', name: 'lion', description: 'king of the jungle'}, 
           {category:'person', name: 'suzy', description: 'a great person'}, 
           {category:'jungle animal', name: 'tiger', description: 'very fast'}, 
           {category:'jungle animal', name: 'monkey', description: 'a prankster'}, 
           {category:'person', name: 'jessie', description: 'good dancer'}
      ]

      constructor(){

      }

      myGroupingFunc(groupItem) {
        return groupItem.category;
      }

This results in a view output like:

jungle animal 
  lion
  king of the jungle

  tiger
  very fast 

  monkey
  a prankster

person
  jim
  a very nice person

 suzy 
 a great person

 jessie
 good dancer

#9

I am following up on this issue, because the “groupingFunction” method of doing a two level list does work for the simple example like above, but I have found it to be inflexible. What is the best way to show a two level array in Nativescript Angular?

The [grouping function] method in my previous answer doesn’t seem to let me change the look of how the category is displayed. More importantly, it requires that I save my array like above:

oldStuff = [
    {category:'person', name: 'jim', description: 'a very nice person'}, 
    {category:'jungle animal', name: 'lion', description: 'king of the jungle'}, 
    etc...
]

But there are times when this way of saving an array does not work very well. I am now dealing with a more complex array, like:

newStuff = [
    {country: US, city: New York, people: [{name: Bill, age: 22}, {name: Suzy, age: 23] }, 
    {country: US, city: Los Angeles, people: [{name: Sarah, age: 21}, {name: Barb, age: 23] },     
    {country: Canada, city: Toronto, people: [{name: Fred, age: 30}, {name: Ted, age: 31] }
]

And I want to show the array grouped by each element in the array, like:

US
    New York
       Bill, 22
       Suzy, 23

   Los Angeles
      Sarah, 21
      Barb, 23

Canada 
  Toronto
     Fred, 30
     Ted, 31

In normal Angular, you could just do something like:

 *ngFor="let items of newStuff"
     item.country
     item.city
    *ngFor="let persons of item.people"
        person.name
        person.age

How can I do this with Nativescript angular’s UI layout?


#10

Well, it looks like the issue was a question of wrapping in the proper layout. Looks like Nativescript in fact does permit nesting *ngFors within each other. Are there problems with this nesting approach?

I was not as familiar with how layouts worked before–my earlier attempts must have missed because of the layout choices (I think this is what you meant @manojdcoder in your reply).

This actually seems to be working:

newStuff = [
    {country: US, city: New York, people: [{name: Bill, age: 22}, {name: Suzy, age: 23} ] }, 
    {country: US, city: Los Angeles, people: [{name: Sarah, age: 21}, {name: Barb, age: 23} ] },     
    {country: Canada, city: Toronto, people: [{name: Fred, age: 30}, {name: Ted, age: 31} ] }
]

html:

<StackLayout>
    <StackLayout *ngFor="let item of newStuff">
        <Label text="{{item.country}}"></Label>
        <Label text="{{item.city}}" style="margin-left: 40px"></Label>
        <GridLayout columns="*,*" *ngFor="let person of items.people" style="margin-left: 80px">
            <Label col="0" text="{{person.name}}"></Label>
            <Label col="1" text="{{person.age}}"></Label>
        </GridLayout>   
    </StackLayout>
</StackLayout>

To display:

US
    New York
       Bill, 22
       Suzy, 23
   Los Angeles
      Sarah, 21
      Barb, 23
Canada 
  Toronto
     Fred, 30
     Ted, 31

This would need some styling and there may be better layout choices than that. I also have not tried it with RadListView. But the basics here seem to work.


Performance: Nativescript Angular v Nativescript Vanilla