Maslow
Maslow

Reputation: 1104

Show DrawerLayoutAndroid via ToolbarAndroid => onIconClicked

I'm new to React native (and React) and I'm playing around a little bit with it.

I managed to add a DrawerLayout that I can drag from the left of my screen. However I'd like to open it when I click on my menu icon in my ToolbarAndroid.

I tried to use "refs" but it doesn't seem to work

I hope I'm clear enough.

Thank you

Upvotes: 18

Views: 8515

Answers (5)

Edison D'souza
Edison D'souza

Reputation: 4640

"undefined is not an object" - Most of us ended up here with a above solution.

Please ensure that you have correctly used the ES6 syntax as mentioned below.

Incorrect Syntax:

onPress={this.drawer()}

Correct Syntax:

onPress={() => this.drawer()}

Code:

<DrawerLayoutAndroid
   ...
   ref={'DRAWER_REF'}
   ...
/>

--------------------------------------------------

//Write this just before render() method

drawer = () => {
  this.refs['DRAWER_REF'].openDrawer();
}

--------------------------------------------------

<TouchableHighlight onPress={() => this.drawer()}>
   <Icon name="bars" size={30} color="#900"/>
</TouchableHighlight>

Upvotes: 2

GuGuss
GuGuss

Reputation: 81

Following all those snippets and still getting the undefined is not an object error.

Then found this thread on GitHub which finally solved my issue and explains the refs problem perfectly.

To follow the DrawerLayoutAndroid example on the React Native documentation (http://facebook.github.io/react-native/docs/drawerlayoutandroid.html), this is the code which works:

constructor() {
  super();
  this.openDrawer = this.openDrawer.bind(this);
} 

openDrawer() {
  this.drawer.openDrawer();
}

render() {
  var navigationView = (
    <View style={{flex: 1, backgroundColor: '#fff'}}>
      <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
    </View>
  );
  return (
    <DrawerLayoutAndroid
      drawerWidth={300}
      ref={(_drawer) => this.drawer = _drawer}
      drawerPosition={DrawerLayoutAndroid.positions.Left}
      renderNavigationView={() => navigationView}>
      <View style={{flex: 1, alignItems: 'center'}}>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
        <TouchableHighlight onPress={this.openDrawer}>
          <Text>{'Open Drawer'}</Text>
        </TouchableHighlight>
      </View>
    </DrawerLayoutAndroid>
  );
}

Upvotes: 0

Fadils
Fadils

Reputation: 1526

Just want to add another solution, especially when Navigator is used to render the scene.

If this is the case, then the above solutions won't work as it doesn't have access to ref specified in the DrawerLayoutAndroid, and it will in fact return

"undefined is not an object (evaluating 'this.refs['DRAWER_REF']')"

or something like that.

Solution:

Create our own Toolbar so that we can pass our rendering component to it.

MyToolbar.js

... import stuff ...

module.exports = React.createClass({
  render: function() {
    return (
      <ToolbarAndroid
        title={this.props.title}
        navIcon = {{uri: "ic_menu_white_24dp", isStatic: true}}
        style = {styles.toolbar}
        titleColor='#FFFFFF'
        onIconClicked={this._onIconClicked}/>
    );
  },

  _onIconClicked: function(){
    this.props.sidebarRef.refs['DRAWER'].openDrawer();
    // sidebarRef is the rendering component we're passing
  }
});

OpenDrawerFromToolbar.js

...
module.exports = React.createClass({
  render: function() {
    var navigationView = (
      <View style={{flex: 1, backgroundColor: '#fff'}}>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>In the Drawer!</Text>
      </View>
    );

    return (
      <View style={styles.container}>
        <DrawerLayoutAndroid drawerWidth = {300}
                         drawerPosition = {DrawerLayoutAndroid.positions.Left}
                         renderNavigationView = {() => navigationView}
                         ref={'DRAWER'}>
        <MyToolbar style={styles.toolbar}
                   title={'My Awesome App'}
                   navigator={this.props.navigator}
                   sidebarRef={this}/> // pass the component to MyToolbar
        <View style = {{flex: 1, alignItems: 'center'}}>
          <Text style = {{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
          <Text style = {{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
        </View>
      </DrawerLayoutAndroid>
    </View>
  );
  },

  _setDrawer: function() {
    this.refs['DRAWER'].openDrawer();
  }
});

Then our Navigator component with its renderingScene function will work:

module.exports = React.createClass({
  render: function() {
    return (
      <Navigator
        style = {styles.container}
        initialRoute = {{ name: 'openDrawerFromToolbar', index: 0 }}
        renderScene = {this.navigatorRenderScene}
        configureScene={ () => { return Navigator.SceneConfigs.PushFromRight; }}/>
  );
},

navigatorRenderScene: function(route, navigator) {
  _navigator = navigator;
      return (
          <OpenDrawerFromToolbar
            route={route}
            navigator={navigator}
            data={route.data}/>
      );
  }
});

Upvotes: 2

Tiago Gouv&#234;a
Tiago Gouv&#234;a

Reputation: 16780

Using the ReactNative sample, you can do like that:

var DrawerTest = React.createClass({
  openDrawer:function() {
    this.refs['DRAWER'].openDrawer()
  },
  render: function() {
    var navigationView = (
        <View style={{flex: 1, backgroundColor: '#fff'}}>
          <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
        </View>
    );
    return (
          <DrawerLayoutAndroid
              drawerWidth={300}
              ref={'DRAWER'}
              drawerPosition={DrawerLayoutAndroid.positions.Left}
              renderNavigationView={() => navigationView}>
            <View style={{flex: 1, alignItems: 'center'}}>
              <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
              <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
              <TouchableHighlight onPress={this.openDrawer}>
                <Text>{'Open Drawer'}</Text>
              </TouchableHighlight>
            </View>
          </DrawerLayoutAndroid>
    );

  }
});

Full File Gist

Upvotes: 8

kzzzf
kzzzf

Reputation: 2664

You should use "refs" as you've mentioned. To do so, for your drawer component have "ref" attribute set:

<DrawerLayoutAndroid
   ...
   ref={'DRAWER_REF'}
   ...
/>

Then in your component use this.refs to access it and call openDrawer or closeDrawer on that ref (e.g. you may want to have Touchable element that will trigger this call):

this.refs['DRAWER_REF'].openDrawer();

Upvotes: 32

Related Questions