Skip to content

Login and Registration

JerJohn15 edited this page May 13, 2016 · 10 revisions

#Login and Registration Design

###Part 1

Update: There have been some updates to the project since the v.021 Release. To download the original file, go here

This wiki section explains how I implemented the first demo of the Login and Registration feature in my forked repository of stock-quotes-and-recco.

Here is an overview of the relevant files explained throughout this wiki:

Project Directory

stock-quotes-and-recco
src/
---js/
-------- components/
-----Views/ //These contain the views for each individual page
----Account/
--------CreateAccount.js//registration page
--------Login.js//login page
----Pages/
--------Home.js//the home page
--App.js//Backend for rendering each page
--NavigationBar.js//Navigation Bar for navigating each page
-Routes.js//routing paths for each component

####Coming up with the Idea

One of the features I had wanted to implement within this project was a Login and Registration form, where a user can login, with their credentials, or register an account, if they do not have an existing one. I wanted to include two buttons: 'login' and 'register', where, upon clicking, would open up each form by way of popup (see diagram below). The idea for the popup was due to the original repository having a logout button, alerting the user that they have logged out of the site.

modals

logout

Instead of implementing a popup, I decided to go with a Modal (I learned about them by listening to an episode of the [UX and Growth] (http://austinknight.com/writing/the-death-of-the-popup-and-rise-of-the-modal/) podcast). Rather than create my own, I used the Modal component from Node JS's 'React Boostrap' package.

####Designing the Features

To incorporate modals into this project, I wanted to create two additional components, Login and CreateAccount, that contain the front-end for each screen embedded within Bootstrap's 'Modal' component, as well as revise the NavigationBar component so that it contains a 'login' and 'register' button. With these features included, whenever the user clicks either button from the navigation bar, a modal will show with the appropriate form generated through their components. (Note: These forms should show whenever the user clicks these buttons on any page with the navigation bar present.)

design of buttons with components

#####Designing the Modal and Login/Registration Form

As explained in the official documentation, bootstrap's Modal component contains stub components that handle the action of opening and closing the modal (Modal), the modal header (Modal.Header, Modal.title), the main content displayed (Modal.body) and footer Modal.footer).

Given this template I've designed both Login and CreateAccount components as forms which display input fields, for entering in a desired Username and Password, as well as buttons, for submitting user information (both forms), clearing all fields from a form (registration feature only), and registering an account (login feature only).

Below is a prototype design of what each form should look like:

login-GUI

register-GUI

#####Handling Action Events Within the Modal

Within the main MODAL component, react-bootstrap has the properties (also known as props), show and onHide that are used to control the action of the modal opening and closing (see the props table in the Modal section). Upon looking at the documentation, I noticed that in order for both props to work, it requires a function and a state to be set within both objects. Also, the modals used in each example, only utilize modals from within a single component. Since I wanted to implement modals in a new component when a button is clicked from within a separate one, I needed to figure out if there was a way to pass a component state from one component to another. Fortunately, there exists a way to do this.

#####Designing Action Events Within the Modal

According to this tutorial from Facebook, their method for handling state values between components is to to pass the component states that you want to use, from one component to another, via its properties (these components are also known as the parent and child component). Whenever you need to access that property again from the child, call the property that you created in the parent component, from within the child component. So I took that information and made the following steps:

(1) Create properties to be passed to the child component in it's parent.

(2) Pass these properties to the child component.

(3) Access these properties from the parent within the child component, whenever needed.

So within my project, I first needed to identify the parent and child components:

Parent-Child-Component-Relationship

The image above, shows the relationship my 'App' component has to its three children: 'NavigationBar', 'Login', and 'CreateAccount'.

Next, I had to figure out where I wanted to implement the main process and how it should function. I took the above steps and tweaked them to fit my project.

process for handling states

As the image above shows, I needed to first (1) create states and setter functions, within the App component, then (2) render the NavigationBar with the setter functions passed through as properties. From there, (3) whenever a user clicks either button from the NavigationBar, I'll need to send a request back to the App component that a button has been clicked and (4) render a Login or CreateAccount component -with a state and function passed through as properties-. Next, I'll need to (5) accept the state request from the App component to open the modal, and finally, (6) send a request back to the App component to close the modal, when the user decides to exit it.

Now let me explain how I implemented this.

#####Implementing the Features

In my App component, I've created created two boolean states, one for handling the acknowledgement of each button event taking place, and four function setters, to handle the changing values as they are called from within each child components. Note: I've passed functions inside the NavigationBar, because the button's onClick handler only accepts functions inside them (try to pass something other than a function to see what happens).

//App.js
//initialization of the states
getInitialState: function(){
  return { showLogin: false, showRegister: false};
},

<div className ="NavBar">
  <NavigationBar onLogin = {this.openLogin}
    onRegister = {this.openRegister}/>
</div>

//The setters which monitor whether or not the modal is active
openLogin: function(){
  this.setState(
    {  showLogin: true  }
  );

},

openRegister: function(){
  this.setState(
    {  showRegister: true  }
  );

},

closeLogin: function(){

  this.setState(
    {  showLogin: false  }
  );

},
closeRegister: function(){

  this.setState(
    {  showRegister: false  }
  );

}

Next comes the accessing of the functions from the NavigationBar. This is done by the using the syntax, this.props.[object name]. Now whenever a button is clicked, a function callback to 'App.js' will be called for either openLogin or openRegister.

//NavigationBar.js
<div style={{ float: 'right' }}>
  <Link style={styles.link} to="/profile">{user.name}</Link>
    <button  id="login"//function callback made to openLogin
      onClick = {this.props.onLogin}>log in</button>

    <button id ="register"//function callback made to openRegister
      onClick = {this.props.onRegister} >register</button>
</div>

After a callback is created, the states of either showLogin or showRegister are set to true and the appropriate component can now be rendered upon evaluation. I've handled this through the creation of ternary operators.

<div className = "Modals">
//NavigationBar.js
//This reads like an If...else statement.
//If either state is true, render that component, with its state and setter,
//passed through. Otherwise, do nothing.
  {this.state.showLogin ?
    <Login openModal = {this.state.showLogin}
      closeModal = {this.closeLogin}/>   : null}

      {this.state.showRegister ?
        <CreateAccount openModal = {this.state.showRegister}
          closeModal = {this.closeRegister} />  : null}
        </div>

Now all that's was left to do is set the show and onHide objects inside the Modal component, to the objects I've declared from the NaviationBar, and create the front-end for each form.

//Login.js - Login screen within a Modal
<div>
  <Modal show= {this.props.openModal} onHide={this.props.closeModal}>
    <Modal.Header closeButton>
      <Modal.Title>Login </Modal.Title>
    </Modal.Header>
    <Modal.Body>
      <label htmlFor="username">Username
       <input type = "text" id= "username" ></input>
      </label>
      <div>
        <br/>
      </div>
      <label htmlFor="password">Password
       <input type = "text" id= "password"></input>
      </label>
    <div>
        <br/>
      </div>
      <button id= "login"> Login  </button>
      <button id= "register"> Register  </button>
    </Modal.Body>
  </Modal>
</div>
//...
//CreateAccount.js - Registration Form
<div>
  <Modal show= {this.props.openModal} onHide={this.props.closeModal}>
    <Modal.Header closeButton>
      <Modal.Title>Registration </Modal.Title>
    </Modal.Header>
    <Modal.Body>
      <form id ="register">
          <label htmlFor="username">Username:
           <input type = "text" id= "username" ></input>
          </label>
          <div>  <br/>  </div>
          <label htmlFor="password">Password:
            <input type = "text" id= "password"></input>
            </label>
            <div>  <br/></div>
              <label htmlFor="password">Re-enter
                Password:
               <input type = "text" id= "password"></input>
              </label>
              <div>   <br/>  </div>
              <button id= "submit"> Submit  </button>
              <button id= "clear" > Clear </button>
      </form>
    </Modal.Body>
  </Modal>
</div>

Now that I had all of the main ingredients made, when I ran the project, I was successfully able to get the login and registration forms to display upon a button click.

login-page

register-page

#####Getting the Page Views to Display Behind the Modal

Originally, this project was designed so that within each main component (see the pages folder in my project), a NavigationBar would be rendered along with it. So the following would take place:

component-navbar

You'll notice, how this process can become repetitive overtime. To resolve this, I had to re-think how the design of each view should be handled. Through research, I concluded that instead of rendering the Navigation Bar within each page, I should have one component, App, maintain the view of the Navigation Bar, and each component page. This required the use of React-Router's Index Route method, and the property, this.props.children. IndexRoute allows a child component to be rendered along with its parent, so in the following code snippet the child component, Home, gets rendered with its parent, App.

//Routes.js - The routing paths
ReactDOM.render(
  <Router history = {hashHistory}>
    <Route path="/" component={App}>//Parent of Home
      <IndexRoute component = {Home}/>//child of App
      <Route path="stocks" component={StockList} />//these get rendered through this.props.children
      <Route path="study" component={StudyTracker} />
      <Route path = "ExRates" component={ExchangeRates} />
      </Route>

  </Router>, document.getElementById('root'));

Now in order to access each page view from the App component, I needed to use this.props.children in my render method, like so:

render() {
    //props.children extracts all of the child components of App depending on what
    //the user clicks in the navigation bar
    var contentView = this.props.children;

    return (
      <div>
        <div className ="NavBar">
          <NavigationBar onLogin = {this.openLogin}
            onRegister = {this.openRegister}/>
        </div>
        <div className = "Modals">
          {this.state.showLogin ?
            <Login openModal = {this.state.showLogin}
              closeModal = {this.closeLogin}/>   : null}

              {this.state.showRegister ?
                <CreateAccount openModal = {this.state.showRegister}
                  closeModal = {this.closeRegister} />  : null}
                </div>
                <div className = "Content">//render this.props.children here
                  {contentView}
                </div>
              </div>

            )

So now whenever I click a button in the Navigation bar, each page gets rendered in my App component, through this.props.children, with the NavigationBar component, as a header. The design of the rendering process can now by updated to the following diagram:

navbar components revised

Having done all this, I was successfully able to finish the Login / Registration Form feature! To view the demo go here. To download this project go here

###Conclusion

While building this demo, I learned what Modals are and how to use them in React. I also learned how to use states to handle transitions with opening and closing windows as well as techniques for displaying views for multiple pages within a single component, using React-Router.

It should be noted that using multiple states and setter functions to handle the action events of button clicking is not the best way to design this feature in the long run (Imagine if there were other features which require states, like a Chatroom or live video feed). If this project were to become a real product, I would probably need to adopt flux or redux, which is built to handle numerous states. In the future, I will probably utilize such packages.

####References:

Creating Modals

React-Bootstrap's Modals

Passing props from Parent to Child

Handling Action Events with States in React

Thinking in React

Index Routing

Layout Page with React-Router

Official Index Routing Documentation

Configuration Components

Clone this wiki locally