Side-menu in navigation-bar in react-native - react-native

I am confused in the use of Navigator with react-native-side-menu. In my code I use navigator and NavigatorIOS for side-menu in navbar,but that code is not working in Android, because of the usage of NavigatorIOS. Now I am trying to convert my code to usage of Navigator in react-native.
Here is the my code with the usage of NavigatorIOS:
var Basic = React.createClass({
getInitialState() {
return {
navigationBarHidden: false
};
},
showSideBar () {
return this.refs.sidemenu.openMenu();
},
getNavigator(){
if (this.refs.nav){
return this.refs.nav.navigator;
}else{
return undefined;
}
},
LogOut(){
this.refs.sidemenu.closeMenu();
this.props.navigator.popToTop();
},
render(){
//alert("renderEmail:"+this.props.email);
return (
<SideMenu
ref="sidemenu"
touchToClose={true}
disableGestures={true}
menu={
<Menu
getNavigator={this.getNavigator}
showSideBar={this.showSideBar}
LogOut={this.LogOut}
/>
}
>
<NavigatorIOS
ref = "nav"
shouldUpdate={true}
style={styles.container}
barTintColor='#1A8A29'
tintColor='white'
titleTextColor='white'
initialRoute={{
component: BecomeMember,
title:'Become Member',
leftButtonIcon: require('image!menu1'),
onLeftButtonPress: ()=> {this.showSideBar(); },
rightButtonTitle: 'Log Out',
onRightButtonPress: ()=> {this.LogOut();},
passProps: {email:this.props.email,userId:this.props.userId},
}}
/>
</SideMenu>
);
}
});
when i wrote using navigatorIOS side-menu works correctly but using navigator in react-native-side-menu it not working, here is the code using Navigator
showSideBar () {
return this.refs.sidemenu.openMenu();
},
getNavigator(){
if (this.refs.nav){
return this.refs.nav.navigator;
}else{
return undefined;
}
},
LogOut(){
this.refs.sidemenu.closeMenu();
this.props.navigator.popToTop();
},
render(){
//alert("renderEmail:"+this.props.email);
var NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState){
if(index > 0){
return(
<TouchableHighlight style={{marginTop: 10}} onPress={() =>{
if(index > 0){
navigator.pop();
}
}}>
<Text>Back</Text>
</TouchableHighlight>
)
}else{
return (
<Text onPress={this.showSideBar()}>Main</Text>
)
}
},
RightButton(route, navigator, index, navState){
return null;
},
Title(route, navigator, index, navState){
return <Text style={styles.navBarTitle}>MaxWords</Text>
}
}
return (
<SideMenu ref="sidemenu" touchToClose={true} disableGestures={true} menu={<Menu getNavigator={this.getNavigator} showSideBar={this.showSideBar} LogOut={this.LogOut}/>}>
<Navigator
ref="nav"
shouldUpdate={true}
style={{flex:1}}
initialRoute={{name:'My Profile',component:MyProfile,leftButtonIcon: require('image!menu1'),
onLeftButtonPress: ()=> {this.showSideBar()},index:0}}
renderScene={(route, navigator) => {
if(route.component){
return React.createElement(route.component, {...this.props, ...route.passProps, navigator, route});
}
}}
navigationBar = {<Navigator.NavigationBar routeMapper={NavigationBarRouteMapper} style={styles.navBar}/>}/>
</SideMenu>
);
}
when i calling the function this.showSideBar(), it throws an error as shown in the image below
Can any one give me suggestions on how to solve this and how to use Navigator with side-menu in react-native ? Any help much appreciated.

Either
1) Add it via passProps to the component. e.g.
initialRoute={{
component: YourComponent,
passProps: {
onLeftButtonPress: this.showSideBa,
},
(..other stuff here)
}}
or
2) Add it to the renderScene as a property. e.g.
renderScene: function(route, navigator) {
var Component = route.component;
var navBar = route.navigationBar;
return (
<View style={styles.navigator}>
<Component
{...route.passProps}
navigator={navigator}
route={route}
onLeftButtonPress={this.showSideBar}/>
</View>
);
},
and update your renderScene() in the Navigator to point to the function instead.
initialRoute={{
component: YourComponent,
(..other stuff here),
renderScene={this.renderScene}
}}
Using method 2 will pass it down to every scene that get rendered through the navigator.

Related

