I have encountered a tricky issue that appears to be simple, but I am struggling to find a solution.
Currently, I am developing a to-do list application using Angular and Angular-Material.
The main part of the application is located in a file named main.html:
<md-content ng-show="mainCtrl.todos.length">
<md-list class="todo_list" flex>
<md-subheader class="md-no-sticky">{{mainCtrl.todoList.label}}</md-subheader>
<acme-todo ng-show="mainCtrl.todos" ng-repeat="todo in mainCtrl.todos track by $index"
text="todo.content" index="$index"></acme-todo>
</md-list>
</md-content>
Within this code snippet, you can see the usage of the acme-todo
directive, which includes a file named todo.html:
<md-list-item layout='row' layout-sm='column' layout-align='center center' layout-wrap>
<i class='material-icons md-avatar'>border_color</i>
<div class='md-list-item-text'><h3>{{mainCtrl.text}}</h3></div>
<div class='md-secondary'>
<md-button class='md-fab md-primary md-small box red-btn'
aria-label='delete' ng-click='mainCtrl.deleteTodo(mainCtrl.index)'>
<i class='material-icons small-icon'>highlight_off</i>
</md-button>
</div>
</md-list-item>
The logic for the acme-todo
directive is defined in todo.directive.js:
(function () {
'use strict';
angular
.module('todoApp')
.directive('acmeTodo', acmeTodo);
function acmeTodo() {
var directive = {
restrict: 'EA',
scope: {
text : '=',
index : '='
},
templateUrl: 'todo.html',
controller : 'MainController',
controllerAs : 'mainCtrl',
bindToController : true
};
return directive;
}
})();
Additionally, there is a file called main.controller.js, where the main controller functionality lies:
(function () {
'use strict';
angular
.module('todoApp')
.controller('MainController', MainController);
function MainController() {
var vm = this;
vm.todos = [];
. . .
vm.addToDo = addToDo;
vm.deleteTodo = deleteTodo;
//vm.todo.content is the ng-model of the input-box
function addToDo() {
if( vm.todo && !_.isUndefined(vm.todo.content)){
pushNewToDo(vm.todo.content);
}
}
function deleteTodo(index) {
vm.todos.splice(index, 1);
}
function pushNewToDo(todo) {
vm.todos.push({ content : todo });
vm.todo.content = '';
}
}
})();
Everything works perfectly except when attempting to delete a to-do item. The
deleteTodo
function receives the correct external$index
from the main'sng-repeat
, but mysteriously, thevm.todos
array is empty at that moment, resulting in nothing being deleted.
If I move all the content from todo.html directly into the place where acme-todo
is used, everything functions correctly.
I also tried using $scope : true
in the directive instead of passing both text
and $index
, but the issue persists.
To replicate the problem, here is a working Codepen. In this pen, I substituted template
for templateUrl
and changed some icons to ensure proper functionality.
Below is an image showing the real application:
https://i.sstatic.net/XY9GE.png
Although directives typically inherit their scope, I am puzzled as to why the todos
array is empty despite sharing scope with the controller.
EDIT
Utilizing a Service
or a Factory
resolves the issue, similar to how it is solved in this CodePen. However, I feel that adding additional logic for such a minor task may be excessive.
Why is the todos array empty even though both the controller and directive share the same scope? How can I rectify this while still using the todo directive approach?