A lot of times your application will have lists of items that will grow or shrink depending on user interaction. For this example we'll expand upon the first post and create a list of tasks. We'll create an observable array and then output it onto the page.
First let's define the Task class. It has task name, percent complete and is complete fields.
class Task { public taskName = ko.observable(""); public pctComplete = ko.observable("0"); public isComplete: KnockoutComputed<boolean>; constructor() { this.isComplete = ko.computed(() => this.pctComplete() === "100"); } }
Now let's take a look at the view model for our app. It has app name and tasks fields.
class AppViewModel { public appName = "Task List"; public tasks = ko.observableArray<Task>(); }
Notice that the "tasks" field is defined as an observable array of Task objects. That means it is now being tracked by Knockout so whenever we add another task to the list it will update the page. The next thing we need is a way to add a task to the array. Let's create addTask and reset functions.
class AppViewModel { //... public addTask(): void { var task = new Task(); task.taskName("Task " + this.tasks().length); this.tasks.push(task); } public reset(): void { this.tasks([]); } }
In our addTask function we create a new Task object, set its name to the length of the tasks array, then add it to the end of the array using push(). Notice that to get the underlying array from a Knockout observable you have to execute the tasks function, e.g. tasks(). Just like any other observable it's a getter/setter.
We also added a reset function. This removes all of the tasks from the array by setting the tasks property to an empty array.
Now let's go and write some markup that will display the task list on our page.
<body> <h1 data-bind="text: appName"></h1> <button data-bind="click: addTask">Add Task</button> <button data-bind="click: reset">Reset</button> <div data-bind="foreach: tasks"> <div> <input type="text" data-bind="value: taskName" /> % Comp:<input type="number" min="0" max="100" step="1" data-bind="value: pctComplete" /> <input type="checkbox" data-bind="checked: isComplete" disabled />Completed </div> </div> </body>
In our markup we define two buttons with click events. One calls the addTask() function in our view model and the other calls reset(). Next we define a div element with a foreach binding set to the tasks array. Now everything inside that div will be repeated for each Task object in the array.
Notice that when inside of a foreach we are in the context of the current element of the array. Therefore we can get the name of the current task by using "value: taskName" as well as the other properties of the Task object.
OK, we have everything we need so let's try it out. If we click the Add Task button a new task will appear on the page with the name "Task 0". If we click the button again another task will appear and so on.
If you click the Reset button all of the tasks will be removed and the page updated.
Observable arrays in Knockout make it easy for us to create dynamic lists if elements on a page. With only a few lines of code we were able to create an interactive list of tasks. Just remember, an observable array object is a wrapper over a JavaScript array, not an array itself.
<jmg/>