How to relate react native ToolbarAndroid with Navigator

I would like to know a way to relate ToolbarAndroid with the Navigator component. My intention is always to show the route.title in a ToolbarAndroid child, such as a Text component. This way, if a use the BackAndroid component, my title is always up to date! I don't want to use Navigator.NavigationBar because I would miss the overflow menu built in on the ToolbarAndroid.
Appreciate any help.
Here is my code:
//... some code before
render() {
return(
<DrawerLayoutAndroid
drawerWidth={300}
ref={(drawerElement) => { this.DRAWER = drawerElement; }}
drawerPosition={DrawerLayoutAndroid.positions.left}
onDrawerOpen={this.setDrawerState}
onDrawerClose={this.setDrawerState}
renderNavigationView={() => <DrawerMenu navigate={this.navigateTo} />}
>
<Icon.ToolbarAndroid
titleColor='#fff'
navIconName='md-menu'
onIconClicked={this.toggleDrawer}
actions={toolbarActions}
onActionSelected={this._onActionSelected}
style={styles.appBar}
overflowIconName="md-more"
>
<View>
<TouchableOpacity
onPress={this.navigateTo.bind(this, 0)}
style={styles.appBarLogo}
>
<Icon name="md-boat" size={30} color="#fff" />
<Text
style={styles.appBarTitle}
numberOfLines={1}
>
{this.state.title}
</Text>
</TouchableOpacity>
</View>
</Icon.ToolbarAndroid>
<Navigator
initialRoute={routes[0]}
renderScene={(route, navigator) => {
switch (route.index) {
case 0:
return <Home />
case 1:
return <Lindau />;
case 2:
return <About />;
case 3:
return <Credits />;
default:
return <Home />;
}
}}
configureScene={(route, routeStack) =>
Navigator.SceneConfigs.FloatFromRight
}
ref={(nav) => { this._navigator = nav; }}
/>
</DrawerLayoutAndroid>
);
}
So, please, help me if anyone has a better solution for this. After several attempts, I figured out one possible solution.
I created a state for my component called 'routes', then, I've set up my Toolbar title with this state. Basically, this state is a stack of my routes. When I change my scene, I push this route in my state, when I back from BackAndroid component, I pop out the route from the state, and everything works fine.
Here the code fixed:
class App extends Component {
constructor(props) {
super(props);
this.state = {
routes: [0], // Here the state to fix the problem...
drawerClosed: true,
}
this.toggleDrawer = this.toggleDrawer.bind(this);
this._onActionSelected = this._onActionSelected.bind(this);
this.navigateTo = this.navigateTo.bind(this);
this.setDrawerState = this.setDrawerState.bind(this);
this.handlesBackButton = this.handlesBackButton.bind(this);
}
navigateTo(idx) {
this.setState({
routes: [ ...this.state.routes, idx]
});
this.DRAWER.closeDrawer();
if (idx === 0) {
this._navigator.resetTo(routes[0]);
this.setState({
routes: [0]
});
} else {
this._navigator.push(routes[idx]);
}
}
handlesBackButton() {
if (this._navigator && this._navigator.getCurrentRoutes().length > 1) {
try {
this._navigator.jumpBack();
const _routes = this.state.routes.slice();
_routes.pop();
this.setState({
routes: _routes
});
} catch(e) {}
return true;
}
return false;
}
render() {
return(
<DrawerLayoutAndroid
drawerWidth={300}
ref={(drawerElement) => { this.DRAWER = drawerElement; }}
drawerPosition={DrawerLayoutAndroid.positions.left}
onDrawerOpen={this.setDrawerState}
onDrawerClose={this.setDrawerState}
renderNavigationView={() => <DrawerMenu navigate={this.navigateTo} />}
>
<Icon.ToolbarAndroid
titleColor='#fff'
navIconName='md-menu'
onIconClicked={this.toggleDrawer}
actions={toolbarActions}
onActionSelected={this._onActionSelected}
style={styles.appBar}
overflowIconName="md-more"
>
<View style={styles.appBarLogo}> // I have to fix this component view...
<TouchableOpacity
onPress={this.navigateTo.bind(this, 0)}
>
<Icon name="md-boat" size={30} color="#fff" />
</TouchableOpacity>
<Text
style={styles.appBarTitle}
numberOfLines={1}
>
{routes[this.state.routes[this.state.routes.length - 1]].title}
</Text>
</View>
</Icon.ToolbarAndroid>
<Navigator
initialRoute={routes[0]}
renderScene={(route, navigator) => {
switch (route.index) {
case 0:
return <Home />;
case 1:
return <Lindau />;
case 2:
return <About />;
case 3:
return <Credits />;
default:
return <Home />;
}
}}
configureScene={(route, routeStack) =>
Navigator.SceneConfigs.FloatFromRight
}
ref={(nav) => { this._navigator = nav; }}
/>
</DrawerLayoutAndroid>
);
}
}

