DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • Leveraging Salesforce Using a Client Written In Vue.js
  • How to Use Bootstrap to Build Beautiful Angular Apps
  • Leveraging Salesforce Using a Client Written In Svelte
  • Leveraging Salesforce Using Spring Boot

Trending

  • Debug Like a Pro in 2025: 10 New Eclipse Java Debugger Features to Enhance Your Productivity (With Spring Boot Examples)
  • Exploring Data Redaction Enhancements in Oracle Database 23ai
  • When Caches Collide: Solving Race Conditions in Fare Updates
  • Building an AI Nutrition Coach With OpenAI, Gradio, and gTTS
  1. DZone
  2. Coding
  3. Frameworks
  4. Leveraging Salesforce Using a Client Written In Angular

Leveraging Salesforce Using a Client Written In Angular

In this series article, John Vester introduces an Angular application and NgRx state management to read data from Salesforce for use by a basic component.

By 
John Vester user avatar
John Vester
DZone Core CORE ·
Oct. 07, 21 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
147.3K Views

Join the DZone community and get the full member experience.

Join For Free

In the “Leveraging Salesforce Without Using Spring Boot” article, I navigated the course for introducing a Spring Boot service that would leverage the well-established Salesforce RESTful API. The goal of this service was to act as a middleware layer; that way, clients not written in Salesforce could retrieve and update contact data stored in Salesforce. This backend service implemented its own caching layer to provide a faster response time and also cut down on the number of times Salesforce needed to be called.

In “Leveraging Salesforce Using a Client Written In Svelte,” I introduced a simple client written in Svelte, which made it possible to update the Salesforce data using an inline editor—again, without actually using the Salesforce client.

The “Leveraging Salesforce Using a Client Written In Vue.js” article introduced a client application using the Vue.js framework to further interact with the Spring Boot service. Using Vue.js, the resulting client was not only able to read data from Salesforce but also processed and displayed updates made to the Salesforce data via a server-sent events (SSE) implementation.

The fourth article in the series, “Leveraging Salesforce Using Mobile Applications Written (Once) In React Native,” introduced native mobile applications for Android and iOS devices leveraging a single source codebase written in React Native. This new client offering allowed senior executives to monitor the progress of the Salesforce data. 

In this article, we will use the Angular framework to complete a new feature request. In this example, the same contact data from Salesforce will be utilized in a drop-down list to avoid having a different source of contact data.

Revisiting the Example Use Case

Let’s briefly recap our example use case: The Business Call Center is about to launch a major marketing campaign. However, they recently discovered that the title generated for the list of contacts was incorrect approximately 90% of the time.

A team of interns has been updating contacts using the Svelte client, and the managerial team has been using the Vue.js client to monitor the updates as they occur, complete with server-sent events appearing as toast messages. Executives have been monitoring the progress using their Android and iOS devices from native clients which have been deployed.

The feature team responsible for the new widget product line has realized that they too can benefit from the contact information stored in Salesforce. The following requirements have been added to the widget application:

  1. The new widget form requires a contact field.

  2. The selection options for the contact field will be a drop-down list.

  3. The source data will be a dynamic list of contacts from Salesforce.

  4. Each selection option will present the contact’s full name with their title in parentheses (if available).

  5. As changes are made to contacts in Salesforce, the list of contact selection options should automatically update (including the title value).

The feature team for the widget product line is planning to start this work right away and should have everything they need based upon the results of prior work completed for this series. 

As a point of reference, below is a link to the Spring Boot service which has been used for this entire series:

https://gitlab.com/johnjvester/salesforce-integration-service

Why Angular?

Angular is a TypeScript-based web client framework that is led by Google and fueled by a very large open-source community. Of all the frameworks I have used in this series, Angular is certainly the largest—almost to the point where it may be better to call it a platform. 

