Accessing a control add-in in a dependency extension

Long time no see, eh? Time flies, what do you know…

I am thrilled to still find you here. Honestly, I wasn’t sure this morning if I was about to even find this blog where I left it seven months ago. Cool to find both my blog and you in good shape, patiently waiting for my contribution.

This morning I had a call with a partner asking if it was possible to deploy a control add-in in such a way that other partners could use its functionality from their own extensions. My answer was, and it still is – well, it should be possible, but I don’t know for a fact because I never tried it.

So let’s try it and find the answer together.

(It goes without saying, but I’ve learned that things that “go without saying” often don’t, so let me go with saying it: this is about Extensions V2, NAV 2018, and Business Central; no NAV 2017 stuff here. And no animals were harmed while during writing of this blog, yet…)

To keep my partner safe and anonymous, and stay GDPR compliant in and out, let’s imagine this imaginary scenario: you are building a cool horizontal feature that does “things” in the back end, but also exposes a little bit of front-end sugar for other NAV partners to consume. So you want to make your control add-in accessible to them.

If this was all about pure AL – it’s a no brainer. Your workflow is as follows:

  1. Create and build your extension
  2. Ship your .app file together with your app.json manifest file to your partners.

Your partners, who want to tap into your functionality from their extension, need to do this:

  1. Create their extension
  2. Make your .app file available in their package cache path
  3. Use the information from your app.json to declare a dependency on your extension from their app.json

If your extension uses publicly accessible stuff, such as a table or a codeunit, or events, your partners can now tap into this functionality from their extension (by reading your table, or calling your functions, or subscribing to your event publishers).

But what if you also make a control add-in a part of your extension? Let’s try it out together.

Creating the “horizontal” extension (the “dependency”)

Let’s get the first part done. The “your” part where you are creating your extension that includes a control add-in to expose to your partners. Your amazing new control add-in will expose a button, that will have a caption of your choosing, and will allow your partners to respond to its click event. Crazy stuff, right?

I’ve got myself a nice and fresh VM this morning from aka.ms/getnav to have access to latest CU (being CU6 from June 6). You may want to get one for yourself, too.

Once it’s up and running, start VS Code, and run the “AL: Go!” command from the command palette. Then choose the “BaseExtension” as its name, select “Your own server” as the server, enter your username (mine was “admin”), enter your password (mine was, whoops, I am not telling you what it was!).

When it’s done, which takes like a half a femtosecond, you have your launch.json file open. Go back to your landing page in IE, or access it from the desktop if you closed it) and copy the last four lines from it (under “launch.json settings” subsection) and paste it inside of your launch.json (make sure to overwrite those same settings in there, which is all settings after “name” and before “startupObjectId”). Also, set the “startupObjectId” to 50100 to run your first page.

If you did it correct, you’ll get something like this:

SNAGHTML2a47603d

A few more housekeeping steps:

  • Delete the HelloWorld.al file
  • Edit the app.json file to declare your extension. Mine changed the name, the publisher, and the idRange sections, and it now looks like this:
    image

Now, time for the real stuff. Create a new file and name it “ControlAddIn Base Control.al”

In it, request some real estate from the app, declare a startup script and a “normal” script, then declare a procedure to set a caption on the button, and two events (one to indicate the control is ready, and one to include the implementation for your declared methods). If you care, declare a stylesheet file to make it look nice, too.

If you are as good as I am, yours will also look more or less like this:

image

Rats! I am not that good – there’s red stuff in here. Let’s fix it.

Create two folders, call one “Scripts”, and another one “Styles”, and in them, create the files as declared in your control .al file. Mine are “startup.js”, “baseControl.js”, and “baseControl.css”.

This takes care of the “red stuff” in the control add-in object (it may require you to close and re-open the editor tab for the control add-in object, though).

Now put beef in these files as indicated in the screenshots below.

image

This one was tough! It calls the OnControlReady event when the control add-in starts. Now, let’s get the easier ones done, too.

image

This is your implementation. It contains one function to set caption, as declared in your control add-in object file. It’s not the smartest piece of JavaScript code ever written, but gets the job done. If there is no button, it creates one, sets its caption, and saves the reference for future use. The button, when clicked, invokes the OnClick event, duh!

And last, but certainly the least and entirely optional, add some CSS juice to get rid of Times New Roman:

image

(Times New Roman makes my toenails curl up)

Finally, let’s test if this works as expected. Create a “Page 50100 Test Control.al” file and populate it with bare minimum of al to try this out:

image

Ctrl+F5, sign in once to deploy your control add-in, then sign in once more to, well, sign in to your NAV, and then perform this complex set of steps:

image

So, we did it, or so it seems.

Now, you are good to deploy this to your partners.

Deploying it to your partners

To deploy it to your partners, just do this:

  1. Take your app file (mine is “Vjeko.com_Control Add-in Base_1.0.0.0.app”) and your “app.json” file
  2. Send them to your partners.
  3. Done.

Using your partner’s control add-in

