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.

Monday, October 24, 2016

React-Navite - Introduction

React Native is one of the very few frameworks that has changed the way mobile applications can be built. Notice how I said mobile applications and not iOS or Android applications or for that matter mobile or tablet devices. React native applies to both. Now you think ahhhh, I have heard this before, we have looked at a lot of frameworks/packages like this before - PhoneGap, Titanium, Kony, Xamarin and so many others. If you think React-Native is one among them you are thoroughly mistaken.

What we look for in mobile applications

There is always a native language to build applications for smart devices and in the case of iOS, there is more than one. Why even concern about anything more to build a native application. What's special about React-Native and why should we care about it. That's a great question to start with.

Developing applications for smart devices is no longer simple anymore. It's not some 5 forms and a list application pattern. People are building CRM and ERP applications for mobile. Today, mobile solutions have changed from antiquated or even an extension from web into a full fledged solutions. In some cases mobile applications are the only go, they don't even have web counter-parts and future looks more like that. I have personally built applications that have more than 100 forms and at least about 40 lists. I am not going got brag about my mobile development experience here, but what I am trying to say is, it is a complex world out there. Applications are gynormous. Maintenance is a major  head-ache. In addition to our work on module, size complexities you have to think about several other factors and that includes


  1. How intuitive is the UI
  2. Support for mobile analytics 
  3. How Keyboard UI is presented and their customizations
  4. Application behavior in different orientations
  5. Graphics/Animation support inline with the application (I am not talking about those fancy animations that annoy users, so to say, but simple animations), 
  6. Access to native objects/applications to build a complete application
  7. Access to local storage, where ever possible. 
  8. Security of data, network operations
These are just a few of them, but you see where I am going

Benefits of building application from common frameworks


We may talk about couple more choices, but I think, if we can have a custom framework that allows us to do all of the above in one seamless form, we all can agree that, it's a great way to get started. And here are some reasons


  1. Code sharability (Even if it is a copy-paste code between iOS & Android, although there are nice design-patterns to handle such cases)
  2. Consistent design patterns between different devices, frameworks
  3. Similar and consistent approach for development, process and maintenance tools
  4. Better planning on tool investment like CI, code analysis etc
  5. Better network handling

Can React-Native help?


We talked about benefits of using a consistent programming language, but such a thing seems to be in an utopian world. Do we have anything closer to reality? The answer is YES and that's where React-Native comes in. This framework from Facebook, allows you to write your application in ES6. Compiler behind the scenes will convert your code into native application. Sounds great. This way you are not dealing with some HTML5 framework or a web solution but a real-world native application. Now all that you need to do is, stick with-in the boundaries of ES6 and React-native framework.

This framework has been tested and FB internally uses this framework to build some of their applications. Apart from FB, there are a lot of other enterprises that are using React-Native for day-to-day applications. Rest assured that you are not the first man to walk this terrain. If you have not tried it, I'd encourage you to read on and give it a shot.

In this section, I will walk you through some simple applications I built to help you see through the advantage of building React-Native application. Things like authentication, weather service, modal applications, better navigation etc are some. These are not typical applications that do the job of showing how to use some basic UI components, but I have weaved together components with application functionality that you can apply for your respective cases. Please stay tuned.....

Monday, October 10, 2016

rocky.js - Pebble Watchface in JavaScript

Create diagital watchface with rocky.js

Pebble is a familiar name in tech world. They were the one's who made the world turn on them when it comes to smart watches. When wearable technology was a dream, their design and approach made them great innovators. They followed it up with Pebble steel which did a wonderful business. Their OS agnostic approach has helped them gain love from both iOS & Android folks. Pebble has made a huge market for itself through its constant innovation and focus. With Pebble2, they have raised the bar a little more. I am not going to review about Pebble2 here. Our interest here is their new JS framework - rocky.js.

Pebble applications have been built with Pebble "C" and to some extent with Pebble JS. With Pebble 4 SDK, rocky.js will be one of the preferred way for pebble apps. rocky.js can be used to develop both watchface's as well as watch apps. Its support for canvas, makes it easy to render complex graphics fast too.

Although, I'd not rank rocky.js to be production ready yet, I'd also not shy away from saying that is is not far off from production grade either. Give it a month, by the time Pebble Time2 comes out to market, I'd say rocky.js may be the face of pebble application development.

What do I need to get started?
Head to developers.pebble.com, register your account and browse into cloudpebble.net, start cranking your code

Let's start by creating a new project, name it "HelloWorld"



