phdcc.Data DNN modules
  search
Powered by FindinSite-MS
Form programmer hooks
phdcc.Data: Overview Examples Getting Started Security Database Versions
phdcc.Data.Form: Form Profile/Register forms Form editing Languages Layout Questions Form hooks Admin
phdcc.Data.View: View  phdcc.Data.List: List phdcc.Data.Search: Search
Last updated: CC 24/5/09

Form hooks for programmers

FormController GetResultSetsForUser

In any DNN program code, you can use the phdcc.Data.Form.FormController method GetResultSetsForUser() to obtain a list of filled-in-forms for a particular user for a specified form. Method GetResultSetsCountForUser() returns the count of forms filled in by the user. For example, you could use the phdcc.CodeModule DNN module to interrogate results from phdcc.Data.Form.

Here are the C# method definitions in phdcc.Data.Form.FormController:
public System.Collections.Generic.List<ResultSetInfo> GetResultSetsForUser(string FormIdName, int PortalId, int UserID, bool ShowDeleted);
public int GetResultSetsCountForUser(string FormIdName, int PortalId, int UserId, bool ShowDeleted);

phdcc.Data.Form.ResultSetInfo and associated classes are defined below.  GetResultSetsForUser() never returns null. The list is ordered with the most recent ResultSets first.

Each time a form's Submit button is pressed, a new ResultSetInfo is generated, each containing a list of ResultInfo individual answers. Use the ResultSetInfo Validates and Authorised properties to determine the state of each ResultSet. You can use the ResultSetInfo Form() method to find the answers provided for individual questions.

Here is some example C# code that builds a list of all the Town answers given by a user on the specified form:
using phdcc.Data.Form;
...
string rv = "Towns:";
FormController fc = new FormController();
List<ResultSetInfo> rsis = fc.GetResultSetsForUser("idAboutPreferences", PortalId, UserID, false);
foreach( ResultSetInfo rsi in rsis)
  if( rsi.Validates) rv += " "+rsi.Form("isQTown");

Use a Session variable to hide an individual question

You can hide a question on a form for an individual user by setting a Session variable to "hidden". For example, use this Visual Basic code to hide the question that has id "idSurveySex":
<% Page.Session("idSurveySex") = "hidden" %>

The question is only hidden while the user's session is stored, so if the user closes their browser and returns later then the session variable will (probably) not be still be set. You might wish to set the session variable in a form hook event handler (see below), or perhaps elsewhere using the phdcc.CodeModule programmable DNN module. If you set a session variable in an onclick handler or during rendering on the same page as a form, then it will be too late to hide the question this time - as the question is hidden during form initialisation.

Form event hooks

You can add to the phdcc.Data.Form functionality by writing ASP.NET VB or C# code that handles various form events. Currently, you can handle these events:

Let us know if you require hooks for other events.

If you output any information that a user provided, please remember to make it HTML safe by calling Server.HtmlEncode().

Writing a form event hook control

