25

I'm sure there is a way to do this, but I just can't see how yet.

What I'd like to do, is add a Picker component, but rather than hard-code the list of items, fetch this from a service and have the Picker bound to something I can populate later.

Here's what I have, but my app won't even run now. Any ideas please?

'use strict';
var React = require('react-native');
var {
    Picker,
    Text,
    View
} = React;

var AvailableServices = React.createClass({
    getInitialState() {
        var fetchServicesUri = 'http://some.url/available_services';
        fetch(fetchServicesUri)
            .then((response) => response.json())
            .then((responseJson) => {
                console.log(responseJson);
                var services = [];
                for(var service in responseJson.services) {
                    services.push(<Picker.Item label={service.Label} value={service.Value}/>);
                }
                this.setState({
                    services: services
                });
            })
            .catch((error) => {
                console.warn(error);
            })
            .done();
        return {
            services: [],
            selectedService: null
        }
    },

    render() {
        return (
            <View>
                <Text>Pick a service</Text>
                <Picker
                    selectedValue={this.state.selectedService}
                    onValueChange={(service) => this.setState({selectedService:service})}
                >
                    {this.state.services}
                </Picker>
            </View>
        );
    }
});

module.exports = AvailableServices;

6 Answers 6

54

You should probably set up your initial state as the empty array, then call your service on componentWillMount or componentDidMount. I've set up something that works with some dummy data here, and pasted the code below.

'use strict';
var React = require('react-native');
var {
    Picker,
    Text,
    View,
      AppRegistry
} = React;

var PickerItem = Picker.Item;

var SampleApp = React.createClass({
    getInitialState() {
        return {
            services: ['a', 'b', 'c', 'd', 'e'],
            selectedService: 'a'
        }
    },

    componentDidMount() {
        setTimeout(() =>  { 
         this.setState({
          services: [ 'one', 'two', 'three', 'four', 'five' ]
         }) 
        }, 3000)
    },

    render() {
        let serviceItems = this.state.services.map( (s, i) => {
            return <Picker.Item key={i} value={s} label={s} />
        });

        return (
            <View>
                <Text>Pick a service</Text>
                <Picker
                    selectedValue={this.state.selectedService}
                    onValueChange={ (service) => ( this.setState({selectedService:service}) ) } >

                    {serviceItems}

                </Picker>
            </View>
        );
    }
});


AppRegistry.registerComponent('SampleApp', () => SampleApp);
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your answer - I've tried it out and definitely getting a lot further. I now get this error: "TypeError: undefined is not an object (evaluating 'this.state.services.map')". It's some issue with parsing the returned JSON from the service call to an object. If I try with your example and use some hard-coded chars it works just fine. Thanks!
@Michael were you calling .map on an array?
Can I ask what PickerItem is used for? I don't see it referenced anywhere. (I'm new to RN and trying to understand.)
I fixed the map error by writing my own loop const srvItems = []; for (var i = 0; i < this.state.service.length; i++) { s = this.state.service[i]; srvItems.push(<Picker.Item key={i} value={s} label={s} />); } and then writing {srvItems} inside the picker. Then works like a bliss.
9

IMPORTANT: if you try to iterate an array of numbers with map then don't forget that label property of Picker.Item should be converted to string:

const pickerItems = [1,2,3].map(i => (
      <Picker.Item label={i.toString()} value={i} />
));

Comments

7

No Loops required, here how i did in my react native based project, similar to above answer to bind or add data dynamically in Picker

import React, {Component} from 'react';
import {Picker,View} from 'react-native';
export default class SampleApp extends Component  {

    constructor(props){
        super(props);
        // HARD CODED DATA , YOU CAN REPLACE THIS DATA  WITH API CALL DATA IN ComponentDidMount() 
       //or in Constructor because countryData is not state.
        this.countryData = ["India","Pakistan","USA"];
        // STATE    
        this.state({
            selectedCountry : null
        });
    }
    // Our country list generator for picker
    countryList = () =>{
        return( this.countryData.map( (x,i) => { 
              return( <Picker.Item label={x} key={i} value={x}  />)} ));
    }
    // RENDER
    render() {
        return (
            <View>
                <Picker
                    selectedValue={this.state.selectedCountry}
                    onValueChange={ (value) => ( this.setState({selectedCountry : value}) )}>
                    { this.countryList() }
                </Picker>
            </View>
        );
    }
}

Hope you find my example simple to understand ;)

Comments

2

You can try this one.

<Picker
      selectedValue={this.state.facilityId}
      style={{ width: '100%' }}
      onValueChange={(itemValue) => this.setState({ facilityId: itemValue, facilityPicked: true })}>
      {facilities.map((facility, i) => {
        return <Picker.Item key={i} value={facility.id} label={facility.facility_name} />
      })}
</Picker>

Here, facilities is a list of object having id and facility_name as key.

Comments

0

I got the same error. The problem is not with picker but instead, with your code.

let items = props.category.map((item,index) => {
     return ( <Picker.Item key={index} label={item.category} value={item.category} /> )
   })
  return(
         <Picker style={styles.pickerStyle}>{items}</Picker>
        );

Instead of using item.category, i was using item.name which caused my app to stop. So check the value of your data.

Comments

0

Question:

I am using map which is a data structure introduced in JS in ES6.

I am using Picker for the dropdown. here's my code :

<Picker
            selectedValue={this.state.branch}
            style={styles.fieldPicker}
            mode="dropdown"

            onValueChange={(itemValue, itemIndex) =>
              this.setState({branch: itemValue})
            }>

            {/* Data Binding */}

                {this.state.branchData.forEach((name, id) => 
                      {
                      return <Picker.Item key={id} value={id} label={name} />;
                      })
                }



          </Picker>

I checked if name and id are being correctly accessed by logging it. The issue is that I am not able to see the dropdown getting populated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.