Saturday, October 7, 2017

A simple Custom Drawer Navigation

In the previous sample we built a simple application that has DrawerNavigation. Lets build more on that. In this sample we build a similar DrawerNavigatoer that has a custom list, formatted by our choice

To start, lets have a simple DrawerNavigator, like the following

export const MainNavigator = DrawerNavigator({
  Home: {
    screen: StackNavigator({
      Home: {
        screen: Home,
        navigationOptions:{
          title:'Home',
        }
      },
    })
  },
  Search: {
    screen: StackNavigator({
      Search: {
        screen: Search,
        navigationOptions:{
          title:'Search',
        }
      },
      Result: {
        screen: Result,
        navigationOptions:{
          title:'Result',
        }
      }
    })
  },
  Saved: {
    screen: StackNavigator({
      SavedStack: {
        screen: SavedWord,
        navigationOptions:{
          title:'Saved Word',
        }
      }
    })
  },
  About: {
    screen: StackNavigator({
      AboutStack: {
        screen: About,
        navigationOptions:{
          title:'About',
        }
      }
    })
  },
},{
  contentComponent: props => (<Drawer navigation={props.navigation} drawerProps={{...props}} />),
});



This code is very familiar to us, mostly. What's new though is 'contentComponent'. We have introduced a new component 'Drawer'. That's what is displayed when drawer, opens. What gets displayed in Drawer is left to us. When a user taps on an item in drawer, we need to navigate to respective view. We need navigator object for that. We pass navigator as an attribute to Drawer. We will talk about drawerProps a little later. We have enough to look into Drawer code

drawer.js

export default class Drawer extends Component {
  render() {
    return (
      <ScrollView style={{flex: 1, marginTop:50, marginLeft:10, marginRight: 20,}}>
        <TouchableHighlight style={styles.lineItem} onPress={() => this.props.navigation.navigate('Home')}>
          <Text style={styles.lineItemText}>Home</Text>
        </TouchableHighlight>
        <TouchableHighlight style={styles.lineItem} onPress={() => this.props.navigation.navigate('Search')}>
          <Text style={styles.lineItemText}>Search</Text>
        </TouchableHighlight>
        <TouchableHighlight style={styles.lineItem} onPress={() => this.props.navigation.navigate('Saved')} >
          <Text style={styles.lineItemText}>Saved</Text>
        </TouchableHighlight>
        <TouchableHighlight style={styles.lineItem} onPress={() => this.props.navigation.navigate('About')} >
          <Text style={styles.lineItemText}>About</Text>
        </TouchableHighlight>
        <TouchableHighlight style={styles.lineItem} onPress={() => this.props.navigation.navigate('PreAuthStack')} >
          <Text style={styles.lineItemText}>LogOff</Text>
        </TouchableHighlight>
      </ScrollView>
    );
  }
}

const styles = StyleSheet.create({
  lineItem: {
    borderBottomColor: 'lightgray',
    borderWidth: 1,
    borderTopWidth:0,
    borderLeftWidth:0,
    borderRightWidth:0,
  },
  lineItemText: {
    fontSize: 20,
    fontWeight: '200',
    textAlign: 'center',
    margin: 10,
  },
});

As you see, the code is very simple. Its a basic component that have a scrollview with a list of controls. Simple, right?. All that happens here is we have a bunch of TouchableHighlight controls, when tapped on it, we navigate to respective views.

Our next step is to make this list more dynamic. That's for the next BLOG. If you are interested to try the entire sample, feel free to visit this code here

Thursday, October 5, 2017

More Navigation and Drawer Navigation

With a simple navigation flow using StackNavigator behind us, our next step is to start playing with more advanced navigation. Honestly, from the little experience I got in the industry, "next advanced" level never stops. Needs are insatiable. LoL
From a real world perspective, we have 2 parts for an application, especially on mobile
  1. Pre-authentication flows
  2. Post-authentication flows
We may have modules that need to work before authentication, things like login form, Forgot password, register/signup, contact us, privacy policies, locate us etc. Of course we all know the post authentication flows. Complexity on each side is different. There may be cases where flow is staggered (like MFA flows) while others may be continuous. We can't say which one is more complicated than the other.

With that in mind, lets start to put together an simple flow. This sample will mix a lot of StackNavigation, in addition we will also see DrawerNavigation. One of the most used navigation in mobile world. In other words called "Hamburger menu" or Side navigation.


Here's a high-level view of what we will see