Some benefits of using Angular are noted below:

  1. Designed to handle enterprise web applications, accommodating next-generation design patterns, including progressive web applications.

  2. Continues to evolve with a dedicated open-source community. This leads to an impressive bug/resolution time frame and a large library of third-party solutions or dependencies which can be added to any modern Angular project.

  3. Supported by Google, serving as the primary web-client framework for technology powerhouses that include Gmail, Microsoft Office, PayPal, Upwork (freelance program), and Samsung.

Personally, I have been involved with enterprise web applications running in both AngularJS and Angular since early 2014. While Angular is designed to handle large-scale applications, I have been equally successful in using the same framework for small and simple applications.

Getting Started with Angular

For this article, I decided to step outside of my comfort zone by giving version 12 of Angular a try. (As a point of reference, I last used version 9 for the fitness application I wrote for my sister-in-law in my “Using Heroku to Quickly Build a Multi-Tenant SaaS Product” series last year.)

Since my Angular command-line interface (CLI) was still on version 9, I needed to use the following command to upgrade to version 12 of the Angular CLI:

npm install -g @angular/cli

First-time users can use this same command as well. 

Issuing an ng version command provided me with the following results:

Shell
 
     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 12.2.0
Node: 14.15.5
Package Manager: npm 6.14.11
OS: darwin x64

Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1202.0 (cli-only)
@angular-devkit/core         12.2.0 (cli-only)
@angular-devkit/schematics   12.2.0 (cli-only)
@schematics/angular          12.2.0 (cli-only)

To create a new Angular 12 application, I issued the following Angular CLI command:

ng new salesforce-integration-angular

The Angular CLI created the application in a new folder called salesforce-integration-angular. Below is a summary of some of the command’s output:

Shell
 
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS
...
✔ Packages installed successfully.

At this point, I used the `ng serve` command to show the newly created Angular application:

Of course, there is not a lot there, but at least the Angular application started in a matter of seconds.

Adding Some Dependencies

The requirements for the widget application contained an interesting business rule. To avoid having to scroll back to the top of the page, I captured the information below:

As changes are made to contacts in Salesforce, the list of contact selection options should automatically update (including the title value).

This requirement translates to the widget application having to maintain the current state of the contact objects. Meaning, the contact list information always needs to be current.

In the “Leveraging Salesforce Using a Client Written In Vue.js” article, the Spring Boot service was updated to broadcast SSEs as changes were made to the state of the contacts stored in Salesforce. The Angular application will also need to listen to those same SSEs.

However, with the Angular application, I decided to use @ngrx/store, which is a Redux-inspired global state management for Angular applications—powered by RxJS. What this means is that I will wire the SSEs from Spring Boot to maintain the state of Salesforce contacts inside the browser. Then, the widget component can employ a reactive design to always have the latest changes—without having to make another call to the Spring Boot service.

Adding the ngrx/store dependency to the Angular 12 application required a simple command:

npm install @ngrx/store --save

With this single dependency added to the project, I can focus on creating the widget component in Angular.

Creating the Widget Component

For this simple example, launching the Angular 12 application will present a new widget form. Because we’re keeping things simple, the form will look like this:

The model field will be a freeform text field and the contact field will contain a dynamic list of Salesforce contacts, kept up to date via the SSE listeners communicating with NgRx.

Creating a new component using the Angular CLI requires the following command:

ng generate component widget

The Angular CLI responds with the following status updates:

Shell
 
CREATE src/app/widget/widget.component.css (0 bytes)
CREATE src/app/widget/widget.component.html (21 bytes)
CREATE src/app/widget/widget.component.spec.ts (626 bytes)
CREATE src/app/widget/widget.component.ts (275 bytes)
UPDATE src/app/app.module.ts (727 bytes)

As a result, a widget component has been created and is ready to use in the `/src/app/widget` folder of the Angular 12 application.

Configuring NgRx 

Rather than include all of the necessary information around configuring NgRx here, the following link to the NgRx website provides a great amount of detail:

https://ngrx.io/guide/store#ngrxstore

Part of this documentation includes the following diagram:

