Say I have an object stored in $scope
like so:
$scope.todo = [
{
"title" : "Groceries",
"todoItems" : [
{
"title" : "Milk",
"status" : "Not Done"
},
{
"title" : "Eggs",
"status" : "Not Done"
},
{
"title" : "Bread",
"status" : "Done"
}
]
},
{
"title" : "Medical",
"todoItems" : [
{
"title" : "Make eye doctor appointment",
"status" : "Not Done"
},
{
"title" : "Go to pharmacy",
"status" : "Not Done"
},
{
"title" : "Take vitamins",
"status" : "Done"
}
]
}
];
I am creating a feature that allows inline editing of each todo item, like so:
I achieve this by toggling a property on the todo list item called editMode. See lines 11-14 in the following code block:
<div ng-app="myApp">
<div ng-controller="dashBoard">
<div class="panel panel-default list-[(listID)]" ng-repeat="(listID, todoList) in todo" ng-cloak>
<div class="panel-heading">[( todoList.title )]</div>
<ul class="list-group">
<li ng-repeat="(itemID, todoItem) in todoList.todoItems" data-as-sortable="board.dragControlListeners" data-ng-model="items" class="status-[(todoItem.status)] todo-item todo-item-[(itemID)]" data-as-sortable-item>
<div class="input-group">
<span data-as-sortable-item-handle class="input-group-addon">
<input ng-click="toggleStatus(listID, itemID, todoItem.status)" type="checkbox" ng-checked="todoItem.status == 1">
</span>
<span ng-if="!todoItem.editMode" class="todo-item-label-wrapper">
<div ng-click="toggleEditMode(listID, itemID, 1)" class="todo-item-label">[(todoItem.value)]</div>
</span>
<span ng-if="todoItem.editMode" class="todo-input-wrapper">
<input show-focus="todoItem.editMode" ng-keyup="$event.keyCode == 13 && toggleEditMode(listID, itemID, 0)" type="text" ng-model="todoItem.value" class="form-control">
</span>
</div>
</li>
</ul>
</div>
</div>
</div>
When any given todo item is clicked, it goes into edit mode. The todo item stays in edit mode until the user hits enter. I'd like to make it impossible to have multiple todo items in edit mode at the same time. If you click on todo item "foo" and then click on todo item "bar", todo item "foo" should switch back to read-only mode.
I am currently achieving this by individually switching every todo item with angular.forEach()
, e.g.:
$scope.toggleEditMode = function(listID, itemID, editMode) {
$scope.todo[listID].todoItems[itemID].editMode = editMode;
//Turn off edit mode on every todo item other than the one that was just clicked
angular.forEach($scope.todo[listID].todoItems, function(todoItem, foreignItemID) {
if (foreignItemID !== itemID) {
$scope.todo[listID].todoItems[foreignItemID].editMode = 0;
}
});
}
But I wonder if angular has some utility for this usecase that I should be using.
What I do in such a case is not having an editMode
property on each item, but instead using a scope variable like $scope.currentEditItemId
. Then you do something like this:
$scope.toggleEditMode = function (listID, itemID, enableEdit) {
if (enableEdit === 1) {
$scope.currentEditItemId = itemId;
// ... whatever you need to do here
}
}
And the HTML would look like this:
<span ng-if="itemId != currentEditItemId" class="todo-item-label-wrapper">
<div ng-click="toggleEditMode(listID, itemID, 1)" class="todo-item-label">[(todoItem.value)]</div>
</span>
<span ng-if="itemId == currentEditItemId" class="todo-input-wrapper">
<input show-focus="todoItem.id == currentEditItemId" ng-keyup="$event.keyCode == 13 && toggleEditMode(listID, itemID, 0)" type="text" ng-model="todoItem.value" class="form-control">
</span>