Nativescript: ListPicker: enable working with an array of objects

Created on 1 Mar 2016  路  12Comments  路  Source: NativeScript/NativeScript

Currently the ListPicker can only display values from an array of strings, however it is not usable for an array of objects, like:
var items = [ {name: "Pizza", price: "8"},{name: "Hot Dog", price: "2"},{name: "Burger", price: "6"} ];.
It would be good if there were properties like:

  • textField - to define which field should be used to display
  • valueField - to define which field should be used to return
  • selectedValue or selectedItem - bindable property, that would contain the selected value (as defined by valueField)

These could be used like this:

    <ListPicker
        items="{{ items }}"
        textField="name"
        valueField="price"
        selectedValue="{{ itemPrice }}"
    ></ListPicker>
question

Most helpful comment

@sebawita I feel like we should re-open this, it's more than a valid scenario, very much a common one that should need less code than this? I feel like we need this to be more dropdownlist\comboboxy with object support.

All 12 comments

Hey @sebawita,

if you override toString() and use binding expressions you can do something like this:

<Page loaded="pageLoaded">
  <StackLayout>
    <Label text="{{ items ? 'Selected item: ' + items[index].name : '' }}" />
    <ListPicker items="{{ items }}" selectedIndex="{{ index }}" />
  </StackLayout>
</Page>
import observable = require("data/observable");
import pages = require("ui/page");

export function pageLoaded(args: observable.EventData) {
    let page = <pages.Page>args.object;

    let items = new Array<any>();
    for (let i = 0; i < 10; i++) {
        let name = `Name ${i}`;
        items.push({ id: i, name: name, toString: () => { return name; } });
    }

    page.bindingContext = { items: items, index: 2 };
}

Furthermore if your bindingContext is not anonymous but Observable the Label text will be updated when you raise change for index property.

@sebawita I feel like we should re-open this, it's more than a valid scenario, very much a common one that should need less code than this? I feel like we need this to be more dropdownlist\comboboxy with object support.

he gave a perfectly good solution.

You can define toString() to return a string.

Using toString is not valid if already being used for serialization. Seems like this should be reopened.

To be honest this workaround feels a little bit hacky, as it requires extra code for something that should be rather simple.
Since UI for NativeScript is free now I moved on to using the AutoComplete component. Or for building the screens where I expect users to enter a lot of data I use DataForm. It just makes my app look and behave a lot better.

Am I correct in understanding that I can't use ListPicker with an array of objects without the hack above ???

As @sebawita said.. ".. feels a little bit hacky, as it requires extra code for something that should be rather simple..."

Hello !

Was this issue resolved?

@Pete Morgan,
It is ListView
I needs ListPicker.

@Topksk
There is a better way from the manual:
https://docs.nativescript.org/api-reference/classes/_ui_list_picker_.listpicker#items
Location Modal

export class Location {
    id: string;
    code: string;
}

Constructor:

import { Component, OnInit } from "@angular/core";
import { ListPicker } from "tns-core-modules/ui/list-picker";
import { Location } from "~/shared/models/location.model";
import { LocationService } from "~/shared/services/location.service";

@Component({
    selector: "Settings",
    moduleId: module.id,
    providers: [LocationService],
    templateUrl: "./settings.component.html"
})
export class SettingsComponent implements OnInit {
    locations: Array<Location> = [];
    items: object = {};
    location: Location;
    selectedIndex: number = 0;

    constructor(private locationService: LocationService) {
    }

    ngOnInit(): void {
        this.locationService.getLocationsAction()
            .subscribe(
                (result: Array<Location>) => {

                    this.locations = result;

                    /*THIS IS WHERE YOU CAN SET THE DISPLAYED TEXT*/
                    this.items = {
                        items: this.locations,
                        length: this.locations.length,
                        getItem: (index) => {
                                const item = this.groeps[index];
                                /*DO WHAT YOU WANT*/
                                return item.name;
                            }
                    };

                },
                (error) => {
                    console.dir(error);
                }
            );
    }

    selectedIndexChanged(args) {
        const picker = <ListPicker>args.object;
        console.log("picker selection: " + picker.selectedIndex);

        this.location = this.locations[picker.selectedIndex];
        console.log("item:");
        //ITEM STILL IS AN OBJECT
        console.dir(this.location);
    }

}

Template:
```html

I've created a PR #6033 to take care of this.
At the moment this is for JS/TS only. Angular is coming next

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rclai picture rclai  路  52Comments

valentinstoychev picture valentinstoychev  路  79Comments

dbbk picture dbbk  路  54Comments

ikhsan017 picture ikhsan017  路  55Comments

surdu picture surdu  路  63Comments