Learn More





DNN Community Blog

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.

Deleting Tasks

In the previous entry: "Editing Tasks" we walked through the process of allowing our users to update their own tasks. In this entry we will walk through a similar process, but this time allowing our users to delete tasks if they choose. Keep in mind that users can only edit and delete tasks which are their own.

Creating the DeleteTask Stored Procedure
You probably guessed it already… and if you did that’s awesome… we will first create our stored procedure to delete tasks. The DELETE command is another command that you want to use with caution because depending on how you code it you can potentially delete a lot of data that you don’t want to delete. Delete statements also make use of the WHERE clause. So anytime you find yourself coding out a DELETE script be sure to proceed with caution.

Open SQL server, expand the ModDev2 database (or whatever you named yours), and right click and open a new query window. In order to create the delete task procedure paste in the following code:

    @TaskId int
WHERE  TaskID = @TaskId

In the delete task procedure script above we, again, create the procedure name with a prefix then pass in a parameter of @TaskId because we only want to delete the task when the TaskId being passed in as the parameter equals the TaskId in the task table. This ensures that we will just delete one task.

Updating the SQL DataProvider File
And you probably guessed the next step too… now that we have our stored procedure we need to update our SQLDataProvider file which has some DNN specific syntax as shown below:

The Delete Task SQLDataProvider Code

And here’s the code snippet:

IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'{databaseOwner}[{objectQualifier}CBP_DeleteTask]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
DROP PROCEDURE {databaseOwner}{objectQualifier}CBP_DeleteTask

CREATE PROCEDURE {databaseOwner}{objectQualifier}CBP_DeleteTask
     @TaskId         int
DELETE FROM {databaseOwner}[{objectQualifier}CBP_Tasks]
WHERE  TaskID = @TaskId

Creating the DeleteTask TaskController Class
With our stored procedure correctly functioning we now need to create our DeleteTask Controller class. If you are picking up on our pattern of updating the stored procedure, then controller class, then web service, then the View control then you are learning and that’s good! Of course there’s no written rule that this is the order in which you have to create these. You can obviously create your files in whatever order makes most sense to you. As I think in a linear perspective this method best helps me keep things in line in my mind.

In Visual Studio open up the TaskController.cs file. Just below the “UpdateTask” method add the DeleteTask controller as shown below:

The Delete Task SQLDataProvider Code

And if you want to copy & paste:

public void DeleteTask(int taskId)
            DataProvider.Instance().ExecuteNonQuery("CBP_DeleteTask", taskId);

In this method again we are using the “public void” because no data set is being returned. We pass in the parameter of taskId. Then we create an instance of the DataProvider and call the “ExecuteNonQuery” SQL method and to that method we pass in the string of the stored procedure we want to execute, which in this case is our “CBP_DeleteTask” method that we just created. We also pass in the taskId because the stored procedure is expecting this parameter.

Creating the DeleteTask Web Service
With our TaskController now having the delete method in place we are ready to proceed and create our Web service. In Visual Studio open the WebServices.cs file and just below the UpdateTask method add in the following code:

The Delete Task Controller

And if you want to copy and paste the code:

public class TaskToDeleteDTO
            public int TTD_TaskID { get; set; }

        [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]
        public HttpResponseMessage DeleteTask(TaskToDeleteDTO DTO)
                var task = new Task()
                    TaskId = DTO.TTD_TaskID

                TaskController tc = new TaskController();
                return Request.CreateResponse(HttpStatusCode.OK);
            catch (Exception exc)
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, exc);

Here again we define a class for our data-transfer-object. This “TaskToDeleteDTO” will be an object that holds the taskId for the task that we want to delete. This data for this data-transfer-object will again come from our View.ascx. With the service method code again we include the security access level attribute, the ValidateAntiForgery token, and the request type declaration… this delete will be a POST request as well. Then we create the HttpResponseMessage “DeleteTask” and into it we pass in the “TaskToDeleteDTO” object named DTO.  Within the try/catch block we create a new task object and set the TaskID property. Next we create a new TaskController named “tc” and on that TaskController we call the “DeleteTask” controller method that we just created. Finally we return the HttpStatusCode of “ok” to complete our service code. In the catch block we log any exceptions in case that something does go wrong with our service.

Updating the View.ascx
With all of our other components correctly configured we’re now ready to update the View.ascx file. This update will be fairly simple. Whenever a user clicks the “Edit” link we are currently showing them a cancel and a save button. We are going to update this and also add in a “delete” option.

In the section that has the comments //Append cancel and save options… add in this new line

   $('.TaskList').find('' + EditListItemDiv + '').append('<div class="Delete" id="' + EditClickedID +'">Delete</div>');