Stack Navigator - App
Stack Stack Navigator - Login
Login form
Forgot Password
Signup
Stack Navigator - Others
Contact us
Privacy policy
Dashboard Navigation
Stack Navigator - Home
Home
Stack Navigator - Module 1
Sub module 1
Sub module 2
Stack Navigator - Module 2
Sub module 1
Sub module 2

At one glance this flow may look simple, but it can be a handful, if we don't understand the concept of navigation from React native context. And trust me, if you go over web, you will see tons of questions around navigation in React native.

As in previous examples, none of the leaf pages are complete. They are place holders pages and contain nothing more than simple text to help us identify the page and a title to show in navigation bar. Our first step is to set the app up. Start by creating a new react-native application and here is the content for our first file

index.js

import { AppRegistry } from 'react-native';
import { StackNavigator } from 'react-navigation';
import React from 'react';
import App from './App';
import LoginNav from './src/screens/preauthentication/authentication/login';
import ForgotPassword from './src/screens/preauthentication/authentication/forgot_password';
import Signup from './src/screens/preauthentication/authentication/signup';
import Home from './src/screens/postauthentication/home';
import { PostAuthDrawer } from "./src/screens/postauthentication/home_drawer";
import ContactUs from "./src/screens/preauthentication/others/contactus";
import PrivacyPolicy from "./src/screens/preauthentication/others/privacy_policy";

const LogonStack = StackNavigator({
  Login: { screen: LoginNav },
  ForgotPassword: { screen: ForgotPassword },
  Signup: { screen: Signup },
}, {
  headerMode: 'screen',
});

const OthersStack = StackNavigator({
  ContactUs: { screen: ContactUs},
  PrivacyPolicy: { screen: PrivacyPolicy},
},{
  headerMode: 'screen',
});

const AppStack = StackNavigator({
  Login: { screen: ({ navigation }) => <LogonStack screenProps={{ rootNavigation: navigation, headerMode: 'none', }} /> },
  Others: { screen: ({ navigation }) => <OthersStack screenProps={{ rootNavigation: navigation, headerMode: 'none', }} /> },
  Home: { screen: PostAuthDrawer }
}, {
  headerMode: 'none'
});

AppRegistry.registerComponent('DrawerNavigation', () => AppStack);

Notice in the above code where in 'Login' and 'Others' item in 'AppStack' have a in-line function that passes the current navigation object as a parameter to 'LogonStack' and 'OthersStack'. We do that, because every stack navigator, as you'd expect has a navigation of its own. Imagine this to be a parent-child navigation. Parent can access the child navigation, because they make it happen. But child has no clue about the parent and hence cannot return back to parent navigation, unless there is a reference to parent some where. The way we pass reference of parent to child is through screenProps. If you are interested and want to know more on the potential of screenProps, please stay tuned. We will have a separate episode on that. Now, why is that we don't have a similar parameter excahnge for 'PostAuthDrawer'. Reason is simple, we don't have anything that will want to come back to 'Login' stack. If we have a log-off screen that's pare of 'Login' stack, yes we will do the same for 'Home' too. Rest of the code is pretty simple

login.js

import React from 'react';
import {
  View,
  Text,
  Button,
  StyleSheet
} from 'react-native';
import { NavigationActions } from 'react-navigation';
import Footer from "../../../components/footer";

export default class LoginNav extends React.Component {
  static navigationOptions = {
    title: 'Login',
  };
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.bodyView}>
          <Text style={styles.text}>PreAuthentication - Login</Text>
          <View>
            <Button title='Login' onPress={ () => this.onLogin() }/>
            <Button title='Cancel' onPress={ () => this.onCancel() } />
            <View>
              <Button title='Forgot Password' onPress={ () => this.onForgotPassword() } />
              <Button title='Signup' onPress={ () => this.onSignup() } />
            </View>
          </View>
        </View>
        <View style={styles.footerView}>
          <Footer screenProps={{rootNavigation: this.props.screenProps.rootNavigation}}/>
        </View>
      </View>);
  }

  onLogin() {
    // go back to main, with additional parameters and NavigationActions
    this.props.screenProps.rootNavigation.dispatch(NavigationActions.reset({
      index: 0,
      actions: [
        NavigationActions.navigate({ routeName: 'Home' })
      ]
    }));

  }

  onCancel() {
    // go back to main with additional parameters and NavigationActions
    this.props.screenProps.rootNavigation.navigate('Main');
  }

  onForgotPassword() {
    console.log('ForgotPassword button pressed');
    this.props.navigation.navigate('ForgotPassword');
  }

  onSignup() {
    console.log('signup button pressed');
    this.props.navigation.navigate('Signup');
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'center',
  },
  bodyView: {
    flex: 1,
    justifyContent: 'center',
    margin: 20,
  },
  footerView: {
    borderColor: 'black',
    borderWidth: 1,
    height: 60,
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});


