Previous page: Create a GraphQL Subscription to send real-time message notifications
Angular Components & GraphQL Subscriptions
Integrate GraphQL Subscriptions into Angular components to build a list of messages
Our subscription is ready in our GraphQL API. Lets now integrate our Angular components with the new subscription to get live message updates. We will adjust our GraphQL setup to allow for websocket communication, create a service to contain our GraphQL subscription logic and finally integrate the subscription exposed from the new service into an Angular component.
Configuring Apollo Client for use with Subscriptions
We need to set up the Apollo client to allow websocket traffic and communication. To achieve this we need to split the link we currently have to handle the interaction with our API in to two parts. One branch of code will handle HTTP requests and another will handle websocket subscriptions.
We will first need to install a few new dependencies to set up a websocket by
running the following commands within from your project folder's web-app
directory:
npm install --save apollo-link-ws
npm install --save apollo-link
npm install --save subscriptions-transport-ws
This will give us the WebSocketLink dependency that we'll need to define our GraphQL endpoint used for subscriptions as well as peer dependencies and utilities that will give us the ability to split the request based on the operation type.
From your project folder, open the file
web-app/src/app/graphql.module.ts
and add the following imports to the top of
the file:

// Existing code...
import { WebSocketLink } from 'apollo-link-ws'; // <-- Add new import
import { ApolloLink, split } from 'apollo-link'; // <-- Add new import
import { getMainDefinition } from 'apollo-utilities'; // <-- Add new import
import { ApolloClientOptions } from 'apollo-client'; // <-- Add new import
const uri = 'http://localhost:4123/graphql';
// Existing code...
Then replace the createApollo
function with the following:

// Existing code...
export function createApollo(httpLink: HttpLink) {
const http = httpLink.create({
uri,
withCredentials: true
});
const ws = new WebSocketLink({
uri: `ws://localhost:4123/graphql`,
options: {
reconnect: true
}
});
/**
* Split the Apollo link to route differently based on the operation type.
*/
const link: ApolloLink = split(
// split based on operation type
({ query }) => {
let definition = getMainDefinition(query);
return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
},
ws,
http,
);
const opts: ApolloClientOptions<any> = {
link,
cache: new InMemoryCache()
};
return opts;
}
@NgModule({
// Existing code...
})
export class GraphQLModule {}
The new version of the createApollo
function will separate queries made
from the client, splitting them by operation type, passing all HTTP requests
to Apollo's HttpLink
and subscription requests to the WebSocketLink
.
The InMemoryCache
will configure Apollo to save data (with caching enabled) to
the physical server memory of which the app runs. For obvious reasons,
this is only suitable for development purposes and for this tutorial.
Create an Angular Service for Subscription logic
Before we can integrate our components with the subscription, we will need to create an Angular service to hold the subscription logic.
Within the terminal or command prompt, create and open the file
web-app/src/app/messages/shared/message-subscription-gql.service.ts
with
the Angular CLI.
ng generate service messages/shared/message-subscription-gql
In the new file add the following code:

import { Injectable } from '@angular/core';
import gql from 'graphql-tag';
import { Subscription } from 'apollo-angular';
import conversationMessageFragment from './conversation-message-fragment.gql';
@Injectable({
providedIn: 'root'
})
export class MessageSubscriptionGQLService extends Subscription {
document = gql`
subscription {
messageAdded {
...conversationMessage
}
}
${conversationMessageFragment}
`;
}
We import our new Subscription
class from apollo-angular
to extend this
in our custom class. All we have to do is specify the document
property on
the class to use this service in our component and subscribe to the query it
generates.
Subscribe to new messages added to the conversation
In our component, we will first need a way to add a new message to our message
list for when data is emitted from the subscription. We will create a method
addNewMessage
that will be called each time a new message is added. This will
be responsible for updating our view-model of messages
.
Open the file
web-app/src/app/messages/view-conversation/view-conversation.component.ts
, add
an import to the new service and define a new dependency in our constructor.

// Existing code...
import { MessageSubscriptionGQLService } from '../shared/message-subscription-gql.service'; // <-- Add new import
// Existing code...
@Component({
// Existing code...
})
export class ViewConversationComponent implements OnInit {
// Existing code...
constructor(
private retrieveMessagesService: RetrieveMessagesService,
private messageSubscriptionGQLService: MessageSubscriptionGQLService // <-- Add new dependency
) {}
// Existing code...
}
Add the following method after the updateMessages
method:

// Existing code...
@Component({
// Existing code...
})
export class ViewConversationComponent implements OnInit {
// Existing code...
updateMessages(result: ApolloQueryResult<{messages: Array<MessageModel>}>) {
// Existing code...
}
addNewMessage(messageData: any) { // <-- Add new method
this.messages.push(
ViewConversationComponent.createMessageInstance(messageData)
);
}
}
The method addNewMessage
changes the user interface by mapping new message
data to a new MessageViewModel
and adding it to the messages
array along
with all other messages. The Angular template will detect the changes in the
component and will update the user interface automatically for us.
We have a method that is purely responsible for the way we update the user
interface. We also need to define a handler to react to new messages sent from
the subscription and notify addNewMessage
of these new changes.
After the addNewMessage
method add the new method messageReceived
:

// Existing code...
@Component({
// Existing code...
})
export class ViewConversationComponent implements OnInit {
// Existing code...
addNewMessage(message: any) {
// Existing code...
}
messageReceived(result: ApolloQueryResult<{messageAdded: MessageModel}>) {// <-- Add new method
if (!result || !result.data || !result.data.messageAdded) {
return;
}
this.addNewMessage(result.data.messageAdded);
}
}
This method is pretty similar to our updateMessages
method that we previously
wrote. The difference being that we have delegated the responsibility of
updating the user interface to another function.
The last thing to do is to subscribe to our new GraphQL subscription. At
the bottom of the ngOnInit
function, add the following code:

// Existing code...
@Component({
// Existing code...
})
export class ViewConversationComponent implements OnInit {
// Existing code...
ngOnInit() {
// Existing code...
// Add new subscription below
this.messageSubscriptionGQLService
.subscribe()
.subscribe(this.messageReceived.bind(this));
}
}
Note: The chained calls to what appear to be duplicate subscribe()
methods
is not an error. The first subscribe
is needed to retrieve the observable
that we need to subscribe to.
We should have everything we need to test our Angular subscription. Make sure
your API is running (along with required environment variables from the
setup guide
and run your application with ng serve
(if it's not already running).
Open your browser window and navigate to
http://localhost:4200. If we type a
new message and click send, or send a new message from a downloaded Slack app
(in the channel conversation-1
), the user interface should update instantly
with your new message without the need for a page refresh.
We've done well to build functionality into our new feature. Our application could benefit a lot from focusing on a better user experience.
Next, lets focus on using Angular animations to improve the user experience
Previous page: Create a GraphQL Subscription to send real-time message notifications