Adding Tasks

Adding Tasks

With task editing now in place, adding the extra functionality to add a new task should be pretty straightforward.

DataAccess

Start by adding a new addTask method to the DataAccess class.

- (DADataTableRow *)addTask {
    // usually our domain logic should be implemented here… 
    DADataTableRow *task = [self.tasksTable addNewRowInEditMode:YES];
 
    //set due date to tomorrow
    task[@"DueDate"] = [NSDate dateWithTimeIntervalSinceNow:86400.0]; 
 
    // default state as not done yet
    task[@"Done"] = @0; 
 
    // default normal priority
    task[@"Priority"] = @2; 
    return task;
}

The main new thing to notice in this code is the call to the DADataTable's addNewRowInEditMode method, which will add a new DADataTableRow to the DADataTable and then possibly put the row into edit mode depending on the boolean value passing in. The rest of the method is simply setting initial values for each of the new row's fields.

The AppDelegate

Add another button to the toolbar and link it up to an IBAction method. In the method, simply call the existing editTask method, but pass in nil for the task.

- (IBAction)addTaskAction:(id)sender {
    [self editTask:nil];
}

Alter the editTask to call the new addTask method on the DataAccess object if the task parameter is nil.

- (void)editTask:(DADataTableRow *)task {
 
  if (!task) {
    task = [[DataAccess sharedInstance] addTask];
  }
  ...
}

Problem

If you now test your sample app and try to add a new task, you will notice there is a problem when you try to save it.

An Error Occurred

While creating the new task, we didn't set the user to whom this task belongs and the User field on the Task table is set to not allow nulls. The problem is that we don't actually have any user details to set this value.

Solution

All changes that are made in the client get passed to Relativity Server inside the Delta objects. There is one delta object per table. Each delta contains one or more changes. Each delta change contains the old (original) and new (modified) values. Within Relativity Server’s business rule scripting model, you can get access to the deltas and changes before Relativity Server processes them. Using techniques similar to how you filtered data coming from Relativity Server, you can now ensure that each new Task has its user field set to the ID of the currently logged on user.

Schema Modeler

Go back to Server Explorer and open Schema Modeler. Expand the SCHEMA tree node and select the Scripts entry. Using the Add Event button, add the beforeProcessDeltaChange script handler.
As its name suggests, the beforeProcessDeltaChange event will be called just before processing a particular change from the delta object for the given table. In this script, you just need to obtain the user ID of the logged in user from the session and update the delta change User field with its value.

// Called before each change is applied to the database
function beforeProcessDeltaChange(delta, change, wasRefreshed, canRemove)
{
  var userId = session['Login.Id'];
  change.newValues['User'] = userId;
  canRemove = false;
}

Try running the application again, add a new Task and hopefully all will work.

Even though the application now works, there is a problem. The beforeProcessDeltaChange script will be run for every change in every delta before it gets processed. If you were to ever start adding records for another table in addition to the Tasks table, this script would try to update a User field on that table as well. You need to solve this by ensuring the delta change is for the tasks table before you try to set the User field.

// Called before each change is applied to the database
function beforeProcessDeltaChange(delta, change, wasRefreshed, canRemove)
{
  if (delta.name == "Tasks") {
    var userId = session['Login.Id'];
    change.newValues['User'] = userId;
    canRemove = false;
  }
}

Finally the script will be setting the User field for every delta change from the Tasks table, even if it's an update. Records that are being updated should already have the User field set from when the record was added, so although it doesn't hurt to set it again, it's not very clean or efficient, so you might want to ensure that the script only sets the User field when the delta is for an insert.

// Called before each change is applied to the database
function beforeProcessDeltaChange(delta, change, wasRefreshed, canRemove)
{
  if (delta.name == "Tasks" && change.isInsert) {
    var userId = session['Login.Id'];
    change.newValues['User'] = userId;
    canRemove = false;
  }
}