Here we made a few changes from our previous sample, first off, we introduced a new 'Footer' component. All that a footer offers us is a way to show 'Contact us' and 'Privacy policy' at the bottom of the page. Notice how the navigation is done from within the component. To navigate between 'Forgot password' and 'Signup', we use the regular navigation object. We use rootNavigator that was passed in screenParams to navigate back to parent view/screen. 

Now that 'Footer' is a component within 'Login', navigation boundries are also defined by 'Login' (i.e. 'Forgot Password' and 'Signup'). Hence we are compelled to pass 'rootNavigator' as a parameter to jump outside the current stack. If you remember, both 'Contact Us' and 'Privacy Policy' are defined as a seperate stack and are not part of 'Login' navigator. The only way we can reach 'Others' stack navigator from within 'Login' navigator is to reach the parent navigator, from there communicate with 'Other' navigator. Hope that make sense to you.

I loved writing 'Footer' component. Although, I'd have liked it even more, if I can have in-line style for 'Footer'. It would have been a lot more easier to just add the component and see the result. As opposed to contain Footer in a view and style to view to show up in the bottom.




Footer.js

import React from 'react';
import {
  StyleSheet,
  View,
  Text,
  TouchableOpacity,
  Alert,
} from 'react-native';
import { NavigationActions } from 'react-navigation';

export default class Footer extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <View style={styles.buttonContainer}>
        <TouchableOpacity style={styles.buttons} onPress={() => this.onContactUs()}>
          <Text style={styles.text}>Contact Us</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.buttons} onPress={() => this.onPrivacyPolicy()}>
          <Text style={styles.text}>Privacy Policy</Text>
        </TouchableOpacity>
      </View>);
  }

  onContactUs() {
    console.log('Tapped on Contact Us');
    this.props.screenProps.rootNavigation.dispatch(NavigationActions.navigate({
      routeName: 'Others',
      params: {},
      action: NavigationActions.navigate({ routeName: 'ContactUs'})
    }));
  }

  onPrivacyPolicy() {
    console.log('Tapped on Privacy Policy');
    this.props.screenProps.rootNavigation.dispatch(NavigationActions.navigate({
      routeName: 'Others',
      params: {},
      action: NavigationActions.navigate({ routeName: 'PrivacyPolicy'})
    }));
  }
}

const styles = StyleSheet.create({
  buttonContainer: {
    flex: 1,
    alignItems:'stretch',
    flexDirection: 'row',
    borderWidth: 0,
  },
  buttons: {
    flex:0.5,
    borderWidth: 0,
    borderColor: 'black',
    borderRadius: 5,
    alignSelf: 'stretch',
    marginLeft: 20,
    marginRight:20,
  },
  text: {
    fontSize: 15,
    textAlign: 'center',
    alignSelf:'center',
    textAlignVertical:'center',
    padding:10,
  },
});


Footer is no different from any of the component we built in the past. The only addition here will be the code to navigate. We access the navigator from screenProps and use it. rest of the code is no different from what you have used in the past



forgot_password.js

import React from 'react';
import {
  View,
  Text,
  Button,
  StyleSheet,
} from 'react-native';

export default class ForgotPassword extends React.Component {
  static navigationOptions = {
    title: 'Forgot Password',
  };
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>PreAuthentication - Forgot Password!!</Text>
        <View>
          <Button title='Submit' onPress={() => this.onSubmit()}/>
          <Button title='Cancel' onPress={() => this.onCancel()}/>
        </View>
      </View>);
  }

  onSubmit() {
    console.log('ForgotPassword - submit button pressed');
  }

  onCancel() {
    console.log('ForgotPassword - submit button pressed');
    this.props.navigation.goBack();
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});


I don't think this code has changed in anyway from our previous examples. Container changes for 'Login' does not affect any navigation in this module. This is the beginning of loosely-coupled navigation.


signup.js

import React from 'react';
import {
  View,
  Text,
  Button,
  StyleSheet
} from 'react-native';

