Disclaimer: The code samples contained in this article should be considered as examples only and may require further additions or changes to work in your environment. Docebo does not provide support for the content of this article.
If you are looking for React Native code examples for the embedded learning mobile SDK, please see Embedded learning for React Native.
Introduction
Docebo embedded learning allows you to integrate an instance of your Docebo platform in various platforms such as Web or Mobile (iOS, Android or React Native) mobile applications and more.
The Docebo platform instance opens when the user clicks on a button or interacts with an element - such as a link, or a string - in your application. When embedded learning opens, the platform instance shows the training content you, as the Superadmin, have selected for the user based on the action the user is performing, in order to provide the best learning on the fly experience, enriching it with ad hoc training.
Depending on the embedded learning configuration, users can be automatically provisioned so that their learning in the flow of work is not an event interrupted by the need to log in.
This document is a technical guide on how to insert embedded learning building blocks into your React 18.0.0 web application, it contains three examples of files:
- Embedded learning module:
- A React hook that injects the kernel URL and sets the
DSDK
object - A context provider that holds the
DSDK
object - A component to be used only in areas of your application where embedded learning is used
- A React hook that injects the kernel URL and sets the
- Example component
- Example application
Embedded learning in your React web application
Embedded learning module
This example contains code that provides:
- A React hook that injects the kernel URL and sets the
DSDK
object. - A context provider that holds the
DSDK
object. - A component that should be added only where embedded learning is used in the app
Tip: If you follow these examples and save this code as a file, in order for the following examples to work properly, it should be named EmbeddedLearningModule
and reside in the same folder as the subsequent code examples, otherwise you will need to adjust the path and filenames of the import
statements in the last two code example blocks.
/*
This hook injects the kernel bundle into the DOM head only once and when loaded
starts the kernel
React 18.0.0
*/
import {createContext, useEffect, useState} from "react";
const useDoceboEmbeddedLearning = (kernelUrl, domain, renewToken, setDsdk) => {
return useEffect(() => {
/*
If the <script id="docebo-embedded-learning-sdk" src="[kernelUrl]">
is not present it injects it
*/
if (!document.getElementById('docebo-embedded-learning-sdk')) {
console.info('[useDoceboEmbeddedLearning] Kernel not present, loading it now...');
/*
This piece of code creates the kernel script
*/
const script = document.createElement('script');
script.id = 'docebo-embedded-learning-sdk'
script.src = kernelUrl;
script.async = true;
/*
When loaded it sets the token provider, starts the kernel
and sets the DSDK object in the provider state
*/
script.onload = () => {
console.info('[useDoceboEmbeddedLearning] DSDK is loaded:', window.DSDK);
setDsdk(window.DSDK);
window.DSDK.kernel().setTokenProvider(renewToken);
window.DSDK.kernel().start({
/*
Here you only need to pass the domain/platform parameter
*/
domain
/*
If you need the context and the language parameters
you can add those here but without passing the token,
the setTokenProvider should handle the authentication
(even if the token has expired)
*/
});
}
/*
This line injects the kernel script into the DOM head
*/
document.head.appendChild(script);
} else if (window.DSDK) {
console.info('[useDoceboEmbeddedLearning] DSDK already loaded:', window.DSDK);
/*
If the kernel is present it sets the DSDK object in the
provider state
*/
setDsdk(window.DSDK);
}
}, [kernelUrl, domain, renewToken, setDsdk])
}
/*
This context helps the child components access the DSDK object
*/
export const EmbeddedLearningContext = createContext(null);
/*
This component represents a section in the whole app that uses
embedded learning. It has the "dsdk" provider variable that
references the window.DSDK object if present. This variable is
readable by every component inside EmbeddedLearningModule and
is useful when listening to events or sending commands
*/
const EmbeddedLearningModule = (props) => {
/*
The DSDK object is an API that allows you to handle commands
and events in embedded learning and is only available after
the kernel is loaded
*/
const [dsdk, setDsdk] = useState(null);
/*
Call the useDoceboEmbeddedLearning hook that loads and starts
the kernel if it has not already done so
*/
useDoceboEmbeddedLearning(
/*
The first parameter is the kernel URL
*/
'https://cdn1.dcbstatic.com/flow/kernels/SDKKernel-v1-latest.bundle.min.js',
/*
The second parameter is the domain/platform
*/
'example.docebosaas.com',
/*
The third parameter is the token provider promise
*/
() => fetch('https://example.docebosaas.com/manage/v1/user/login', {
method: 'POST',
body: JSON.stringify({"username": "jon.doe", "password": "pw!123"})
}).then(response => {
return response.json().then(responseBody => responseBody.data.access_token)
}),
/*
The fourth parameter is the setter for the DSDK object
*/
setDsdk
)
return (
<EmbeddedLearningContext.Provider value={dsdk}>
{props.children}
{dsdk && <p><strong>DSDK</strong></p>}
{!dsdk && <p><strike>DSDK</strike></p>}
</EmbeddedLearningContext.Provider>
);
}
export default EmbeddedLearningModule
Example component
This file represents an example widget. In this example, the learner can load other courses into the widget by pressing on the buttons that send commands using the DSDK
API. This file should be named ExampleComponent
in order for the subsequent example file to function as expected and reside in the same folder.
Please note: Please note that this component should be nested inside the previous component and it reads the DSDK
value set by the provider.
import {useContext, useEffect} from "react";
import {EmbeddedLearningContext} from "./EmbeddedLearningModule";
const ExampleComponent = (props) => {
/*
This is the dsdk variable read from the provider
*/
const dsdk = useContext(EmbeddedLearningContext);
useEffect(() => {
let loadCourseRegistration
/*
This hook only kicks in when the DSDK API is available
and sets up an event listener
*/
if (!!dsdk) {
loadCourseRegistration = dsdk.getEventManager().on('course_loaded', (e, p) => {
console.info('[ExampleComponent] Course loaded event triggered', p);
});
}
/*
This event listener should be cleared when the component unmounts
*/
return () => loadCourseRegistration?.clear();
}, [dsdk]);
const onClickCommand = (e) => {
/*
The DSDK API is optional but if it does not exist, the command is
not sent
*/
dsdk?.getCommandBus().send('load_course', 'widget', {
id: e.target.value
}, (e2) => console.info('[ExampleComponent] Load Course command is triggered', e2));
};
return (
<>
<div style={{width: '500px', height: '500px', border: '1px solid black'}}>
<dcbo-course-player id="widget" courseid="181"></dcbo-course-player>
</div>
<ul>
<li>
<button onClick={onClickCommand} value="181">Load course 181</button>
</li>
<li>
<button onClick={onClickCommand} value="182">Load course 182</button>
</li>
<li>
<button onClick={onClickCommand} value="183">Load course 183</button>
</li>
</ul>
</>
);
}
export default ExampleComponent;
Example application
This example application combines everything together in an application. The previous examples are imported in the first two lines of the code, please make sure they are saved in the same location as the Example application and are named as advised, otherwise you may need to adjust the first two import lines of the code for filenames or folder location.
import EmbeddedLearningModule from "./EmbeddedLearningModule";
import ExampleComponent from "./ExampleComponent";
import {useState} from "react";
function App() {
const [page, setPage] = useState('a');
return (
<>
<button onClick={() => setPage('a')} disabled={page === 'a'}>A</button>
<button onClick={() => setPage('b')} disabled={page === 'b'}>B</button>
<hr/>
{page === 'a' && <p>This is page A, embedded learning is only on page B</p>}
{page === 'b' &&
<>
<EmbeddedLearningModule>
<p>This page contains embedded learning</p>
<ExampleComponent></ExampleComponent>
</EmbeddedLearningModule>
</>
}
</>
);
}
export default App;