Purely in context of situation. Let's take an example of dynamically changing title tags and page view:
.config(['$routeProvider','$locationProvider',function($routeProvider,$locationProvider){
$routeProvider.when('/', {
template: '/views/home.html',
title:'Home'
});
$locationProvider.html5Mode(true);
}]);
.controller('app', ['$scope','$route','$location',function($scope,$route,$location){
$scope.$on("$routeChangeSuccess",function($currentRoute,$previousRoute ){
$scope.title = $route.current.title;
$scope.page = $route.current.template;
});
}]);
Now both our title and page view are being dynamically loaded in through app level controller that wraps our application. This can be very useful.
<html lang="en" ng-controller="app">
<head>
<title>{{title}}</title>
</head>
<body>
<ng-include src="page"></ng-include>
</body>
</html>
Here's an example of when not to use it. Let's say one of our partial pages return data from an API:
<!-- search.html -->
<div ng-repeat="item in items">
{{item.title}}
</div>
And in our app level controller we are pulling data via broadcast:
$scope.$on('searchComplete',function(d){
$scope.items = d
});
That partial will show the data as we intended however - problems could arise when other child partials use items where scope is being overwritten.
<!-- other-search.html -->
<div ng-controller="OtherSearch" ng-click="search()">
<div ng-repeat="item in items">
{{item.title}}
</div>
</div>
In this partial, ng-click is guiding the users request. So if the app level controller already binded items in the parent, the user will see a list of items when toggling to this partial even if they never triggered the action of search().