JS: The $2sxc Root Object
The $2sxc-object is the core JavaScript object helping you to access data of your view or WebAPIs of your 2sxc-App.
Note
2sxc uses these objects internally for building the edit experience. You only need this if you wish to do custom JavaScript stuff in 2sxc, like retrieve data from a WebApi.
Advanced cases where you need $2sxc:
- When you want to use view-data as an asyc-JS call
- if you wish to work with WebAPI REST calls
- if you want more control over the edit-experience with custom buttons etc.
How to use
- add a script-tag to include the 2sxc.api.min.js
note 1: in edit-mode this happens automatically
note 2: always use lower-case paths and the minified version - call the
$2sxc(...)
constructor to get a sxc-controller for your module (as each module on the page will have an own $2sxc controller) - work with the API of the sxc-controller
Here's a simple example of a template-file:
@Edit.Enable(js: true)
<script>
$(function () {
var modId = 17;
var sxc = $2sxc(modId);
alert("edit mode: " + sxc.isEditMode());
});
</script>
The code above shows
- how to include the api-file in the best way using
@Edit.Enable(js: true)
- how the sxc-object is resolved
- how to ask if we're in edit-mode
The moduleId is usually dynamic, so you can't hardwire it with var modId = 17
into your JS code. This is explained in the next section Initialization.
Initialization of the $2sxc for a Module
We have three initializers:
$2sxc(DomNode)
- recommended$2sxc(moduleId)
- oldest way, very common- a special version for internal use only$2sxc(moduleId, contentBlockId)
The Recommended HTML/DOM-Node Initializer
We recommend the DOM-Node syntax, because in that mode $2sxc will go up through the DOM-tree and find the module it's in (or the content-block), and auto-configure itself. What's nice about this is that this method works without any server-side support (which you need for the other methods). Here's a simple example:
<a onclick='$2sxc(this).manage.run("layout")'>layout</a>
In the above example, the dom-node is given by the current click, which puts the current <a>
node in the this
object.
Here's a JS example:
var x = $(".myApp"); // get ANY dom element inside this 2sxc app
var sxc1 = $2sxc(x); // use it
// the same thing in 1 line
var sxc2 = $2sxc($("#SomeNodeInThePage"));
Note that the simple example above assumes that there is only one item on the page, but there can often be more. So you'll usually need to do something like this
// note that we cannot work before the page-onready.
// so our code is in a $(our-code);
$(function(){
$("some-jquery-selector").each(function(index, element){
var sxc = $2sxc(element);
// now do something...
});
});
The Classic ModuleId method
In this method, you need to get the ModuleId from somewhere, usually provided by the server-side template. In a Token-Template you would use [Module:ModuleId]
and in a Razor-Template it's @Dnn.Module.ModuleID
(large "ID").
The previous code in Tokens would be like:
$(function () {
var sxc = $2sxc([Module:ModuleId]);
alert("edit mode: " + sxc.isEditMode());
})
And the same code in Razor would be like:
$(function () {
var sxc = $2sxc(@Dnn.Module.ModuleID);
alert("edit mode: " + sxc.isEditMode());
})
You can also find an example of finding all of our nodes and initializing them in the TimeLineJS App. If you're interested, here's the js-initializer.
Everything about the Module-Level sxc
Controller
In the module sxc controller you'll read about:
- The API of a module-level controller
- Calling commands, creating toolbars and buttons
- Working with JSON data of the current module
- Working with REST / HTTP Async Stuff
- Working with WebAPI calls, especially to your backend WebAPI in your api-folder
- Calling Queries (from the visual query designer)
Technical Features Explained
Including the $2sxc API JavaScript File
Each template that needs the $2sxc-file when not logged in must include it, to be sure it's always there when needed. Note that we've included various features to prevent duplicate execution.
- if the file is included multiple times, it will only execute once
- if the file is included minified and unminified, it too will only be executed once
- if you need to debug the JS for whatever reason with F12 in the browser a sourcemap is included
- for more advanced debuging, just include the unminified version
Note that the entire code is packed in an IIFE, so the only global variable created is the $2sxc
.
Everything is Cached
We optimized for just about every thinkable situation, so the $2sxc will build a controller-object for a module, but following calls to it will use the cached information. Example:
var sxc = $2sxc(42); // initial call, will build controller for Module 42
var sxc2 = $2sxc(42); // second call, will use cached controller
var sxc3 = $2sxc(domNodeInsideTheModule42); // another call, will also used cached controller
Metadata Needed by $2sxc to Work
The $2sxc object needs a few pieces of information to work properly, which are stored in a JSON in the HTML. So the Module-DIV-Tag is actually enhanced with additional pieces of information. This structure is open and easy to read, but the structure can change from time to time, so don't read/rely on that JSON, use the $2sxc to access any information.
There are even situations where additional metadata in inserted into the HTML rendered by your template. This has to do with inner-content (see next section) and the same "don't rely on the JSON" applies.
Module-Instances and Content-Blocks
This is a very advanced topic, so if you're new - just skip this. Also if you use content-blocks you don't need to understand this, it's just included for completeness.
A 2sxc-module can contain many 2sxc-content-blocks since version 8.4 because an item could have independent, inner content-blocks. Because of this, the controller may need an additional parameter, so instead of $2sxc(moduleId)
it can also use $2sxc(moduleId, contentBlockId)
.
As mentioned above, you never need to work with this, it's included for completeness. Since the now recommended method to initialized $2sxc is not with the moduleId but with a DOM-node, that call will automatically resolve everything correctly.
Additional properties of the $2sxc Controller
- In 2sxc 9.30 a new object
$2sxc.cms
was added - read about it in $2sxc.cms
TODO: document the properties, mention that they won't be stable in future versions
Till we find time to document more, please consult the $2sxc API
Background: How $2sxc works
This is just some info for you to better understand what happens behind the scenes:
How Module-Level Information is found
- When you use
$2sxc(moduleId)
it scans the DOM for the<div>
tag that contains the module with that ID - When you use
$2sxc(htmlNode)
it starts from that node and scans all parents till it finds the<div>
which is the module wrapper - Once it finds that, it knows what module it's for and configures itself
How Page and Portal Information is Found
This is for information the $2sxc needs for WebApi calls. This here applies to 2sxc 10.25+
- It first checks the html-head section for a
meta
tag with the name_jsApi
. If this exists, it contains a JSON with everything it needs. - If that doesn't exist it will retry 3x times (in case the head wasn't ready yet) and otherwise falls back to the old mechanism.
- The old mechanism is to ask DNN and the ServicesFramework for this information. This is always available when you're logged on as an editor, but it's only on the page for anonymous users IF
- ...you are either using the old mechanisms
- ...or your Razor code asked for with
@Edit.Enable(js:true)
Demo App and further links
You should find some code examples in this demo App
- TimeLineJS
- all the JS-apps including AngularJS in the app-catalog
More links: Description of the feature on 2sxc docs
History
- Introduced in 2sxc 04.00
- Enhanced with
cms
(see cms) in 9.30