Building a React front end in Business Central

Why on earth would you want to do that?

That, honestly, still is one of my reactions when I work on this project. Fair warning to you, dear reader, this is very much still a work in progress. What I am going to share in this blog post will hopefully help someone to realize the power of React front ends and help that someone get started. Don’t expect a glib demo style bit of code though, I am just going to try to inflict my learning curve on you. Or at the very least help someone to get started with React.

So why React? Mostly because I want to be able to create better looking and more interactive user interfaces than the standard page lets me. Don’t get me wrong, I think the way we define pages in Business Central is genius and it has been for the past 40 years. There are some cases however where it just falls short. In the past few years there have been enough of those that I started to build Control Add-Ins with JavaScript. React is just a logical progression of that. I’ll let someone else explain what React is.

ReactJS is an open-source JavaScript library which is used for building user interfaces specifically for single page applications. It’s used for handling view layer for web and mobile apps. React also allows us to create reusable UI components. React was first created by Jordan Walke, a software engineer working for Facebook. React first deployed on Facebook’s newsfeed in 2011 and on Instagram.com in 2012.

React allows developers to create large web applications which can change data, without reloading the page. The main purpose of React is to be fast, scalable, and simple. It works only on user interfaces in application. This corresponds to view in the MVC template. It can be used with a combination of other JavaScript libraries or frameworks, such as Angular JS in MVC. Source.

In my opinion this says it all. “specifically for single page applications”, “web applications which can change data, without reloading the page”, and “fast, scalable, and simple” just screams Control Add-In to me. Microsoft itself uses React in its new UI Fabric framework. I expect us to see a lot more of that in the near future.

How to get started? Before making it as far as building an extension there are some steps you need to take first. If you are completely new to HTML, CSS, and/or JavaScript I highly recommend doing the codecademy courses first. To get started with React follow the add React to a website and the tutorial instructions.

In this blog post I won’t go into the building of a Control Add-In and its initial setup. If you are interested there is a ton of stuff out there on Google. Hat tip to Vjeko and Arend-Jan for posting stuff that helped me. And to a ton of more or less anonymous Stack Overflow posters. Where would we be right?

The nitty gritty

This is by no means a comprehensive How To. I will just describe the interaction between React and Business Central. If you want to know more just get in touch or check the GitHub project.

First thing I did was to create two VS Code projects, one for my extension, one for my React project. In my React project I added Node.js so I can use JSX. JSX is an easier way to create HTML code in JavaScript. With it you can simply write HTML in JavaScript. JavaScript code will be placed in parentheses.

JSX, and with it the second VS Code project, is completely optional. I just prefer using it. The only requirement is to have Node.js installed on your computer. To add JSX to your React project go to your project folder in the terminal, and paste these two commands (source):

Step 1: Run npm init -y
Step 2: Run npm install babel-cli@6 babel-preset-react-app@3

You start the compiler from the VS Code terminal. I find it useful to build straight to the Scripts folder of my extension:

npx babel --watch src --out-dir "~path to my extensions~\reactpages\React Pages\Objects\Scripts" --presets react-app/prod

The first thing i create in my extension is a Control Add-In on a page. Mine looks like this:

 controladdin ReactPageControlAddinRED
{
    Scripts =
        'https://unpkg.com/react@16/umd/react.development.js',
        'https://unpkg.com/react-dom@16/umd/react-dom.development.js',
        'Objects/Scripts/reactPageFunction.js';
    StartupScript = 'Objects/Scripts/reactPageStart.js';

    StyleSheets = 'Objects/Css/reactPage.css';

    HorizontalStretch = true;
    HorizontalShrink = true;
    MinimumWidth = 250;

    procedure InitControls(FieldList: JsonArray; Data: JsonArray; PageActions: JsonArray);
    procedure ValidationResult(FieldKey: Integer; Data: JsonArray; LastError: Text);
    event ControlReady();
    event ValidateField(FieldKey: Integer; Data: JsonArray);
    event HandleAction(Data: JsonArray; PageAction: JsonObject);
    event UpdateRecord(Data: JsonArray);
} 

From top to bottom there are some things I want to draw you attention to.

The first two scripts are needed to make React work. Please don’t use these for production. When deploying, replace “development.js” with “production.min.js”.

My reactPageFunction.js contains my React classes. The startup script just calls the reactPageFuntion.js. The reason for doing is is to be able to host the JavaScript elsewhere. It is not possible to host the startup script elsewhere so this is my solution for that problem.

My procedures are used to move data from my page to my JavaScript. events work the other way. On this particular page I send a FieldList with its data and an ActionList. React will display the fields and actions I define in the JSON arrays. The React code to do this looks like this:

window.InitControls = function(fieldList, data, actions) {
  ReactDOM.render(
    <FieldList
      fieldList={fieldList}
      data = {data}
      actions = {actions}
    />,
    document.querySelector('#controlAddIn'),
  )
}

From top to bottom this event creates a function that will render my React component. It renders the FieldList class that I have created earlier and appends it to the Control Add-In div that the Business Central page created for us.

The FieldList class has a state in which I load the three JSON arrays. this state is what we manipulate and what ultimately determines what React shows on the screen.

class FieldList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      fields: Object.values(this.props.fieldList),
      data: Object.values(this.props.data),
      actions: Object.values(this.props.actions),
    }
  }

If I want to validate the content of a field in React I call the ValidateField event of my Control Add-In which validates the field and sends the validated data back to React.

Microsoft.Dynamics.NAV.InvokeExtensibilityMethod("ValidateField", [e.target.dataset.id, newData])

In a bit of typical React magic I added a listener for the ValidationResult procedure inside the componentDidMount function. In this function I call the setState to update the state of my React class. That is what renders the changes on the page. The fun thing about React is that while the underlying Business Central page is validating my React component will remain responsive. I can even start typing in another field and everything will work perfectly!

componentDidMount(){
  window.ValidationResult = (fieldkey, data, lastError) => {
    let newData = Object.values(data);
    this.setState({data: newData});
    let fields = [...this.state.fields];
    if (lastError)
    {
      fields[fieldkey].errorMessage = lastError;
    } else {
      fields[fieldkey].validated = true;
      fields[fieldkey].errorMessage = null;
    }
    this.setState({ fields : fields });
  }
}

In the calling and handling of the validation I also set the validated boolean of the field to false and then true. This allows me to display a nice loading image on my HTML form while Business Central is validating the field. Same for the error message, when there is an error in validating the field React will display an error message based on the state of the React Class. Finally to display the fields on the React Component I call the fieldsForm which renders everything into a form.

I won’t go into the details on how to make a React form work. In this blog I wanted to focus on the integration of React with Business Central. If you want to know more about React forms I suggest reading this. Some quick highlights though.

 fields.map((val, idx) => { }

This loops through the fields array.

 { fields[idx].validate && fields[idx].validated ?  [some new div]  : null } 

The question mark in JavaScript is a ternary operator. This line is basically an if statement, you could write it like this. Null in this case means don’t display anything.

if (fields[i].validate && fields[idx].validated) {
  [some new div]
} else {
  null
}

Add a little CSS magic and the result is this:

Annotation 2019-10-22 214647

This is of course a very very brief description of what I made. You can find the full project on GitHub.

Some final thoughts. First, there are people who are working on extensions that will allow you to create really nice UI elements in Business Central without mucking about with JavaScript. If you are interested in this please send me a message and I will get you in touch with them.

Second, and blindingly obvious, I am not a React developer (yet). I am only learning and sharing what I learned. If you have anything to add please create a pull request on GitHub. I welcome collaboration.

Third, as I mentioned before, this is a work in progress. I will share more when I learn more.

Fourth, it is of course entirely possible to create a React frontend outside of Business Central using the APIs. Or even to call the APIs from inside a Control Add-In. That will be a new blogpost. Stay tuned!

Photo by Greg Rakozy on Unsplash

Lees ook:

Create a custom Email Scenario For Business Central

Today I had to send a specific email from Business Central from a specific backoffice account. Roberto Stefanetti has written...

A monumental event, part 2

I will show you a simple process that I have automated with the Azure Event Grid and Logic Apps, sending...

A monumental event, part 1

An introduction to event driven architecture in relation to Business Central. You will read about why I use serverless back...
ticket system
Skip to content