export default class Signup extends React.Component {
  static navigationOptions = {
    title: 'Signup',
  };
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>PreAuthentication - Signup</Text>
        <View>
          <Button title='Submit' onPress={() => this.onSubmit()}/>
          <Button title='Cancel' onPress={() => this.onCancel()}/>
        </View>
      </View>);
  }

  onSubmit() {
    console.log('Signup - submit button pressed');
  }

  onCancel() {
    console.log('Signup - submit button pressed');
    this.props.navigation.goBack();
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});


Not much has changed on this code from our previous samples. 


home.js

import React from 'react';
import {
  StyleSheet,
  View,
  Text,
  Button,
  TouchableOpacity,
  Image,
} from 'react-native';

export default class Home extends React.Component {
  static navigationOptions = {
    title: 'Home',
  };

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>Home - Post Login</Text>
      </View>);
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});


This is the landing page post login. If take a step back look into home_drawer.js, we have contained home.js in a seperate stacknavigator in stead of just referencing it as a screen. You can take it as a placeholder to add more in the coming days as well as to cover issues with DrawerNavigator. As I alleged earlier, the most complicated piece in React Native is Navigation. With nested navigators, complication adds up. I'd encourage you to take this code, play around with navigation and experience it for yourself.


submodule_11.js

import React from 'react';
import {
  StyleSheet,
  View,
  Text,
  Button,
} from 'react-native';

