I'm coming from Backbone and trying to wrap my head around Angular for a new project and would like to get some feedback on whether I'm using it correctly or not.
What I'm trying to accomplish is this: I have a list of items that can be very easily rendered with an ngRepeat
. Each item starts off in an inactive state. When a user selects one of the items it enters into an expanded active state that shows some extra details and controls for working with the currently selected item. The markup for these two states is different enough that adding & removing some CSS classes won't cut it, so I have separate templates for each state.
The approach I've taken is encapsulating this functionality into a directive that can render the two templates. When the item is initially rendered the inactive template is used. When an item is selected (in the example, by checking a checkbox) then the active template is compiled and the resulting markup put into the element's HTML. When the checkbox is unchecked the same happens for the inactive template.
The ngShow
/ngHide
directives won't work for me in this case because there could potentially be lots of these things on the page and my understanding is that ngShow
/ngHide
will render the markup for both states and then show/hide based on some model property. Ultimately only one item will be active at any given time so rendering all that markup for each item only to display one at a time seems wasteful. I also wanted more control over the transition between the inactive & active states.
Is this solution something that would be considered idiomatic Angular or an egregious abuse of directives? Am I exposing myself to any bugs?
The directive:
module.directive("myDirective", ['$compile', '$http', '$templateCache', function($compile, $http, $templateCache) {
function getTemplate(isActive) {
var templateLoader,
baseUrl = 'templates/',
templateMap = {
active: 'checked.html',
inactive: 'unchecked.html'
},
templateUrl = baseUrl + templateMap[isActive ? 'active' : 'inactive'];
return $http.get(templateUrl, { cache: $templateCache });
}
function render(scope, element) {
getTemplate(scope.isActive)
.success(function(html) {
element.hide().html(html);
})
.then(function(response) {
element.html($compile(element.html())(scope)).fadeIn();
});
}
function linker(scope, element, attrs) {
render(scope, element);
scope.onSelected = function() {
render(scope, element);
};
}
function controller($scope) {
$scope.isActive = false;
}
return {
restrict: 'A',
scope: {
item: '='
},
controller: controller,
link: linker
};
}]);
The active template:
<div>
<h1>{{item.description}}</h1>
<p>{{item.details}}</p>
<input type="checkbox" ng-model="isActive" ng-change="onSelected()">
</div>
The inactive template:
<div>
<input type="checkbox" ng-model="isActive" ng-change="onSelected()"> {{item.description}}
</div>
And the view:
<ul ng-controller="TheController">
<li ng-repeat="thing in stuff" my-directive item="thing">
</li>
</ul>