官术网_书友最值得收藏!

Time for action – building a data model

Before we can begin implementing data binding, we need a data model to bind to. If you recall, we are only saving the task names to localStorage. Our data model is simply an array of strings. Now that each task has multiple details fields we will need something a little more substantial to hold all of that data. You can find the source code for this section in Chapter 3\example3.2.

Let's start by defining a task object for our data model. We will create a new file, taskList.js to put it in:

function Task(name)
{
    this.name = name;
    this.id = Task.nextTaskId++;
    this.created = new Date();
    this.priority = Task.priorities.normal;
    this.status = Task.statuses.notStarted;
    this.pctComplete = 0;
    this.startDate = null;
    this.dueDate = null;
}
// Define some "static variables" on the Task object
Task.nextTaskId = 1;
Task.priorities = {
    none: 0,
    low: 1,
    normal: 2,
    high: 3
};
Task.statuses = {
    none: 0,
    notStarted: 1,
    started: 2,
    completed: 3
};

Starting from the top, our constructor takes one parameter-the task name. It uses that to set the name field in the object. Each task has a unique task ID, which gets incremented every time a task is created. The rest of the members are set to default values.

We are attaching a Task.nextTaskId field to the Task object constructor to keep track of what the next unique task ID should be. Doing this allows us to define what we would call static or class variables in languages that have classes, such as Java or C# (where they are defined using static variables). The nextTaskId field will get saved to localStorage whenever it changes so that we know where we left off when the user returns to the application.

Notice that priority and status are using enumerations. We implement those as static objects (because JavaScript doesn't have enumerations) attached to the Task constructor.

The next thing we need is a list to store the Task objects in. To make it easier to manage the code for this, we will create a TaskList object that is basically a wrapper over an array. It provides methods to add, remove, and get tasks:

function TaskList(tasks)
{
    tasks = tasks || [];

The constructor takes one optional parameter that is an array of the Task objects. The first line of the constructor checks to see if an array was passed in. If not, it creates a new empty array using empty square brackets ([]).

Note

In JavaScript the logical OR operator (||) can act as a null-coalescing operator. It returns the left-hand operand if the operand is "truthy"; otherwise it returns the right operand. In this case, truthy means that a tasks parameter was passed in and is not null or undefined. This is very useful paradigm for defining default values.

Now we add a public getTasks() method that simply returns the array. We will need access to it later to save the tasks:

    this.getTasks = function()
    {
        return tasks;
    };

Next we add a public addTask() method that takes a Task object and appends it to the end of the array:

    this.addTask = function(task)
    {
        tasks.push(task);
        return this;
    };

The public removeTask() method takes a task ID as a parameter and removes the associated task from the list:

    this.removeTask = function(taskId)
    {
        var i = getTaskIndex(taskId);
        if (i >= 0)
        {
            var task = tasks[i];
            tasks.splice(i, 1);
            return task;
        }
        return null;
    };

It gets the index of the task by calling getTaskIndex(), then uses the array.splice() method to remove it from the tasks array. The getTaskIndex() method is a private method that takes a task ID as a parameter and searches through the array to find the task with that ID. If it finds the task it returns it. Otherwise it returns -1:

    function getTaskIndex(taskId)
    {
        for (var i in tasks)
        {
            if (tasks[i].id == taskId)
            {
                return parseInt(i);
            }
        }
        // Not found
        return -1;
    }

Next up is the public getTask() method. It takes a task ID as a parameter and also uses the getTaskIndex() method to find it. It returns the associated Task object, or null if it doesn't exist.

    this.getTask = function(taskId)
    {
        var index = getTaskIndex(taskId);
        return (index >= 0 ? tasks[index] : null);
    };

The last public method we are going to add is called each(). It takes a reference to a callback function as a parameter. It loops over the array of tasks and executes the callback function for each task in the array. This method can be used to iterate over all tasks in the list:

    this.each = function(callback)
    {
        for (var i in tasks)
        {
            callback(tasks[i]);
        }
    };
}
主站蜘蛛池模板: 灵璧县| 丰镇市| 桃江县| 五华县| 濉溪县| 嘉黎县| 临清市| 收藏| 南溪县| 延吉市| 宽甸| 济宁市| 乌兰县| 新巴尔虎左旗| 托克托县| 定陶县| 桓仁| 和平县| 垫江县| 江口县| 永德县| 永登县| 紫阳县| 鹿泉市| 阜康市| 兴和县| 库伦旗| 康保县| 平山县| 嵩明县| 信宜市| 祥云县| 固阳县| 广河县| 金阳县| 虎林市| 措美县| 江永县| 多伦县| 台山市| 宁蒗|