export default class SubModule11 extends React.Component {
  static navigationOptions = {
    title: 'Sub Module 11',
  };
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>Module 1 - Submodule 1</Text>
        <View>
          <Button title='Next' onPress={() => this.onNext() }/>
          <Button title='Home' onPress={() => this.onHome() }/>
        </View>
      </View>);
  }

  onNext() {
    console.log('SubModule11: onNext touched');
    this.props.navigation.navigate('SubModule2')
  }

  onHome() {
    console.log('SubModule11: onHome touched');
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

There is no change to this code from our previous examples. submodule_21 & submodule_22 are the same as submodule_11 & submodule_12


submodule_12.js

import React from 'react';
import {
  StyleSheet,
  View,
  Text,
  Button,
  Alert,
} from 'react-native';
import { NavigationActions } from 'react-navigation';

export default class SubModule12 extends React.Component {
  static navigationOptions = {
    title: 'Sub Module 12',
  };
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>Module 1 - Submodule 2</Text>
        <View>
          <Button title='Next' onPress={() => this.onNext() }/>
          <Button title='Home' onPress={() => this.onHome() }/>
        </View>
      </View>);
  }

  onNext() {
    Alert.alert('Yeah from navigation', "Sorry, can't navigate. Does not exist for the moment", [
        {text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
        {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
        {text: 'OK', onPress: () => console.log('OK Pressed')},
      ],
      { cancelable: true });
    console.log('SubModule12: onNext touched');
  }

  onHome() {
    console.dir(this.props);
    this.props.navigation.navigate('Home');
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});



home_drawer.js

import React from 'react';
import { StackNavigator, DrawerNavigator } from 'react-navigation';

import SubModule11 from './module_1/submodule_11';
import SubModule12 from './module_1/submodule_12'
import SubModule21 from './module_2/submodule_21';
import SubModule22 from './module_2/submodule_22'
import Home from './home';

const Module1Stack = StackNavigator({
  SubModule1: { screen: SubModule11 },
  SubModule2: { screen: SubModule12 }
}, {
  headerMode: 'screen'
});

const Module2Stack = StackNavigator({
  SubModule1: { screen: SubModule21 },
  SubModule2: { screen: SubModule22 }
}, {
  headerMode: 'screen'
});

const HomeStack = StackNavigator({
  Home: { screen: Home },
}, {
  headerMode: 'screen',
});

export const PostAuthDrawer = DrawerNavigator({
  Home: { screen: ({ navigation }) => <HomeStack screenProps={{ rootNavigation: navigation, headerMode: 'none', }} /> },
  Module1: {
    screen: Module1Stack,
  },
  Module2: {
    screen: Module2Stack,
  },
});

This code is very much open. Both 'Module1', 'Module2' & 'HomeStack' are simple 'StackNavigator'. All of this navigators are contained in 'DrawerNavigator'. The code for 'Home' is slightly different from the rest. This is one of the bug that I mentioned about React-Native Navigators (v 0.48). Try removing this code and play around to see why this code is there.

In subsequent posts we'll take a look at customization of 'DrawerNavigator'







Monday, October 2, 2017

Basic Navigation in React Native

Navigation is the one of the most important & complicated part of mobile application. This is one piece that we wish to focus more on this and following blogs. The more we understand navigation, better it is for the application.

From day-to-day development, there will always be additions and deletions to navigation and flow pattern's. If navigation is tightly coupled to application, we will have major re-writes for every change to navigation. This in-turn affect release cycle and over all application maintenance cost. For us to stay afloat with eternal changes that comes from BA and business, it is important for us to keep the navigation component out of rest of the application. Keep it as loosely coupled and treat it as seperate library/framework/component. This way, changes can easily be accomodated.

We will build a very basic navigation application now, as we move along, we will add additional functionalites and well as document some lessons learnt, errors and solutions.

Our index file carries nothing more than navigation definition and application level configurations. We want our startup application to kick off from stack navigator, this way we will be able to move forward and back, if/when needed.

index.ios.js/index.android.js
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import { StackNavigator } from 'react-navigation';

import Home from './src/screens/postauthentication/home';
import Login from './src/screens/preauthentication/authentication/login';
import ForgotPassword from './src/screens/preauthentication/authentication/forgot_password';
import Signup from './src/screens/preauthentication/authentication/signup';

const PreAuth = StackNavigator({
  Login: { screen: LoginNav },
  ForgotPassword: { screen: ForgotPassword },
  Signup: { screen: Signup },
}, {
  headerMode: 'none'
})

const AppStack = StackNavigator({
  Login: { screen: Login },
  ForgotPassword: { screen: ForgotPassword },
  Signup: { screen: Signup },
});

AppRegistry.registerComponent('MoreNavigation', () => AppStack);

We have not setup the first page/component/form to show up in this navigator. ReactNative and StackNavigator makes it easy for us. It's anybodies guess. Login will be the component that will be displayed by default.

Login component is the main thread that connects to other components like 'Forgot Password' and 'Signup' form. When the user taps on Login button, he'll be redirected to 'Home' component. From a real-world perspective, we can think of this to be login page/form. Upon validation, user should be able to login to the application. While others are options to establish non-authentication flows.

Login.js
/**
 * Sample React Native App - Login.js
 * https://github.com/facebook/react-native
 * @flow
 */
import React from 'react';
import {
  View,
  Text,
  Button,
  StyleSheet
} from 'react-native';
import { NavigationActions } from 'react-navigation';

export default class LoginNav extends React.Component {
  static navigationOptions = {
    title: 'Login',
  };
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>PreAuthentication - Login</Text>
        <View>
          <Button title='Login' onPress={ () => this.onLogin() }/>
          <Button title='Cancel' onPress={ () => this.onCancel() } />
          <View>
            <Button title='Forgot Password' onPress={ () => this.onForgotPassword() } />
            <Button title='Signup' onPress={ () => this.onSignup() } />
          </View>
        </View>
      </View>);
  }

  onLogin() {
    console.log('Login button pressed');
    // go back to main, with additional parameters and NavigationActions
    this.props.navigation.dispatch(NavigationActions.reset({
      index: 0,
      actions: [
        NavigationActions.navigate({ routeName: 'Home' })
      ]
    }));

  }

  onCancel() {
    console.log('Cancel button pressed');
    // go back to main with additional parameters and NavigationActions
    // this.props.navigation.navigate('Main');
  }

  onForgotPassword() {
    console.log('ForgotPassword button pressed');
    this.props.navigation.navigate('ForgotPassword');
  }

  onSignup() {
    console.log('signup button pressed');
    this.props.navigation.navigate('Signup');
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

Notice we have different method implementation for navigation. For us to navigate to 'Forgot Password' or 'Signup' we use props.navigation.navigate. While to go to 'Home', we use NavigationActions. Reason is simple. When we go to 'Home', user should not be able to be able to go back to logon screen unless user log's off. Even worse, post-login we don't want to see a back button in navigation bar for iOS and back button should not take the user to logon screen in Android. This requirement leads us to reset the navigation stack. This way we don't have any history to go back.

Rest of the forms are as simple as login

Signup.js
/**
 * Sample React Native App - Signup.js
 * https://github.com/facebook/react-native
 * @flow
 */
import React from 'react';
import {
  View,
  Text,
  Button,
  StyleSheet
} from 'react-native';

export default class Signup extends React.Component {
  static navigationOptions = {
    title: 'Signup',
  };
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>PreAuthentication - Signup</Text>
        <View>
          <Button title='Submit' onPress={() => this.onSubmit()}/>
          <Button title='Cancel' onPress={() => this.onCancel()}/>
        </View>
      </View>);
  }

  onSubmit() {
    console.log('Signup - submit button pressed');
  }

  onCancel() {
    console.log('Signup - submit button pressed');
    this.props.navigation.goBack();
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

Forgot_password.js
/**
 * Sample React Native App - ForgotPassword.js
 * https://github.com/facebook/react-native
 * @flow
 */
import React from 'react';
import {
  View,
  Text,
  Button,
  StyleSheet,
} from 'react-native';

export default class ForgotPassword extends React.Component {
  static navigationOptions = {
    title: 'Forgot Password',
  };
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>PreAuthentication - Forgot Password!!</Text>
        <View>
          <Button title='Submit' onPress={() => this.onSubmit()}/>
          <Button title='Cancel' onPress={() => this.onCancel()}/>
        </View>
      </View>);
  }

  onSubmit() {
    console.log('ForgotPassword - submit button pressed');
  }

  onCancel() {
    console.log('ForgotPassword - submit button pressed');
    this.props.navigation.goBack();
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

Notice, how we go back to previous screen on 'Cancel'. If we are two or more forms down in stack, and wish to go back to root, we can pass a key parameter to 'goBack()'. Check the documentation here for more


That's it for now. A multi-layered navigation application will be added soon




Monday, September 25, 2017

A simple list view implementation in React native

As I started on my React Native lessons, it was very difficult to stop by one place for all information. Especially to display a listview, load data from a remote service also format listview for a better presentation

Here I have a simple Listview that shows how to get started

  1. Create a Listview component
  2. Load data from a remote JSON service
  3. Format rows for data
  4. Setup a header (you can set up a footer in a similar fashion)
  5. Do some basic styles
  6. Show error, if remote service fails
A basic functional ListView can be created from here. What we are about to do is create a ListView that can do a service call. Implementation for this service is done in separate component. So is the error. With that said, people with mobile development background will know how complicated ListRows and TableRows can get. It's a better idea for us to separate header, footer and rows into their own components too. Our ListView component now has the following other component that works with it

  1. A Vanilla Listview
  2. Custom Header
  3. Custom Row
  4. Custom service component (Acts as a base class)
  5. Finally, a separate error component
This code can be done better in many ways. But for us to get started, this will be easy to follow and change if needed

index.ios.js/index.android.js


/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  ListView,
  View
} from 'react-native';
import ListHeader from './src/components/list_header';
import ListRow from './src/components/list_row';
import PageError from './src/components/page_error'
import CountriesService from './src/services/countries';