How to access to a function in a specific js file from navigation Bar in React Native?

I'm trying to access to a function in a specific js(chat.js in my local) file from the nagivation Bar in React Native.
Naviagation Bar is stated in index.ios.js and the code is given below.
render() {
....
<Navigator
initialRoute={{ title: 'Log In Page', index: 0, component: FirstPage }}
configureScene={() => {
return Navigator.SceneConfigs.FloatFromRight;
}}
navigationBar={
<Navigator.NavigationBar
routeMapper={{
LeftButton: (route, navigator, index, navState) =>
{
if (route.index === 0) {
return null;
} else {
return (
<TouchableHighlight onPress={() => navigator.pop()}>
<Text style={styles.route_title}> Back </Text>
</TouchableHighlight>
);
}
},
RightButton: (route, navigator, index, navState) =>
{
if (route.index === 10000){
return (<Text>Done</Text>);
}else{
return null;
}
},
Title: (route, navigator, index, navState) =>
{ return (<Text style={styles.route_title}> {route.title} </Text>); },
}}
style={{backgroundColor: '#28b496'}} />
}
...
When I click 'back' in the page(chat.js), I want to execute a specific function that is stated in chat.js file, such as pusher.unsubscribe('test_channel');.
How would I be able to access an internal function from the top in React-native?
I'm looking forward to seeing any opinion on this matter!
Best
export this function
then import it in your index file
In order to achieve that you can use 'navigator' parameter. You can access component's functions through this parameter. You can access it by using structure below
First write a method in Navigator component
<Navigator initialRoute = {{name:'home'}}
renderScene = {this.renderScene.bind(this)}
navigationBar = {<Navigator.NavigationBar routeMapper={NavigationBarRouteMapper} style={styles.navBar}/>}
callerFunction= {() => this.yourFunctionName()} // this is what you should add
/>
then assign this method the function you want to call
then you can access yourFunction through this callBack function(callerFunction).
{navigator.props.callerFunction()}
Definetely you can send parameters as well.

how to show navigation bar using navigator component in react-native

Hi every one I am trying to use navigator component in place of navigatorIOS, but what the problem navigator is not showing in view, below is my code for navigator and navigatorIOS
NavigatorIOS:
<NavigatorIOS
style={styles.navigator}
barTintColor='#37475e'
titleTextColor='white'
initialRoute={{
title:' Words',
component:Main
}}/>
using navigatorIOS I can view the navbar but using using navigator Component I am facing problem I want to use navigator component instead of navigatorIOS
Navigator Component:
<Navigator
style={styles.navigator}
TintColor='#37475e'
titleTextColor='white'
initialRoute={{
title:'Words',
component:Main
}}
renderScene={(route, navigator) =>{
return <route.component navigator={navigator} {...route.passProps} />;
}}/>
Can any one give me suggestions for how to solve this any help much appreciated
Yes, you need to create a <Navigator.NavigationBar />, and pass it in as a prop to the Navigator:
class App extends React.Component {
render() {
return (
<Navigator
style={{flex:1}}
initialRoute={{name: 'Main', component: Main, index: 0}}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { ...this.props, ...route.passProps, navigator, route } );
}
}}
navigationBar={ <Navigator.NavigationBar routeMapper={NavigationBarRouteMapper} /> }
/>
)
}
}
You then need to create a routeMapper object, which you pass in as a prop to the Navigator.NavigationBar:
var NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
if(index > 0) {
return (
<TouchableHighlight style={{marginTop: 10}} onPress={() => {
if (index > 0) {
navigator.pop();
}
}}>
<Text>Back</Text>
</TouchableHighlight>
)} else {
return null}
},
RightButton(route, navigator, index, navState) {
return null;
},
Title(route, navigator, index, navState) {
return <Text>Hello From My App!</Text>
}
};
There is a great example in the UI Explorer in their GitHub, check it out here.
App.js
<Navigator
ref={(ref) => this._navigator = ref}
configureScene={(route) => Navigator.SceneConfigs.FloatFromLeft}
initialRoute={{
id: 'Main',
title: 'Words'
}}
renderScene={(route, navigator) => this._renderScene(route, navigator)}
navigationBar={
<Navigator.NavigationBar
style={styles.navBar}
routeMapper={NavigationBarRouteMapper} />
}
/>
This code for left, right and title on navigationBar in react-native
const NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
switch (route.id) {
case 'Page1':
case 'Page2':
case 'Page3':
return (
<TouchableOpacity
style={styles.navBarLeftButton}
onPress={() => {_emitter.emit('openMenu')}}>
<Icon name='menu' size={25} color={'white'} />
</TouchableOpacity>
)
default:
return null
}
},
RightButton(route, navigator, index, navState) {
switch (route.id) {
case 'Page1':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'map'} size={25} color={'white'} />
</TouchableOpacity>
)
case 'Page2':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'map'} size={25} color={'white'} />
</TouchableOpacity>
)
case 'Page3':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'tab'} size={25} color={'white'} />
</TouchableOpacity>
)
default:
return null
}
},
Title(route, navigator, index, navState) {
return (
<Text style={[styles.navBarText, styles.navBarTitleText]}>
{route.title}
</Text>
)
}
}
route.onPress(): method to call right button click.
route.title: set title of page.
For reference, use following link: Navigator

