Fix Breaking Change InstanceData in v13
Keywords: #Deprecated #InstanceData
2sxc v13 cleans up some historic, deprecated functionality. They were not used much, but if you have code which used this, here's how to fix any code in production.
Specifically, three features were removed:
- The ability to publish Module Instance Data directly
- The ability to configure this in the View settings
- The JS API which was optimized to process the resulting data in a fairly untypical way
Reason for Removal
These features were removed because they were almost never used, and newer mechanisms are much more appropriate than that old stuff.
History - How it Used to Work
2sxc V3 (ca. 2013) introduced a feature where a Module could publish the data it was also showing on a normal screen as a WebApi / JSON call.
It was required that a view activates this feature to ensure that it doesn't happen by accident. The settings in the view were like this (example from the TimelineJs App):
- Go to the view configuration
- The old deprecated settings
- Enable data publishing (which opened the data for JS)
- The streams which were to be published
Note that the stream Default
is still called Default
today, but ListContent
is usually called Header
today.
Once this was setup, there was a way to get this data through a WebApi call.
- From v3 to ca. v6 there was a call which actually went through the Dnn Page (so it was slow)
- V6 to ca. v11 it used a call to
app-sys/AppContent/GetContentBlockData
- Later there was a special WebApi call to
app/auto/InstanceData
which did the same thing
The format of the response was a bit special, specifically it looked like this (TimelineJs example):
- The call to
InstanceData
- The data which was on a special
List
sub-object
To complement this, there was a JS-API which worked as follows:
// Process each Timeline DOM-element on the page
$(".timeline-embed").each(function() {
// Define our timeline element, get moduleId
var timeLineElement = $(this);
var sxc = $2sxc(this);
// Load the data from the 2SexyContent module and define a callback
sxc.data.on("load", function (source, data) {
processDataAndCreateTimeline(source, data, sxc.id, timeLineElement)
}).load();
});
Specifically, it used a data.on
call to kind of say: on load get the data from the current module.
The resulting data was then used in the JS - for example like this in TimelineJS:
// what should happen on loading of the data:
function processDataAndCreateTimeline (data, moduleId, timeLineElement) {
// Old code using the `in`, the `ListContent` and `.List[...]` stream
var content = data.in.Default.List;
var listContent = data.in.ListContent.List[0];
var timelineData = getTimelineData(moduleId, content, listContent);
...
Upgrade to Newer functionality
Tip
Below you'll find instructions how to create the same functionality using Visual Query and newer JS APIs.
But: In many cases you may actually want a different solution, because Visual Query is very powerful and may provide other ways to get you the data you need.
Step 1: Create Query which Gets Instance Data
This creates a Query API call which gets the same data as before, but in a newer API and newer standard.
Create the Query - in our example we'll call it ModuleData
After doing this, you have created a query which returns the same data as before, with 2 important differences:
- The stream
ListContent
is now calledHeader
- There are no permissions configured yet for anonymous users to access the query
Step 2: Update the JS code to use the Query instead of the .data
We have updated the TimelineJS code to use the new fetchJson
api - see docs:
// Process each Timeline DOM-element on the page
$(".timeline-embed").each(function() {
// Define our timeline element, get moduleId
var timeLineElement = $(this);
var sxc = $2sxc(this);
// New version using fetch and the default Query we just created
sxc.webApi.fetchJson('app/auto/query/ModuleData')
.then((data) => processDataAndCreateTimeline(data, sxc.id, timeLineElement));
});
In addition, the data returned is a simpler. Specifically three things are now different:
- it doesn't have a level
in
- it doesn't need the use
.List
- in our new Query the Header is in a stream
Header
and notListContent
This would be the modified code in TimelineJs:
function processDataAndCreateTimeline (data, moduleId, timeLineElement) {
// Re-format streams that are contained in data
var content = data.Default;
var listContent = data.Header[0];
var timelineData = getTimelineData(moduleId, content, listContent);
...
Step 3: Set Query Permissions
After doing Step 1 & 2 you will have a working solution, but only super-users (host-users) can use the query because the read-permissions have not yet been configured. To configure them, use this checklist:
Shortlink to here: https://go.2sxc.org/brc-13-id