export default class SimpleListView extends CountriesService {

  constructor() {
    super();
    ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    var currentState = this.state;
    this.state = {
      countries: currentState,
      dataSource: ds.cloneWithRows(['row 1', 'row 2']),
      error: '',
      rowHeaderText: 'Countries and their codes',
    };
    console.dir(this.state);
  }

  componentDidMount() {
    this.loadJSONData();
  }

  loadJSONData() {
    fetch(this.state.countries.jsonURL, {method: "GET"})
      .then((response) => response.json())
      .then((responseData) => {
        console.log('Length: ' + responseData.RestResponse.result.length);
        let result = responseData.RestResponse.result;
        this.setState({
          dataSource: this.state.dataSource.cloneWithRows(result)
        });
      })
      .catch((error) => {
        console.log('ERROR');
        this.setState({countries: {error: error.message}})
      })
      .done(() => {
        this.setState({
          loadStatus: 'completed'
        });
      })
  }

  render() {
    console.log('Render invoked');
    if(this.state.error) {
      return (
        <PageError errorText={this.state.error}/>
      )
    } else {
      return (
        <View style={styles.container}>
          <Text>{ this.state.loadStatus }</Text>
          <ListView style={styles.listview}
                    dataSource={this.state.dataSource}
                    renderRow={(rowData, sectionID, rowID, highlightRow) => this.rowData(rowID, rowData)}
                    renderHeader={this.rowHeader.bind(this)}
          />
        </View>
      );
    }
  }

  rowData(rowID, rowData) {
    return (
      <ListRow index={rowID} name={rowData.name} alpha2_code={rowData.alpha2_code} alpha3_code={rowData.alpha3_code}/>);
  }

