Hi all,
I'm dealing with a problem regarding the SPA module type and Angular development. Because Angular loads the html views as needed (routing), I am not able to make use of the Token Replace.
In DNN 7 I created a property in codebehind where I collect all information I need (which depends on the specific module) and inject this into Angular as JSON-String:
protected string ModuleProperties
{
get
{
dynamic properties = new ExpandoObject();
using (var rsxr = new ResXResourceReader(MapPath(LocalResourceFile + ".ascx.resx")))
{
var res = rsxr.OfType<dictionaryentry>()
.ToDictionary(
entry => entry.Key.ToString().Replace(".", "_"),
entry => LocalizeString(entry.Key.ToString()));
properties.Resources = res;
}
properties.Settings = Settings;
properties.Editable = ModulePermissionController.HasModuleAccess(SecurityAccessLevel.Edit, "edit", ModuleConfiguration) && IsEditable;
properties.UserId = UserId;
properties.ModuleId = ModuleId;
properties.PortalId = PortalId;
properties.HomeDirectory = PortalSettings.HomeDirectory.Substring(1);
properties.RawUrl = Request.RawUrl;
return ClientAPI.GetSafeJSString(JsonConvert.SerializeObject(properties));
}
}
and inject this into Angular as a JSON string:
<script>
angular.element(document).ready(function () {
function init(appName, moduleId, apiPath) {
var sf = $.ServicesFramework(moduleId);
var httpHeaders = { "ModuleId": sf.getModuleId(), "TabId": sf.getTabId(), "RequestVerificationToken": sf.getAntiForgeryValue() };
var localAppName = appName + moduleId;
var application = angular.module(localAppName, [appName])
.constant("serviceRoot", sf.getServiceRoot(apiPath))
.config(function($httpProvider) {
angular.extend($httpProvider.defaults.headers.common, httpHeaders);
});
return application;
};
var app = init("funStoryApp", <%=ModuleId%>, "BBFunStory_Module");
app.constant("moduleProperties", '<%=ModuleProperties%>');
var moduleContainer = document.getElementById("funStoryApp<%=ModuleId%>");
angular.bootstrap(moduleContainer, [app.name]);
});
</script>
In a DNN 8 SPA module there is no codebehind so this is no more a possible solution. Some of the properties are exposed via the ModuleContext Token (ModuleID etc.) but this is not complete and there is no possibility to get special information that is not included in ModuleContext.
As a first workaround I encapsulated my ModuleProperties as a WebApi method. But because some of the information is needed first before retrieving the data for the module I have to call the Properties first, wait for the result and then I can fetch my data. This is annoying and a backstep in speed and usability in opposite to the DNN 7 approach.
So I came to the idea to use the ModuleContext as a replacement for my ModuleProperties. But that needs a change in DNN. The method to sample all the needed infos could be placed into the BusinessController class with a fixed name. And the class where the ModuleContext is prepared could be extended like this:
switch (propertyName.ToLower())
{
case "moduleid":
return _moduleContext.ModuleId.ToString();
case "tabmoduleid":
return _moduleContext.TabModuleId.ToString();
case "tabid":
return _moduleContext.TabId.ToString();
case "portalid":
return _moduleContext.Configuration.OwnerPortalID.ToString();
case "issuperuser":
return _moduleContext.PortalSettings.UserInfo.IsSuperUser.ToString();
case "editmode":
return _moduleContext.EditMode.ToString();
case "moduleproperties":
if (!string.IsNullOrEmpty(_moduleContext.Configuration.DesktopModule.BusinessControllerClass))
{
Instantiate businesscontroller class 'bcc' with reflection
if (bcc has method 'getModuleProperties')
return bcc.GetModuleProperties();
}
default:
if (_moduleContext.Settings.ContainsKey(propertyName))
{
return (string)_moduleContext.Settings[propertyName];
}
break;
What do you think about this solution ? Is it worth a pull request or isn't this the right way to go for solving my annoying problem ?