At a high level, we’ll add the following elements to the Angular 12 application:

  1. ContactService: to make API calls to Spring Boot, allowing for us to receive contacts.

  2. EventService: to make the connection to the SSE URI running in the Spring Boot service.

  3. ContactEffect: to register event listeners and load the original contacts from the Spring Boot service.

  4. ContactAction: to describe the events that are dispatched from the ContactService.

  5. ContactReducer: to ensure the state changes are being processed.

  6. ContactSelector: to select and derive contact information from the store.

  7. WidgetComponent: to listen to the ContactAction and receive data from the ContactSelector.

Let’s dive into the code and see how this looks in TypeScript.

ContactService

The ContactService handles making basic API calls to the Spring Boot service that has been used throughout this series. The Angular 12 client will simply make a call to the /contacts URI and return an “observable” containing a list of contact objects:

TypeScript
 
export class ContactService {
  constructor(private http: HttpClient) { }

  getContacts(): Observable<Contact[]> {
    return this.http.get<Contact[]>( environment.api + '/contacts')
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }
}

EventService

The EventService establishes a connection to the URI in Spring Boot which is broadcasting SSE updates. I added the getServerSentEvent() method to make the connection:

TypeScript
 
getServerSentEvent(): Observable<any> {
    return Observable.create((observer: { next: (arg0: any) => void; error: (arg0: any) => void; }) => {
      const eventSource = this.setSource();
      eventSource.onmessage = event => {
        this.zone.run(() => {
          observer.next(event);
        });
      };
      eventSource.onerror = error => {
        this.zone.run(() => {
          observer.error(error);
        });
      };
    });
  }

When a SSE arrives, the _onMessage() method is called:

TypeScript
 
private _onMessage(e: MessageEvent): void {
    const message = JSON.parse(e.data);
    if (message) {
      this.dispatchActionInNgZone(processSseUpdate(message));
    }
  }

This in turn dispatches the action into the NgZone:

TypeScript
 
private dispatchActionInNgZone(action: Action): void {
    this.zone.run(() => this.store.dispatch(action));
  }

ContactEffect

The ContactEffect registers an event listener to the EventService, updates contacts from SSE messages that are received, and loads the original contacts from the Spring Boot service.

TypeScript
 
registerEventListener$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(ContactActionTypes.AllContactsLoaded),
        tap(action => {
          this.eventListenerService.register();
        }),
        repeat()
      ),
    { dispatch: false }
  );

  updateContactFromSSE$ = createEffect(() =>
    this.actions$.pipe(
      ofType(processSseUpdate),
      map( payload => {
        const anyContact:any = (payload as any);
        const contact = (anyContact as Contact);
        const updatedAction:Update<Contact> = {
          id: contact.id,
          changes: { ...contact }
        };
        return new ContactUpdated({contact: updatedAction});
      })
    )
  );

  loadAllContacts$ = this.actions$.pipe(
      ofType<AllContactsRequested>(ContactActionTypes.AllContactsRequested),
      mergeMap(() => this.contactService.getContacts()),
      map(contacts => { new AllContactsLoaded({ contacts })} )
    );

ContactAction

The ContactAction describes the events that are dispatched from the ContactService.

TypeScript
 
export enum ContactActionTypes {
  AllContactsRequested = '[Contact API] All Contacts Requested',
  AllContactsLoaded = '[Contact API] All Contacts Loaded',
  ContactUpdated = '[Contact API] Contact Updated'
}

export class AllContactsRequested implements Action {
  readonly type = ContactActionTypes.AllContactsRequested;
}

export class AllContactsLoaded implements Action {
  readonly type = ContactActionTypes.AllContactsLoaded;
  constructor(public payload: { contacts: Contact[] }) { }
}

export class ContactUpdated implements Action {
  readonly type = ContactActionTypes.ContactUpdated;
  constructor(public payload: { contact: Update<Contact> }) { }
}

export type ContactActions = AllContactsRequested |  AllContactsLoaded | ContactUpdated;

ContactReducer