Now your code block should look like this:

The Append Delete Link Code

Here again we are using jQuery to find the specific DIV whose edit button was clicked and then we are appending cancel, save, and now delete options to it.

Cancel, Save, & Now Delete
Thus far we’ve created script blocks for when the user clicks both cancel and save after they’ve edited their task. Now we need to add in a block for when the user clicks “Delete”.  Just below the save button code block add in the following snippet:

    $('.Delete').click(function() {
                     var DeleteClickedID = $(this).attr('id');

                         text: 'You sure you want to delete',
                         yesText: 'Yep,delete',
                         noText: 'Cancel',
                         title: 'Delete Confirmation',
                         callbackTrue: function() {


                     function deleteTask(DeleteClickedID) {
                         var taskId = DeleteClickedID;
                         var taskToDelete = {
                             TTD_TaskID: taskId,

                         var sf = $.ServicesFramework(<%:ModuleContext.ModuleId%>);

                             url: '/DesktopModules/MyFirstModule/API/ModuleTask/DeleteTask',
                             type: "POST",
                             contentType: "application/json",
                             beforeSend: sf.setModuleHeaders,
                             data: JSON.stringify(taskToDelete),
                             success: function(data) {

Looking at this code we see that we are again using jQuery to find the unique ID of the delete button that got clicked. This way we’ll know which task should be deleted. We set this value to a variable called “DeleteClickedID”. 

Guarding Against Accidental Deletion
Then you see something new… you see the $.dnnConfirm code block. If you think about it… we’re going to have our delete button very close to our save & cancel button. This is bad user interface design on my part... feel free to update yours as needed ;-) Since this may not be the best user interface a user may try to click save and accidentally click delete… and that wouldn’t be good... so we should probably update the UI, but we can take some steps to guard against accidental deletion and that’s exactly what that $.dnnConfirm is.

Since we aim to guard against accidental deletion we can prompt the user to confirm that they do in fact want to delete the item they just clicked. Looking at the $.dnnConfirm text you see where we can define a few items in this block. We can tell the pop-up what text we want to present to the user, the “yes” action text, the “no” action text, the pop-up title, and finally the callbackTrue actions. In our code example you see where the callbackTrue option has a function defined and that function is where we call the deleteTask function and pass in the taskId of the item to be deleted. So we added one step in the deletion process, but it acts as a safeguard to our users.

Beneath that we’re back to our same way of calling the service framework, but this time we just reference and updated url… the DeleteTask route of our service. Then once we delete the task, again we call our faithful loadTasks() function.

The below video walks through the concepts covered in this blog entry

We have indeed come a long way and I hope that you have learned some things, found this helpful, and been able to get your tasks module functioning correctly. Though we aren’t done just yet… we’ve got 1 or 2 more things we need to discuss and illustrate. We’re going to create a setting for our module. I hope to see you in the next blog entry!

Go to the Next Blog Entry: Giving Our Module a Setting


David Lastra
This is the most easy of all of this tutorial series so far.
Thanks :)
David Lastra Thursday, December 04, 2014 11:52 AM (link)
Patrick Fischer
Need to add .Delete{ cursor: pointer;} to module.css
Patrick Fischer Thursday, January 29, 2015 11:18 AM (link)
James Brown
Link to the series introduction

Link to the previous Blog Entry:
James Brown Monday, June 15, 2015 11:48 AM (link)
dnnConfirm only work when logged in as Host. I'm using version 7.4.1. Can you help me with this?
AYE AYE MON Wednesday, July 15, 2015 12:58 AM (link)
Mark Buelsing
Looking good Clint
Mark Buelsing Saturday, March 19, 2016 4:09 PM (link)

Comment Form

Only registered users may post comments.


2sic Daniel Mettler (124)
Aderson Oliveira (15)
Alec Whittington (11)
Alex Shirley (10)
Andrew Nurse (30)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (21)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (203)
Chris Paterra (55)
Clinton Patterson (28)
Cuong Dang (21)
Daniel Bartholomew (2)
Dave Buckner (2)
David Poindexter (3)
David Rodriguez (2)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (74)
Geoff Barlow (6)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (269)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matthias Schlomann (15)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Mike Horton (19)
Mitchel Sellers (28)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Peter Donker (52)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott S (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Timo Breumelhof (24)
Tony Henrich (3)
Torsten Weggen (2)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (37)
Will Strohl (163)
William Severance (5)
Try Evoq
For Free
Start Free Trial
a Demo
See Evoq Live
Need More Information?