Time to put your partner’s shoes on. You are now not you anymore; you are now your partner, the one who uses your extension. Yes, I confused myself, too, I tend to do this.

First thing, create your extension, the one that will (try to) consume your partner’s shiny button control add-in.

It’s easy, “AL: Go!” once again, follow the same first bunch of steps as you did earlier, up to deleting the HelloWorld.al file.

First step, sort out the app.json manifest file. This time (apart from using a different control add-in range, which should go without saying, but doesn’t, just in case) you need to declare a dependency on the Base Extension you (when you were your partner) created earlier. To do that, use the info from the “app.json” file you received from your partner. This is what I’ve got:

image

Now, to make it simpler, run the “AL: Download symbols” command, to get the symbols files stored in your package cache path. If you didn’t do anything fancy, it should be right inside your workspace, under .alpackages. Now, select any of the .app files inside your .alpackages folder, press Alt+Shift+R to reveal the .alpackages folder in Explorer, and then paste the .app file you received from your partner right in there together with the two files already in place. Now, if you are doing this from the same machine, that file will already be there, because VS Code was smart enough to download that file together with base NAV files automatically.

Good, now let’s try to see if we can use the control add-in your partner extension exposes.

Create a “Page 50110 Test Partner Control.al” file and add al code to define the page that, well, at this stage, attempts to use your partner’s control add-in. For all I care, it can be the exact copy of the original page 50100 from the previous workspace, save for the object ID and name, which should be 50110 “Test Partner Control”. If you didn’t care more than I did, this is what you have at this stage:

image

Last step, change the startupObjectId from 22 to 50110 inside your launch.json file, cross your fingers, close your eyes, and press Ctrl+F5. Okay, if you can’t do it with your eyes closed, open your eyes, position your left pinky on Ctrl, your left middle finger on F5, close your eyes, and click.

(you may open your eyes now…)

image

Yaay! It works!

Really, I didn’t expect anything less, but now I know for a fact. And so do you. You’re welcome!

Vjeko

Vjeko has been writing code for living since 1995, and he has shared his knowledge and experience in presentations, articles, blogs, and elsewhere since 2002. Hopelessly curious, passionate about technology, avid language learner no matter human or computer.

This Post Has 19 Comments

  1. ajkauffmann

    Ever seen the _Exclude_ClientAddIns_ extension that is shipped with Business Central? It serves exactly the same purpose: it contains a control add-in (for OAuth) that can be adopted in your own extension.

    1. Vjeko

      Now I have 🙂

  2. Vincent Vancalbergh

    As fate would have it, I was asking myself that very question yesterday. Thanks Vjeko!

    1. Vjeko

      I don’t know what the problem with accepting Enter key for a JavaScript add-in you are experiencing, can you please elaborate? I am pretty sure that whatever you are trying to do should work and is possible.

  3. Ignacio Pablo

    Hello Vjeko

    Thank you for the example. I downloaded it from GitHub to try but I can’t make it work in any version. I’m using a docker.

    Greetings

    1. Vjeko

      Probably you are missing the applicationarea property.

  4. Ignacio Pablo Cerdán

    Hi

    I found my mistake.

    I was missing the application area.

    Thanks for the post.

  5. vkv1986

    Hi Vjeko,
    I would like to learn more about Control Add-In Development in AL and I decided to use the “Base Extension” as starting point. I installed it and I can open the “Test Control” page, but the “Click me!” button doesn’t appear. I am using microsoft/bcsandbox:gb sandbox on local server (al-2.0.43900.vsix). Can you please help me to solve this issue.
    Many Thanks!

    1. Vjeko

      Did you set the application area property?

  6. Davide

    Hi Vjekoslav, do you know if version in dependencies is “Strictly” mandatory? I mean, it must be exactly the same of the main app, or it could be from that version above (i.e Dependency 1.0.0.2 is good for app 1.0.0.2, 1.0.0.3, 1.0.0.4, 1.0.1.0, 1.1.0.0 and so on)

  7. c4r10k4

    On a October release of BC this code not found. Does anyone know if something needs to be changed?

    1. Vjeko

      Sorry, what code isn’t found there?

  8. Armela Kamenica

    Hello there.
    I am using the same idea to be able to reference another extension. So I am extending an extension. I was able to define the dependency , download the symbols and create a page extension to a new page I created via the first APP.I thought this would work, but I get an error message when I try to publish my new extension..
    So I have already publixhed Extension AppName and I am trying to publish the second one.

    Here is error message

    “The request for path /NAV/dev/apps?SchemaUpdateMode=synchronize failed with code 422. Reason:
    Cannot synchronize the extension because no synchronized extension could be found to satisfy the dependency definition for Appname by AK 1.0.0.7.

    Any ideas ?

    1. Vjeko

      Hi,

      Sorry, no I don’t know what is going on here, I can only offer the lame excuse “it worked for me”. Maybe you should contact Microsoft Support and see if they can solve it for you.

      /Vjeko

Leave a Reply