The ContactReducer makes sure the state changes are processed.

TypeScript
 
export function contactReducer(state = initialContactsState, action: ContactActions): ContactsState {
  switch(action.type) {
    case ContactActionTypes.AllContactsLoaded:
      return adapter.setAll(action.payload.contacts, {...state, allContactsLoaded: true });
    case ContactActionTypes.ContactUpdated:
      return adapter.updateOne(action.payload.contact, state);
    default: {
      return state;
    }
  }
}

WidgetComponent

Finally, the WidgetComponent leverages all the NgRx state-management elements to provide a dynamic and self-updating list of contact information from Salesforce via the Spring Boot service and SSE URI.

The ngOnInit() method connects to the NgRx store, then receives the original list of contacts:

TypeScript
 
ngOnInit(): void {
    this.widget.model = "Some Model Description Goes Here";

    this.contactService.getContacts().subscribe((data) => {
      this.store.dispatch(new AllContactsLoaded({ contacts: data }));
      this.loading = false;
    });
  }

With the NgRx implementation in place, updates will be processed as they are received from the Spring Boot service over the SSE URI.

To make sure the Widget component is displayed when Angular starts, I reduced the app.component.html file to a single line:

<widget></widget>

Using the Angular Application

Using ng serve from the Angular CLI, we start up the Angular 12 application with all of the above changes in place. 

This displays the widget form, showing the contact data from Salesforce in the drop-down list:

Using the following cURL command, I updated the title for Rose Gonzales from “SVP, Procurement” to “SVP, Information Technology.”

Shell
 
curl --location --request PATCH 'http://localhost:9999/contacts/0035e000008eXq0AAE' \
--header 'Content-Type: application/json' \
--data-raw '{
    "Title": "SVP, Information Technology"
}'

The PATCH command resulted in an HTTP status code of 202 (Accepted) and returned the following payload:

JSON
 
{
    "attributes": {
        "type": "Contact",
        "url": "/services/data/v52.0/sobjects/Contact/0035e000008eXq0AAE"
    },
    "id": "0035e000008eXq0AAE",
    "Name": "Rose Gonzalez",
    "Title": "SVP, Information Technology",
    "Department": "Procurement"
}

Without making any changes to the widget form, the drop-down list options now appear like this:

Notice how the contact title changed automatically for Rose Gonzalez.

Conclusion

Starting in 2021, I have been trying to live by the following mission statement, which I feel can apply to any IT professional:

“Focus your time on delivering features/functionality which extends the value of your intellectual property. Leverage frameworks, products, and services for everything else.”

- J. Vester

In this article, I created a widgets component using Angular 12 which included a drop-down list of contacts populated with data from within the Salesforce implementation. I added NgRx state-management functionality to listen for SSE messages from Spring Boot in order to keep the list of contacts current. In this case, I leveraged the powerful NgRx state-management framework to do the work for me—requiring very few changes to the widget component at all.

Similar to my experiences with Svelte, Vue.js, and React Native, the time to create a ready-to-deploy component was very fast, measured in minutes rather than hours. Just like in all of this series’ articles, we have been able to use Salesforce without actually using a Salesforce client.

Of course, a production-ready scenario would require some additional work to prepare this application for “prime time” use.

If you are interested in the source code used for the Angular client, simply navigate to the following repository on GitLab:

https://gitlab.com/johnjvester/salesforce-integration-angular

In the next article of this series, I plan to turn things 180 degrees and use Lightning Web Components (LWC) outside the Salesforce ecosystem. 

Have a really great day!

AngularJS Spring Framework mobile app Spring Boot Contacts (Apple) Command-line interface Web Service Data (computing)

Opinions expressed by DZone contributors are their own.

Related

  • Leveraging Salesforce Using a Client Written In Vue.js
  • How to Use Bootstrap to Build Beautiful Angular Apps
  • Leveraging Salesforce Using a Client Written In Svelte
  • Leveraging Salesforce Using Spring Boot

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: