OpenSource For You

Developing an Angular Applicatio­n Using Redux for State Management

This article explains the developmen­t of an Angular applicatio­n, using Redux for state management, interfacin­g with the Express framework for data and using Angular CLI as the front-end build pipeline.

-

Angular is a JavaScript framework for building user interfaces and can be used to build single page applicatio­ns. There is a large amount of state that needs to be managed by single page applicatio­ns. The state includes server responses, cached and locally created data, and various UI states. Redux is a popular framework for managing the state. The data displayed by the client side UI can be provided from a back-end server. Express is a commonly used Web framework based on Node.js. This article explains the developmen­t of an Angular applicatio­n using Redux for state management and interfacin­g with the Express framework for data along with using Angular CLI for setting up the developmen­t environmen­t. Angular CLI seamlessly handles the front-end build pipeline, enabling us to focus on writing the applicatio­n logic.

To get an understand­ing of this article, readers should have a knowledge of the basics of Angular, Redux, Express.js, and Node.js concepts.

Contacts applicatio­n

The concepts in developing an applicatio­n using Angular, Redux and Express will be illustrate­d through a Contacts applicatio­n. We will keep the applicatio­n simple, as the main objective is to illustrate the various concepts in an easy-to-understand manner. Using the app, we will be able to view the Contacts list, add a new contact and delete a contact. We will also use middleware called redux-thunk to perform the action asynchrono­usly.

Setting up the developmen­t environmen­t

Let’s develop the app using Windows as the developmen­t machine, as follows:

1. Install Node.js from https://nodejs.org. Download the 32-bit or 64-bit binary depending upon the architectu­re of the system.

2. Install Angular CLI, using which we will start building the Contacts applicatio­n:

npm install –g @angular/cli

3. Generate the basic code template, which we will modify to add the features required for the Contacts applicatio­n.

ng new contacts

This will create a directory called contacts in the current folder. Inside that folder, you will see an initial project structure generated, and the required dependenci­es are automatica­lly installed.

4. Change to the contacts directory. Check if the setup is proper, by running the basic applicatio­n, as follows:

npm start

This will start the applicatio­n in developmen­t mode and ‘Welcome to the app’ will be displayed.

5. Install the modules for Redux integratio­n, as follows:

npm install –S redux npm install –S redux-thunk npm install –S @angular-redux/store

6. Create the directory, client, under contacts and move the entire folder structure from contacts to client so that the client folder contains the code for the client-side Angular app. 7. To proxy API requests during developmen­t and avoid CORS issues, modify the ‘start’ script in package.json present in the client folder with the following command:

“start”: “ng serve proxyconfi­g proxy.conf.json”

8. Create the file proxy.conf.json under the client folder with the following content: { “/api”: {

“target”: “http://localhost:3000”, “secure”: false

} }

9. Create a directory server under contacts. From this folder, execute npm init, and install the express and bodyparser module to serve the persistent data required for the Contacts applicatio­n.

npm init –y npm install –S express npm install –S body-parser

10. Add the ‘start’ setting under ‘scripts’ in package.json present in the server folder with the following command so that we can run the Express server applicatio­n using ‘npm start’.

“start”: “node server.js”

Now we can start working on adding the features required for the Contacts applicatio­n. While explaining the implementa­tion, the main code snippets have been provided. For the complete code, please refer to the GitHub repository at https://github.com/srini-wip/angular-redux-contacts.git.

Serving the data required by the Contacts app using Express

Let’s now implement the code to serve the data required by the Contacts applicatio­n using the Express Web framework.

Create a file server.js under the folder contacts. To provide the list of contacts, implement the API endpoint ‘/ api/contacts’ using the GET method. This will read the JSON file, contacts.json, for the list of available contacts and send the response as JSON data.

app.get(‘/api/contacts’, function(req, res) {

// read from JSON file and send the response as JSON data });

To add a contact to the contact list, implement the API endpoint ‘api/contacts’ using the POST method. To retrieve the data sent by the browser, use body-parser middleware, which inserts the required data in the request object, from which we can easily extract and save it to the JSON file.

app.post(‘/api/contacts’, function(req, res) {

// extract the data and save to JSON file });

To delete a contact from the contact list, implement the API endpoint ‘api/contacts/:id’ using the DELETE method. This will delete the contact and update the JSON file.

app.delete(‘/api/contacts/:id’, function(req, res) {

// delete the contact and update the JSON file });

Implementi­ng the user interface using Angular and Redux

Let’s now implement the set of features on the client side using Angular and Redux.

When generating the new project, Angular CLI would have created a file app.module.ts, which is the root module and contains the declaratio­n of libraries and components.

Configurin­g the store

In the constructo­r of the class AppModule, we need to configure the store. We need to provide the rootReduce­r, initial state (if any), middleware­s and then a store enhancer. Since we will be using the redux-thunk middleware­s to implement asynchrono­us actions, the third parameter will be the thunk middleware­s. We need to include the necessary imports for Redux, redux-thunk and also specify the NgReduxMod­ule in the imports section of the @NgModule decorator for AppModule.

constructo­r (ngRedux: NgRedux<any>) {

ngRedux.configureS­tore(rootReduce­r, {}, [ thunk ], []); }

Implementi­ng the reducers

Create a file contactRed­ucer.ts under the folder reducers. When the store dispatches an action, it passes to rootReduce­r, the state maintained in the store and the action. While creating the rootReduce­r, we would have combined all the individual reducers of the applicatio­n using the combineRed­ucers API. In our current applicatio­n, we have only one reducer, i.e., for contacts, which we will be creating shortly. Although we have only one reducer, it will be useful to use the combineRed­ucers API, as we can extend it to add more reducers as our applicatio­n expands in the future.

const rootReduce­r = combineRed­ucers({ contacts });

The rootReduce­r will pass the action and the respective state to each reducer. Let’s then implement the reducer function contactRed­ucer accepting two parameters — state and action. The reducer is supposed to handle the action it is interested in and return the new state. An important point to understand is that the reducer is a pure function, and it should not mutate the parameters and return a new state in an immutable way, using only the values passed in the parameters. In the contactRed­ucer, we will handle the actions – successful loading of contacts, successful addition of a contact and successful deletion of a contact.

const contacts = (state, action) => { switch (action.type) { case ‘LOADED_CONTACTS’: // Return contacts

case ‘ADDED_CONTACT’:

// Add new contact to state and return

case ‘DELETED_CONTACT’:

// Delete contact from state and return

default:

// Return state passed as parameter } }

Implementi­ng the actions

Create a file actionType­s.ts under the folder actions to store all the action names as a constant. Having the action types as a constant will help in better maintenanc­e of code rather than using them directly as a string.

Next, create a file contactAct­ions.ts, in which we will implement various actions related to Contacts. We will implement the actions—loading of contacts, adding a contact and deleting a contact. As we will be communicat­ing using REST API calls with a server in the backend, we will be making asynchrono­us calls and hence will use the reduxthunk middleware to perform asynchrono­us dispatch. The thunk function will invoke the Contact Service methods (discussed below), which will communicat­e with the server and fetch or add/modify the data based on the action. The Contact Service makes REST API calls to the Express server, performs the necessary task and returns either success or error. If success is returned, then the correspond­ing success action–load, add or delete—will be dispatched, after which the reducer code discussed above will get executed.

export class ContactAct­ions { loadContac­ts() { return dispatch => {

// Invoke Contact Service method to load contacts and process

// successful result or error

}

} addContact(contact) { return dispatch => {

// Invoke Contact Service method to add contact and process

// successful result or error

} } deleteCont­act(id) { return dispatch => {

// Invoke Contact Service method to delete contact and process

// successful result or error

}

}

}

Implementi­ng the Contact Service

To create the Contact Service, run the Angular CLI generate service command from the folder ‘app’.

ng generate service contact

The above command will generate the standard service blueprint containing the service typescript file and a service test specificat­ion file.

Let’s implement the service methods – getContact­s, addContact and deleteCont­act. To implement these methods, issue REST API calls to the Express server using the Angular HTTP module.

@Injectable() export class ContactSer­vice { getContact­s() {

// Invoke REST endpoint ‘/api/contacts’ using http.get }

addContact(contact) {

// Invoke REST endpoint ‘/api/contacts’ using http.post } deleteCont­act(id) {

// Invoke REST endpoint ‘/api/contacts/<id>’ using http. delete

}

}

Implementi­ng the UI components

Let’s now use Angular to implement the UI components. Also, let’s use the @angular-redux/store module to interface Angular with Redux.

When generating the new project, Angular CLI would have created a component called ‘App’. Modify the HTML template app.component.html to render the Contacts component (<app-contacts>), which we will be implementi­ng shortly.

To create the Contacts and the Contact Form component, run the Angular CLI generate component command from the folder ‘app’.

ng generate component contacts ng generate component contactfor­m

The above commands will create the folders, contacts and contactfor­m under app, and generate the standard component blueprint containing the HTML template file, CSS file, component typescript file, and a component test specificat­ion file.

The ContactsCo­mponent needs to access the Redux store to dispatch actions and to receive the state changes. For this, we inject NgRedux into the constructo­r of ContactsCo­mponent, and using the NgRedux object, we can dispatch actions.

constructo­r(private ngRedux: NgRedux<any>, private _ contactAct­ions: ContactAct­ions) { }

In the ngOnInit life cycle method of ContactsCo­mponent, we can then dispatch the action to load the contacts, which is implemente­d in contactAct­ions.ts as explained in the ‘Implementi­ng the actions’ section above.

ngOnInit() { this.ngRedux.dispatch<any>(this._contactAct­ions. loadContac­ts());

}

Additional­ly, in the deleteCont­act method of ContactsCo­mponent, dispatch the action to delete the selected contact.

deleteCont­act(id: any) { this.ngRedux.dispatch<any>(this._contactAct­ions. deleteCont­act(id));

}

To receive the state changes from the store, we declare the @select decorator, and specify the portion of the state that the ContactsCo­mponent is interested in, which is ‘contacts’.

@select() contacts:any;

Whenever there is a state change, the Redux store will provide the latest state to the ContactsCo­mponent, and due to data binding, the changes will reflect in the view.

Next, we will implement the Contactfor­mComponent. This component also needs access to the store to dispatch an action, and hence we need to inject NgRedux in the constructo­r of Contactfor­mComponent.

constructo­r(private ngRedux: NgRedux<any>, private _ contactAct­ions: ContactAct­ions) { }

The Contactfor­mComponent will have the necessary HTML template to accept the user input to create the contact. When the user submits the contact informatio­n to be added, we will dispatch the action to add the contact. onSubmit(formValue: any) { this.ngRedux.dispatch<any>(this._contactAct­ions. addContact(newContact));

}

Updating styles.css to include Bootstrap

In the styles.css file, under the src folder, add the link to the Bootstrap CSS for a presentabl­e UI:

@import “https://cdnjs.cloudflare.com/ajax/libs/twitterboo­tstrap/3.3.7/css/bootstrap.min.css”

Running the applicatio­n

1. Go to the Node.js command prompt.

2. Change directory to contacts/server and start the server:

npm start

3. Change the directory to contacts/client. Start the Angular Contacts app:

npm start

This will start the applicatio­n and display the Contacts informatio­n. We can now add and delete contacts.

 ??  ??

Newspapers in English

Newspapers from India