You will be taken to cloud studio, from the left navigator, tap/select index.js



We will build our first simple display current time watch face, copy paste the following lines of code

var rocky = require('rocky');
var formatAMPM = function(date) {
  var hours = date.getHours();
  var minutes = date.getMinutes();
  var ampm = hours >= 12 ? 'pm' : 'am';
  hours = hours % 12;
  hours = hours ? hours : 12; // the hour '0' should be '12'
  minutes = minutes < 10 ? '0'+minutes : minutes;
  var strTime = hours + ':' + minutes + ' ' + ampm;
  return strTime;
}
var display_time = function(ctx) {
  // Determine the width and height of the display
  var w = ctx.canvas.unobstructedWidth;
  var h = ctx.canvas.unobstructedHeight;
  var d = new Date();
  // Set the text color
  ctx.fillStyle = 'white';
  // Center align the text
  ctx.textAlign = 'center';
  ctx.font = '30px bolder Bitham';
  // Display the time, in the middle of the screen
  ctx.fillText(formatAMPM(d), w/2, 50, w);
}
rocky.on('draw', function(event) {
  // Get the CanvasRenderingContext2D object
  var ctx = event.context;
  // Clear the screen
  ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);

  display_time(ctx);

});
rocky.on('minutechange', function(event) {
  // Request the screen to be redrawn on next pass
  rocky.requestDraw();
});

Most of the the code is self-explanatory. We start by registering for event-notifications from rocky. One for 'minutechange' (you can try 'secondchange', 'hourchange', etc) and other for redraw. Every minute, code invokes redraw, where-in we display current time through a custom format function.

You are restricted on size and type of fonts, pretty much the same as in "C". However, you can have custom fonts for your applications.

You are all set. Tap on "run", wait and watch your code execute

Tuesday, October 4, 2016

Authentication in NodeJS

We all know and have done authentication for variety of applications - be it on web, mobile, windows or mac applications. The challenge with authentication lies on a couple of different fronts

  1. How easy it is for different applications to integrate and use the same authentication mechanisms
  2. How easy is it to use different strategies without breaking client applications


Its lot more easier said than done. In the past, client application will accept user names and passwords, encrypt credentials and send them over to a safe network and will wait for authentication status from server(s). This works great if we have a singular repository for authentication. Todays users have too many accounts to remember, one would think, its lot more easier to use any of the social network for authentication, while authorization can be managed internally. Such a solution will need more work from both client and server side on one dimension. But from the other dimension, it requires less work in terms for process. Client applications help user choose from one of many social engineering repositories, captures information and passes it to the server. While the server, does not digest this information, but rather, reaches out to the selected repository for information, gets back minimum profile information, along with a token identifier that can be used for back-forth communication. As long as all of the information from the server is available in request header, communication has no problems. If either TTL expires or the request header is manipulated, then authentication process is broken and the user is no longer identified as a authenticated user. He'll be re-directed to logon screen. Behind the scenes, developer needs to classify what constitutes secure paths and what are open for public, which is pretty much like the way he has to do for any regular secure application. No changes there. Enough talking. Lets get down to business.

How about creating a simple NodeJS application that will help you authenticate with different repositories like - Google+, Facebook, Twitter, LinkedIn etc? Sounds exciting. Here' how we can do it

Create a simple NodeJS application and see it work on the choice of your port. I prefer port 3000, you can choose any port of your choice. Once you have the intiial setup, head on to https://developers.facebook.com/, from there choose "My Apps". Tap on "Add a New App". You'll get a pop over, fill in the details, like display name, description, type of application etc. Now, in "Settings" section provide additional information like "App domain", which in our case will "localhost:3000" callback URL will be "http://localhost:3000/auth/facebook/callback". This is the URL that FB application will call us back on, after both successful or failed logon, with appropriate response. Note down App Id and secret key information from FB's site. Under Products section, you'll see "Facebook Login". Under "settings", make sure you set "http://localhost:3000/auth/facebook/callback" for "Valid OAuth redirect URIs".

Now, back in our node application, let's build strategies to handle this. For us to let application talk to FB, we need some more basic set up

Open terminal, navigate to your root directory of node application

npm init
npm install passport --save
npm install passport-facebook --save
npm install passport-github --save
npm install passport-linkedin-oauth2 --save
npm install passport-google-oauth --save
npm install body-parser --save

Each of these npm packages installed allow us to interface with respective authentication repositories. Now, back to FB's authentication. Import passport and passport-facebook packages into your application


