DNN has been plagued with slow editing experience since DNN 3 - mostly because of the WebForms Postback system. 2sxc has fixed most of this by now, getting all UI actions to flow in less than 1 second; and Content-updates all reload immediately using AJAX. But for most DNN modules and 2sxc-Apps this is more complex but easy. I've lost many sleepless nights getting this to work, and hope that I can help you by sharing this.
The Challenges of Complex-Content (Modules/App)-AJAX
- Loading Mechanisms
- The ones in charge when your module or App is added to the page
- The ones in charge of updating the screen when the editor makes changes to content or configuration
- Loading JS resources when the app is added normally
- Preventing problems with multiple loading of JS resources (like if other modules also had the resources loaded)
- Starting the JS initializer, because document.ondocumentready already happened a while before
- Preventing previously initialized items to not double-initialize and do something unexpected
Step 1: Loading Mechanism
The loading mechanism is possibly the most difficult, because there are so many strategies you can use. Basically you need something around your module/app/view/template, which handles the AJAX aspects. We'll look at these cases
- Dynamic Content (templated dynamic content-items or content-lists using 2sxc & Razor/Tokens)
- Apps (bundles of data / views / logic / web-api in 2sxc using Razor / Tokens)
- SPA Apps (JS based Single Page Applications in 2sxc using any JS framework like AngularJS)
- DNN SPA Modules (only in DNN 8+)
- DNN Modules (mostly WebForms based, possibly with MVC)
1.1 Standard Dynamic Content AJAX
This is the freebie. Because 2sxc since version 7.0 automatically loads all Dynamic Content views/templates using AJAX within fractions of a second.
1.2 Apps AJAX (Token or Razor Based)
This is added in 2sxc 8.4.4 and also a freebie. All you have to do is enable the AJAX switch in the App Configuration and you're good to go (see image).
Note that this setting is disabled by default because many apps need some optimizations / testing. So we wanted to be sure that the stable behavior is the default.
1.3 SPA Apps AJAX
For standard SPA Apps there are various possibilities. The trivial way is to just enable the AJAX like for Apps. If you SPA was any good to start with, it will automatically support this use case as well, since any good SPA is meant to load properly and initialize the correct state based or URL-Routing.
But there are two cases where you may want something else:
- If you want to get your SPA to perform AJAX by itself on content-changes, and not just reload the entire app, then your SPA must register itself in 2sxc to handle the AJAX. This is not yet standardized but will be implemented soon.
- If your SPA doesn't behave correctly because it doesn't place its state in the URL then the AJAX-reload will often reload a view which isn't the one you expected. The basic recommendation is to fix your SPA to track its state in the URL - as you should for any modern SPA because of SEO and more. If you don't want to do this, then you too should register in 2sxc to handle the AJAX reloads yourself - which will be added soon.
1.4 DNN 8+ SPA Modules (AngularJS, etc.)
1.5 DNN Modules (WebForms / MVC)
This is a LOT of work - sorry :(. DNN itself simply doesn't provide much to get you going quickly. DNN offers some basics, but implementing it can easily take 2-10 days, depending on the scale of your module. Here's what you'll have to do:
- Start with a server side service (WebAPI) which delivers the content-parts you want to reload by AJAX. Depending on your solution you'll want to provide rendered HTML or JSON data (if you just want to load the data). You can imitate much what 2sxc does - the HTML-rendering is currently done in the [todo] while the module-level data is provided by the [todo]. Note that this may require a LOT of refactoring under the hood to get this to work reliably, and you'll have to invest some time with security issues.
- Rework your editing / dialog cycle, as the default cycle opens DNN pages (containing server controls) which when complete, will re-load the page. You will probably want to:
- …switch to JS based dialogs (also a good thing to prepare for .net Core) - but you can skip this if it's too much work for now
- …open the dialogs in a way that doesn't call the page-reload but some of your own code, to then do the AJAX refresh
- Note that re-loading can be very complicated, so do spend some time with the 2sxc implementation. For example, there are cases where only some HTML is replaced, while in other cases everything incl. the module-state in the browser must be flushed
1.5+ Alternatives if you're using WebForms or MVC
- You're probably much faster to just convert your module to a SPA-App or a 2sxc App and ride the existing infrastructure. But in case you want to stick to WebForms (not supported by 2sxc) then this manual path is the way to go.
- There is also a secret trick to bypass everything using jQuery.load - which allows you to actually load the entire page but then only pick the parts you want and insert it into the existing DOM. It's fairly messy and not recommended, but could be a temporary option
- There is another secret trick where you can load a page with only one module (the one you want to AJAX) and leave away the skin and everything - using an mid=[moduleid] parameter and a bunch of stuff, which looks a bit like this
[your page]?mid=[your mid]&dnnprintmode=true&SkinSrc=%5bG%5dSkins%2f_default%2fNo+Skin&ContainerSrc=%5bG%5dContainers%2f_default%2fNo+Container
this can be combined with jQuery.load to build a viable AJAX solution, but it's fairly hacky.
The main thing you should cover is that basically all JS things should check if they had already been initialized, and if yes, they should not initialize again. There are many libraries to do things like this, but the very basic aspect is to check if something exists, which the JS creates, and only run the code if this is missing. Something like this (wrapped in an IIFE as best practice):