Pass value between component in React Native Navigator

How can I pass data from sceneA to sceneB with Navigator in React Native?
I'm using this to go to sceneB:
this.props.navigator.push({
id: "MainPage",
name: 'mainPage'
});
You need to set up the passProps property on the navigator. There are a few recent examples on stack overflow, specifically here and here.
<Navigator
initialRoute={{name: 'Main', component: Main, index: 0}}
renderScene={(route, navigator) => {
return React.createElement(<YourComponent />, { ...this.props, ...route.passProps, navigator, route } );
}} />
or
<Navigator
initialRoute={{name: 'Main', component: Main, index: 0}}
renderScene={(route, navigator) => {
<route.component {...route.passProps} navigator={navigator} route={route} />
}
}
/>
If you are looking for the most basic of setups just to understand the functionality, I have set up a project here that you can reference, and pasted the code below.
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
Navigator,
Image,
TouchableHighlight, TouchableOpacity
} = React;
class Two extends React.Component {
render(){
return(
<View style={{marginTop:100}}>
<Text style={{fontSize:20}}>Hello From second component</Text>
<Text>id: {this.props.id}</Text>
<Text>name: {this.props.name}</Text>
<Text>name: {this.props.myVar}</Text>
</View>
)
}
}
class Main extends React.Component {
gotoNext(myVar) {
this.props.navigator.push({
component: Two,
passProps: {
id: 'page_user_infos',
name: 'page_user_infos',
myVar: myVar,
}
})
}
render() {
return(
<View style={{flex: 4, flexDirection: 'column', marginTop:100}}>
<TouchableHighlight style={{ height:40, borderWidth:1, marginBottom:10, backgroundColor: '#ddd'}} name='Pole' onPress={ () => this.gotoNext('This is a property that is being passed') }>
<Text style={{textAlign:'center'}}>Go to next page</Text>
</TouchableHighlight>
</View>
)
}
}
class App extends React.Component {
render() {
return (
<Navigator
style={{flex:1}}
initialRoute={{name: 'Main', component: Main, index: 0}}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { ...this.props, ...route.passProps, navigator, route } );
}
}}
navigationBar={
<Navigator.NavigationBar routeMapper={NavigationBarRouteMapper} />
} />
);
}
}
var NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
if(index > 0) {
return (
<TouchableHighlight style={{marginTop: 10}} onPress={() => {
if (index > 0) {
navigator.pop();
}
}}>
<Text>Back</Text>
</TouchableHighlight>
)} else {
return null}
},
RightButton(route, navigator, index, navState) {
return null;
},
Title(route, navigator, index, navState) {
return null
}
};
var styles = StyleSheet.create({
});
AppRegistry.registerComponent('App', () => App);
I would set up your navigator as this example. Essentially, put the navigator in your index scene and have all the necessary components imported there. Then, define a renderScene() function to handle all the routes based on a name (or id, like you did). I would not use the component object as the thing itself that is passed from the call to the navigator push method because if you do that you will have to import the component in that specific view. I used to do that and ran into many problems, so I am just warning you if you run into any issues, consider this approach.
renderScene(route, navigator) {
if(route.name == 'root') {
return <Root navigator={navigator} />
}
if(route.name == 'register') {
return <Register navigator={navigator} />
}
if(route.name == 'login') {
return <Login navigator={navigator} />
}
if(route.name == 'home') {
return <Home navigator={navigator} {...route.passProps} />
}
if(route.name == 'update') {
return <Update navigator={navigator} {...route.passProps} />
}
}
Sometimes the pass prop doesn't work (at least for me) So what I do is I pass it in the route object itself
nav.push({
id: 'MainPage',
name: 'LALA',
token: tok
});
so to access it in the next scene I use
var token = this.props.navigator.navigationContext.currentRoute.token;
although kind of a complicated "access" but it is fool proof pass props might work or might not also in this way you can pass the properties in the route object itself thus saving you from the hassle of sending it in a different way.
This might not be the right way but I find it a tad bit more convenient.
If you are using react-native-navigation, simply add passProps to your params object, according to documentation.
eg.:
this.props.navigator.push({
screen: 'example.Screen',
title: 'Screen Title',
passProps: {
id: 'MainPage',
name: 'mainPage'
}
})
You can also pass parameters to sceneA to sceneB using following way. Assume that _handlePressOnClick() is written on some button click in SceneA screen.
_handlePressOnClick(){ //this can be anything
this.props.navigator.push({
name: "sceneB", //this is the name which you have defined in _renderScene
otherData: {
dataA: "data1"
}
})
}
Then defined data in your _renderScene where you have implemented your navigator like this way
_renderScene(route, navigator) {
switch(route.name) {
case "sceneA":
return (
<sceneA navigator={navigator} />
);
break;
case "sceneB":
return (
<sceneB navigator={navigator} otherData={route.otherData}/>
);
break;
}
Don't forget to import your views files like this
import sceneA from './sceneA';
import sceneB from './sceneB';
Now in sceneB file you can access your otherData following way
var {dataA} = this.props.otherData;
or
constructor(props){
super(props);
this.state={
otherData: this.props.otherData
}
}
then in your render() method you can access otherData using state.
<Text>{this.state.otherData.dataA}</Text>
You can also use to maintain global level state using redux which is accessible through action and props automatically.
1.While passing the data from scene A to scene B, you must specify in the navigator tag that you are also passing the data with route.
ex.
if(route.name == 'home') {
return <Home navigator={navigator} data={route.data} />
}
send data from scene A
ex.this.props.navigator.push({name:'sceneB',data:{name:this.state.name},});
in scene B access data like this
ex. this.props.data.name
and you get the data from scene A to scene B

Navigator.SceneConfigs can't find variable: Navigator

I want to configure various scene animations with Navigator.SceneConfigs ("FloatFromRight" and "FloatFromLeft").
Within the Scene - if I call the scene with a configured animation I receive the error message "Can't find variable: Navigator" (although I am of the opinion that I copied the code above from the React-Native examples).
_onPressBar1: function(){
debugger;
this.props.nav.push({
id: 'Login',
sceneConfig: Navigator.SceneConfigs.FloatFromLeft,
});
},
I created the following Navigator:
render: function() {
return (
<Navigator
style={styles.container}
renderScene ={this.renderScene}
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}}
initialRoute={{
id: 'Login',
index: 0,
}} />
);
}
with the following renderScene:
renderScene: function(route, navigator){
if ('Login' === route.id) {
return (
<View style={{flex: 1}}>
<TopBar nav={navigator} displBackIcon={false} />
<Login
name={route.name}
navigator={navigator} />
<BottomBar nav={navigator} currentPage={route.id} />
</View>
);
} else if ('Test' === route.id) {
return (
<View style={{flex: 1}}>
<TopBar nav={navigator} displBackIcon={false} />
<Test
navigator={navigator} />
<BottomBar nav={navigator} currentPage={route.id} />
</View>
);
}
},
The _onPressBar1 function was included in a different file where I forgot to include the Navigator in the React definition:
var {
Image,
Navigator,
StyleSheet,
Text,
TouchableOpacity,
View,
} = React;