var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;

app.use(passport.initialize());
app.use(passport.session());

passport.use(new FacebookStrategy({
    clientID: AppConstants.FaceBook.appId,
    clientSecret: AppConstants.FaceBook.secretKey,
    callbackURL: BASE_URL + AppConstants.FaceBook.callbackURL
}, function (accessToken, refreshToken, profile, done) {
    process.nextTick(function () {
        done(null, profile);
    });
}));

We set the application use passport, passport session and FacebookStrategy as its middleware. Either replace  'AppConstants.FaceBook.appId' and 'AppConstants.FaceBook.secretKey' with the one you got from FB's site, or you can create a separate file with this information. Both of these are less secure, although, later one is slightly better. Personally, I'll store secret key and appID information in a remote location and fetch it when the application starts, or dump it in a secure remote DB, or even better store it as an environment variable. For this sample application, we are fine with any approach.

Now to handle callback from FB, here's what you amy want to do in your router configuration


// Facebook Router
router.get('/auth/facebook', passport.authenticate('facebook'));
router.get('/auth/facebook/callback', passport.authenticate('facebook', {
    successRedirect: '/success',
    failureRedirect: '/error'
}));

router.get('/success', function (req, res, next) {
    if(req.session != null) {
        console.log('Session information');
        console.dir(req.session);
    } else {
        console.log('SESSION is NULL');
    }

    res.redirect(302, 'home');
});
router.get('/error', function (req, res, next) {
    res.send("Error logging in.");
});
router.get('/', function (req, res, next) {
    res.sendfile('public/login.html');
});

And that's it. If your authentication is successful, you'll be re-directed to "home" page. You can follow this same procedure for all other authentication strategies like LinkedIn, Twitter, Google and Github. Working code for all of this is available in location

Sunday, June 12, 2016

Angular2 - Pipes

What are pipes? A pipeline is a sequence of processes chained together by their standard streams, so that the output of each process (stdout) feeds directly as input (stdin) to the next one. Straight from Wikipedia, yeahhhh.

Pipes in Angular are no different. There are a lot of things we can achive with it, but I'd advice you from going overboard. Always check to see if there is a better place/way to do this. If the transformation is one-time and is not complicated, fair enough, do it on the client side. The moment you see the same transformation done more than once, think about a custom pipe. Even with custom pipe you'd want to make sure it is simple. If it gets complicated, try to handle it on server side (in service). Keep client light & clean, make your code less buggy and light.

Angular2 allows for different types of pipes - Literal, Number, Currency, Date, Object and so much more. If the templated pipes are not enough, you can customize and create a pipe of your own. We will not delve into custom pipes in this BLOG. Let's save that for later

First, let's do a currency pipe
Add a new component - currency.component.ts & Pipes.service.ts

pipes.service.ts


import {Injectable} from "angular2/core";

@Injectable()
export class PipesService {
    getToDaysDate():Date {
        return new Date();
    }

    getApplicationVersion(): number {
        return 1.0;
    }

    getApplicationBuild(): number {
        return 12321;
    }

    getDollarValue(): number {
        return 15.41;
    }

    getEuroValue(): number {
        return 40.003;
    }

    getRandomData() {
        //TODO: Make this an array and return something randomly
        return "Some data";
    }
}

That's the service we will use for all components we will create from now on.

currency.component.ts

import {Component, OnInit} from 'angular2/core';
import {PipesService} from "./pipes.service";

@Component({
    selector: 'currency-comp',
    template: `
        <h5>Today's currency values</h5>
        <div class=".pipes">
            <ol>
                <li>{{dollarValue | currency:'USD':true}}</li>
                <li>{{euroValue | currency:'EUR':false:'1.4-4'}} </li>
            </ol>
        </div>
    `,
    providers:[PipesService],
})
export class CurrencyComponent implements OnInit {

    dollarValue: number;
    euroValue: number;
    
    constructor(private _pipesService: PipesService) {}

    ngOnInit():any {
        this.dollarValue = this._pipesService.getDollarValue();
        this.euroValue = this._pipesService.getEuroValue();
    }
}

As you see, cdollarValue is a number variable, we use currency pipeline to convert it to a currency field. Take a look at https://angular.io/docs/js/latest/api/common/CurrencyPipe-class.html to know more on parameters and other choices

Add a new component

date.component.ts

import {Component, OnInit} from 'angular2/core';
import {PipesService} from "./pipes.service";
import {MyVersionComponent} from "./version.component";