VB form hooks do not (now) seem to work in DNN 4 (as Overrides doesn't find matching base class function). C# form hooks work in DNN 4. Both C# and VB form hooks work in DNN 5. Don't know why.

To add your form event hook handlers, write a user control in VB or C#. Upload the file to the DesktopModules\phdcc.Data.Form directory. In the form editor, enter the name of your control in the "Form hook control" box.

Use the following as the basis of a VB user control. Only include methods for the events that you wish to handle. The following code is in a file called FormHookVB.ascx so that it matches the chosen ClassName property (without the extension). The filename must not start with a number and should not contain periods and spaces. Your code will usually also contain the various Import lines.

<%@ Control Language="VB" ClassName="FormHookVB" Inherits="phdcc.Data.Form.FormHookBase" AutoEventWireup="true" %>

<%@ Import Namespace="phdcc.Data.Form" %>
<%@ Import Namespace="DotNetNuke.Entities.Modules" %>
<%@ Import Namespace="DotNetNuke.Entities.Profile" %>
<%@ Import Namespace="DotNetNuke.Entities.Users" %>
<%@ Import Namespace="DotNetNuke.Services.Mail" %>

<script runat="server">

Public Overrides Function FormLoaded(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo) As Boolean
  Return True
End Function

Public Overrides Sub FormEditing(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo, ByVal UserId As Integer)

End Sub

Public Overrides Sub FormStored(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo, ByVal rsi As ResultSetInfo)

End Sub

Public Overrides Sub FormAuthorised(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo, ByVal rsi As ResultSetInfo)

End Sub

Public Overrides Sub UserRegistered(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo, ByVal CreatedUserInfo As UserInfo)

End Sub

Public Overrides Function ResultsDeleted(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo, ByVal UserId As Integer) As Boolean
  Return True
End Function

Public Overrides Sub FormModerating(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo, ByVal UserId As Integer)

End Sub

Public Overrides Sub FormAmending(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo, ByVal UserId As Integer)

End Sub

Public Overrides Sub FormAdding(ByVal viewForm As PortalModuleBase, ByVal form As FormInfo, ByVal UserId As Integer)

End Sub

</script>

If your code does not compile, then the compile error exception and stack trace will be shown in red above the form Admin box if you are in DNN edit mode, ie you are logged in as a DNN administrator.

If there are any runtime exceptions, then these are caught. For ordinary users, these exceptions are not shown. If you are in DNN edit mode, ie you are logged in as a DNN administrator, then the exception and stack trace are shown in red before the form Admin box.

Hook handler parameters

Please consult the DNN documentation or code and the phdcc.Data.Form code for details of these objects. phdcc.Data.Form.ResultSetInfo is detailed below.

phdcc.Data.Form.ResultSetInfo class, VB

Public Property Action() As String
Empty, or "Authorised by 'username'"

Public Property Authorised() As Boolean
True if result is authorised

Public Property FormIdName() As String
Form id

Public Property IPaddress() As String
IP address of the current user

Public Property LangCode() As String
The 'PreferredLocale' code from the DNN profile of the current user

Public Property ResultsetId() As Integer
The id of the added row in DNN database table phdcc_Data_ResultSets

Public Property ResultTime() As Date
Not set correctly at this stage

Public Property UserId() As Integer
The UserId of the person who (originally) submitted the form

Public Property UserName() As String
The UserName of the person who (originally) submitted the form

Public Property Validates() As Boolean
True if the form answers validate

Public Property RegisterAsUserFailed() As Boolean
For 'profile/register' forms, true if the username or email already exists.

Public Results As List(Of phdcc.Data.Form.ResultInfo)
A list of the provided answers, each a phdcc.Data.Form.ResultInfo, detailed below


Public Function Form(ByVal QuestionIdName As String) As String
Returns the answer provided the specified question, or null if not answered. Gets the answer from Results.

Public Function Form(ByVal QuestionIdName As String, ByVal QuestionOptionIdName As String) As String
Returns the answer provided the specified question and option, or null if not answered. Gets the answer from Results.

phdcc.Data.Form.ResultInfo class, VB

Each instance corresponds to a form answer is added as a row to DNN database table phdcc_Data_Results.

Public Property GroupIdName() As String
The group id

Public Property QuestionIdName() As String
The question id

Public Property QuestionOptionIdName() As String
The question option id, or empty

Public Property ResultValue() As String
The user's answer to the question

phdcc.Data.Form.FormInfo class, C#

public enum FormModes
{
    Unknown = 0,
    Loaded = 1,
    UserEdit = 2,
    AdminAddEdit = 3,
    AdminModerateEdit = 4,
    AdminAmendEdit = 5,
};

public PortalModuleBase moduleControl = null;
public FormController objFormController = null;
public FormModes FormMode;
public int LastResultSetId = 0;
public bool LastValidates = false;
public bool LastAuthorised = false;
public List<ResultInfo> LastResults = null;

public bool FormTypeIsProfile();
public bool FormTypeForceRegistration();
public bool FormTypeRequiresAuthorisation();
public bool FormTypeRequiresLoggedOn();
public bool FormTypeSendEmail();

public int ModuleId;
public int FormId;
public string FormIdName;
public int FormType;
public string DefaultLangCode;
public int CreatedByUser;
public DateTime CreatedDate;
public string ThankYouUrl;
public string EmailTo;
public string FormHookControl;
public string CssFile;

public string GetLastResult(QuestionInfo question, string QuestionOptionIdName, out bool AnyLastResults);

FormLoaded event

The FormLoaded event hook is called after the form has been loaded but before the group and question controls are created. If you return false then the form is not generated (even the Admin block is not visible).

FormEditing event

The FormEditing event hook is called if the form is editable, ie when first shown, when validation fails, and after Moderate/Amend pressed. It is called after the form has been loaded and the group and question controls are created (in the page PreRender phase).

FormStored event

The FormStored event hook is called after a user has submitted a form. Property rsi.Validates indicates whether the form validated.

FormAuthorised event

The FormAuthorised event hook is called after a form has been authorised by an administrator.

UserRegistered event

The UserRegistered event hook is called after a user has been created in a Profile/Register form.

ResultsDeleted event

The ResultsDeleted event hook is called when an administrator deletes a results set.

FormModerating, FormAmending, FormAdding events

These event hooks are called when an administrator starts to moderate, amend or add a user's results. The UserId parameter indicates the user, while form.LastResultSetId and form.LastResults indicate the last results.


Complete C# example

The following C# example shows how to handle the FormAuthorised event hook. The code determines if this is the first time that a set of results has been authorised for this user. If so, then it resends the standard email with the user registration details, including their password. This email could be enhanced to show more information using [Custom:0] tokens, eg submitted form values.

The code first inspects the form LastAuthorised and LastResultsAuthorised fields to determine if this is the first set of authorised results for this user. If it is, the DNN UserInfo is retrieved. Normally, the Membership.Password field is blank at this stage, so the code uses a sneaky technique to obtain this direct from the ASP.NET System.Web.Security.Membership class.

The code then uses standard DNN techniques to retrieve a localised email subject and body from the GlobalResources. Note that the password will be replaced with ******* if the user is a SuperUser. Finally, DNN class DotNetNuke.Services.Mail.Mail is used to send the email.

<%@ Control Language="C#" ClassName="FormHookCS" Inherits="phdcc.Data.Form.FormHookBase" AutoEventWireup="true" %>

<%@ Import Namespace="phdcc.Data.Form" %>
<%@ Import Namespace="DotNetNuke.Entities.Modules" %>
<%@ Import Namespace="DotNetNuke.Entities.Profile" %>
<%@ Import Namespace="DotNetNuke.Entities.Users" %>
<%@ Import Namespace="DotNetNuke.Services.Mail" %>

<script runat="server">

public override void FormAuthorised(PortalModuleBase viewForm, FormInfo form, ResultSetInfo rsi)
{
  // Determine if this is the first set of authorised results
  bool FirstSetOfAuthorisedResults = false;
  if (!form.LastAuthorised)
    FirstSetOfAuthorisedResults = (form.LastResultsAuthorised.Count == 0);

  if( FirstSetOfAuthorisedResults)
  {
    // Get DNN user
    UserInfo ui = UserController.GetUser(viewForm.PortalId, rsi.UserId,true);
    // Sneakily get password
    MembershipUser user = Membership.GetUser(ui.Username);
    string pwd = user.GetPassword();
    ui.Membership.Password = pwd;

    // Get subject from GlobalResources
    string Subject = Localization.GetSystemMessage(viewForm.PortalSettings.DefaultLanguage, viewForm.PortalSettings, "EMAIL_USER_REGISTRATION_PUBLIC_SUBJECT", ui);

    // Get body from GlobalResources
    string Body = Localization.GetSystemMessage(viewForm.PortalSettings.DefaultLanguage, viewForm.PortalSettings, "EMAIL_USER_REGISTRATION_PUBLIC_BODY", ui); // pwd will be replaced with ******* if SuperUser

    // Send the email
    string SendMailError = Mail.SendMail(viewForm.PortalSettings.Email, ui.Email, form.EmailTo, Subject, Body, "", "text", "", "", "", "");
  }
}

</script>

Custom question user controls

You can write a user control to show your own custom question - select the control question type. You can program in either VB or C#, following the instructions given here. Your user control must be in the DesktopModules/phdcc.Data.Form directory - the full filename must be specified in the ControlFilename question option.

In essence, your user control must let the user answer a question. The answer is always returned to phdcc.Data.Form as a string. You must get any previously entered value and display it. You must provide custom validation and store the answer string.

For a profile form that has been filled in, the initial display has an "Amend" button with all the questions disabled. The phdcc.Data.Form code automatically disables and enables all of your controls. If there is any special enable handling, then do this job in the Enabled property setter.

phdcc.Data.Form primarily works with ViewState turned off, ie all controls have EnableViewState="false". It is recommended that you follow this practice.

Your user control must be based on phdcc.Data.Form.QuestionUserControlBase and override the following methods and property (defined here in C#):

public virtual void Page_Loading()
Populate your controls, including setting any previous values for Profile forms. Use the QuestionControl qc to access question and form information.

public virtual bool Enabled()
Do any 'Enabled' property handling

public virtual void Crystalise()
In this method, add any code that is required to bring the user interface up to date

public virtual string GetAnswer()
Return a string that contains the user's answer

public virtual void SetAnswer(string answer)
Set the answer: only used if question linked to DNN property Username

public virtual void Validate(bool DoingSubmitValidate, ref bool Validates, ref string CompleteErrorList, ref string ControlToGetFocusId, ref bool DoNotStore)
Validate the answer and do dependency checks, as per the example below

public virtual void Store(QuestionControl.ReportValue reporter, int StoreUserId, string StoreUserName)
Store the answer

Example question user controls - staff type

Available for download (ExampleUserControl.zip) is an example question user control. It is written in Visual Basic (VB) with a separate codebehind file.

The user control displays a list box with five options available for multiple selection. The currently selected items are shown to the right. JavaScript is used to update the display on the right as items are selected.

The control stores the currently selected items as a string, with each selected option appended, comma separated.

The control uses an asp:ListBox control with a hard-coded list of options. The currently selected items are displayed as the InnerHtml of an HTML TD element which has the following attributes to make it usable server-side:
ID="litChosen" EnableViewState="false" runat="server"

The list box has its onchange client-side event handler set to JavaScript function SetStaffSelected. This JavaScript works out which items are selected and re-creates the TD contents to match.

The VB codebehind for the control implements all the required methods and properties - it shows how to do standard tasks such as loading default and previous values, validation and storage.