  rowHeader() {
    return (
      <ListHeader headerText={this.state.rowHeaderText} />
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
    marginTop: 30,
  },
  listview: {
    flex: 1,
    borderWidth:1,
    borderColor:'#000000',
    alignSelf:'stretch',
    margin:10,
  },
  errorHeader: {
    fontSize: 26,
    textAlign: 'left',
    fontWeight: '200',
    color:'red',
    margin: 10,
    marginTop:50,
  },
  errorText: {
    fontSize: 20,
    textAlign: 'left',
    fontWeight: '300',
    color:'black',
    margin: 10,
  },
});

AppRegistry.registerComponent('SimpleListView', () => SimpleListView);

From code maintenance perspective, I create a separate directory structure for services and components.

  • src/services for all service code
  • src/components for all components


src/services/countries.js

import React, { Component } from 'react';

export default class CountriesService extends Component {
  constructor() {
    super();
    countries = {
      jsonURL: 'http://services.groupkt.com/country/get/all',
      error: '',
    };
    this.state = countries;
  }

  loadJSONData() {
    fetch(this.state.jsonURL, {method: "GET"})
      .then((response) => response.json())
      .then((responseData) => {
        console.log('Length: ' + responseData.RestResponse.result.length);
        let result = responseData.RestResponse.result;
        this.setState({
          dataSource: this.state.dataSource.cloneWithRows(result)
        });
      })
      .catch((error) => {
        console.log('ERROR');
        console.dir(error);
        this.setState({error: error.message})
      })
      .done(() => {
        this.setState({
          loadStatus: 'completed'
        });
      })
  }
}

Here's out List Header

src/components/list_header.js
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class ListHeader extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <View style={styles.headerRow}>
        <Text style={styles.headerRowText}>{this.props.headerText}</Text>
      </View>);
  }
}

const styles = StyleSheet.create({
  headerRow: {
    flex: 1,
    backgroundColor: 'gray',
  },
  headerRowText: {
    fontSize: 25,
    textAlign: 'left',
    fontWeight: '300',
    color:'white',
    margin: 10,
  }
});

Each row is an instance of this class

src/components/list_row.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class ListRow extends Component {
  constructor(props) {
    super(props);
  }

  styleRow() {
    if(this.props.index %2 == 0) {
      return styles.evenContainer
    }
    return styles.oddContainer;
  }

  render() {
    return (
      <View style={this.styleRow()}>
        <Text style={styles.rowTitle}>{this.props.name}</Text>
        <Text style={styles.rowText}>{this.props.alpha2_code}</Text>
        <Text style={styles.rowText}>{this.props.alpha3_code}</Text>
      </View>);
  }
}

const styles = StyleSheet.create({
  evenContainer: {
    flex: 1,
    backgroundColor: 'white',
  },
  oddContainer: {
    flex: 1,
    backgroundColor: 'lightgray',
  },
  rowTitle: {
    fontSize: 18,
    fontWeight: '200',
    textAlign: 'left',
    margin: 20,
  },
  rowText: {
    textAlign: 'left',
    color: '#333333',
    marginLeft: 25,
  },
});

All errors can be contained in this component

src/components/page_error.js
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class PageError extends Component {
  constructor(props) {
    super(props);
  }

  styleRow() {
    if(this.props.index %2 == 0) {
      return styles.evenContainer
    }
    return styles.oddContainer;
  }

  render() {
    return (
      <View>
        <Text style={styles.errorHeader}>
          ERROR
        </Text>
        <Text style={styles.errorText}>{this.props.errorText}</Text>
      </View>);
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  errorHeader: {
    fontSize: 26,
    textAlign: 'left',
    fontWeight: '200',
    color:'red',
    margin: 10,
    marginTop:50,
  },
  errorText: {
    fontSize: 20,
    textAlign: 'left',
    fontWeight: '300',
    color:'black',
    margin: 10,
  },
});

Sunday, April 16, 2017

Convert callbacks to Promise


How to use promise design patterns on AWS API's

We all talk about callback hell in JavaScript world. There are a few ways we can follow to mitigate callback hell, its a matter of time, before it catches up with us. One of the ways we can get better of it is use "Promise".

A simple Callback sample

Here's a classic example of how I read contents from an S3 bucket first with callback pattern, then later with promise. This change is not drastic, but benefits are. It's not just code maintenance, readability also improves by miles. The more you follow promise patterns more are the chances you stay clear with context and re-usability. Finally, something that brings smile to perfectionists - Unit tests. Promise makes it lot more easier for unit tests.



'use strict';

var config = {
    accessKeyId: 'SDFLGSDFGLJSDFGL',
    secretAccessKey: 'sdasdfasdflfmasdlasdffm/asdf',
    region: 'us-east-1'
};