@Component({
    selector: 'myDate-comp',
    template: `
        <div class="pipes">
            <table width="100%">
                <tr>
                    <td><h2>{{today | date:'short'}}</h2></td>
                    <td align="right"><myVersion-comp align="right"></myVersion-comp></td>
                </tr>
            </table>
        </div>
    `,
    directives: [MyVersionComponent],
    providers: [PipesService],
})
export class MyDateComponent implements OnInit {
    constructor(private _pipesService:PipesService) {
    }

    today:Date = null;

    ngOnInit():any {
        this.today = this._pipesService.getToDaysDate();
    }

}

Here, we do something like what we did in currency component. Now you see the familiar pattern of how pipes work. To know more check https://angular.io/docs/js/latest/api/common/DatePipe-class.html

Most of the other pipes work very much the same way, except for one  AsyncPipe. It's different from other

randomAsync.component.ts



import {Component, OnInit} from 'angular2/core';

@Component({
    selector: 'async-comp',
    template: `
        <h5>Async - Random</h5>
        <div class=".pipes">
            {{randomData | async}}
        </div>
    `,
})
export class RandomAsyncComponent {

    randomData: string = new Promise((resolve, reject) => {
        setTimeout(() => resolve('Random Data!'), 2000);
    });
}

To understand AsyncPipe better, knock of " | async" out of code, see the behavior and put it back. You'll notice that this pipe will be one of the most used pipes of all of them.

Finally, if you are wondering, how I have my app component, here's how I have aggreagated the rest of them

app.component.ts

import {Component} from 'angular2/core';
import {MyDateComponent} from './date.component'
import {CurrencyComponent} from "./currency.component";
import {RandomAsyncComponent} from "./randomAsync.component";

@Component({
    selector: 'my-app',
    template: `
       <h1>Angular 2 - Sample Pipes</h1>
        <p>Welcome to the world of Angular2 Pipes</p>
        <myDate-comp></myDate-comp>
        <currency-comp></currency-comp>
        <async-comp></async-comp>   
    `,
    directives: [MyDateComponent, CurrencyComponent, RandomAsyncComponent],
})
export class AppComponent {

}

app.scss

body {
  padding: 32px;
  margin: 32px;
  font-family: "Roboto", Arial, sans-serif;
  font-size: 16px;
}

.pipes {
  margin: 32px 0;
  padding: 16px;
  background-color: #eee;
  border: 1px solid #ccc;
}

Angular2 - http GET/POST

What's the use of an application that does not talk with a remote datastore to persist or retreive information. This is one that I was looking forward to when I started Angular2. I believe it's the same with you. We are not going to make a deep dive, but rather touch enough piece to help you move along.  We will need a remote service that can persist contact information and give us back the contact list. For this exercise, I have created a sample NodeJS service that'll do the job - https://javascriptkrishnan.blogspot.com/2016/05/nodejs-mongodb-communication.html. Code is not pristine, but certainly get's us going. This NodeJS solution persists contact data passed to it in MongoDB and get's it back to us when requested. If you try this solution, please make sure you install and have accessible MongoDB. It's not just enough you have MongoDB, you need to fix it's access. Ensure right credentials are passed. How do you store user name and password for MongoDB in your Node JS solution. There are so many patterns. However, a simpler solution can be found here - https://javascriptkrishnan.blogspot.com/2016/06/application-initialization-dev-vs.html

Alrighty, what do we change in our code to be access this http service? Fairly simple. Remember we implemented mock services, it comes handy. All that we need to do is fix the services file to import http module and get data from remote location, instead of mock service. Here's the updated code. You may want to brush your knowledge on Promises

ContactsService.ts

/**
 * Created by krishnansriramrama on 5/28/16.
 */


import {Injectable} from "angular2/core";
import {Http, Headers} from "angular2/http";
import 'rxjs/Rx';
import {Contact} from "./Contact";

@Injectable()
export class ContactsService {
    ENPOINT_URL:string = "http://localhost:3000/contacts";

    constructor(private _http: Http){}

    getAllContacts() {
        return this._http.get(this.ENPOINT_URL).map(res => res.json());
    }

    saveContact(contact: Contact) {
        var contactBody: string = contact.toString();
        var header = new Headers();
        header.append('Content-Type', 'application/json');
        console.log("Saving contact: " + contactBody);
        return this._http.post(this.ENPOINT_URL, contactBody, {headers: header}).map(res => res.json());
    }
}