var tipsBucketConfig = {
    'Bucket': 'somebucket',
    'Key':'tips_xyz.json'
};

var AWS = require('aws-sdk');
var awsConfig = require('aws-config');

var s3 = new AWS.S3(awsConfig(config));
var listAllBuckets = function() {
    s3.listBuckets({}, function(err, data) {
        if(err) {
            console.log('ERROR: Failed to collect any information about buckets');
        } else {
            var buckets = data.Buckets;
            var owners = data.Owner;
            for (var i=0; i<buckets.length; i+=1) {
                var bucket = buckets[i];
                console.log(bucket.Name + ' created on ' + bucket.CreationDate);
            }

            for (var i=0; i<owners.length; i+=1) {
                console.log(owners[i].ID + ' created on ' + owners[i].DisplayName);
            }
      }
    });
};

listAllBuckets();



Of course, we can make this code better, by creating a callback function that can be passed to "listBuckets" method. I bet you can, imagine for a minute, our requirement gets a little more complicated. If we have multiple buckets and we need to dig into one of the bucket for information, you can easily see the constrictor tightening its grip.




Promise Approach

This is where promise helps. And here's how we can convert the code above to a promise pattern


'use strict';

var config = {
    accessKeyId: 'SDFLGSDFGLJSDFGL',
    secretAccessKey: 'sdasdfasdflfmasdlasdffm/asdf',
    region: 'us-east-1'
};

var tipsBucketConfig = {
    'Bucket': 'somebucket',
    'Key':'tips_xyz.json'
};

var promise = s3.listBuckets({}).promise();
promise.then(function(data) {
    var buckets = data.Buckets;
         var owners = data.Owner;
         for (var i=0; i<buckets.length; i+=1) {
             var bucket = buckets[i];
             console.log(bucket.Name + ' created on ' + bucket.CreationDate);
         }

         for (var i=0; i<owners.length; i+=1) {
             console.log(owners[i].ID + ' created on ' + owners[i].DisplayName);
         }
}).catch(function(err) {
    console.log('ERROR: Failed to collect any information about buckets');
});

We have error handler abstracted out. If we need to interrogate a specific bucket, then we will return a promise, that can be re-used a lot more easily than conventional callback pattern.

Let me know your thoughts and as always, thanks for your time.

Sunday, February 26, 2017

JS development with ATOM IDE

JavaScript has been the most sought after s/w development language in the last 3 years. Researchers claim JS developers will be the highest paid developers in 2017/18. If you are a JS developer, you cannot wish for a better time.

NodeJS has rocked the service industry. Angular JS & React JS is now shaping client industry. React Native, Native Script and Cordova is redefining Mobile development. As a whole JS is every where.

With right design patterns and IDE, JavaScript development an easier tool to master. Design patterns is a skill level. I'll continue to post more on different design and architecture patterns, in coming days. Let's first talk about IDE's.

There are a fleet of IDE available for JS development. If you are looking for a paid solution. Look no where belong Webstorm. From the open source world we have Eclipse, Sublime Text, Brackets, ATOM, VSCode and so much more. I started with the oldest in the game, Sublime Text. I continue to use it for some cases. No complaints, it still continues to be one of the best of the simple IDE's.

However there is another IDE that has been making rounds, "ATOM". Very simple, efficient, super easy to maintain. I liked the interface from day one. I shared my experience with my friends. They tried it and had similar experiences.

Most of these open source IDE's like Sublime Text, work well with right packages. ATOM is no different. ATOM store is loaded with packages and is easy to access it too. No need to install any external package managers to begin. Open preferences from ATOM menu and you have "Install Packages" right there. From source control to terminal access, code compilation, spell check and documentation, all sort of packages are available.

Here are the list of packagaes I installed for ATOM. There are a lot more, if you want


  • Atom Beautify
  • Atom TernJS
  • Auto-detect Indentation
  • Auto-update packages
  • Autocomplete Modules
  • DocBlockr
  • Editor Config
  • GIT Projects
  • Language Babel
  • Linter ESLint
  • Linter Flow
  • Nuclide
  • React
  • Sync Settings
  • Term3
  • TODO Show
  • Pigments
  • Toolbar
  • file-icons
  • autoprefixer
  • emmet
  • highlight-line
  • highlight-selected
  • selection-highlight
  • Node debugger for ATOM
  • atom typescript
If there's a package I missed that you found very useful, please do share it.