我有两个控制器和一个指令。两个控制器都具有相同类型的数据,即过滤器阵列。两个控制器使用相同的函数来操作此数据,但这些函数依赖于this
(具有“控制器为”语法的范围)。如何将这些功能抽象为服务,但将数据存储在控制器中?我想过将范围转移,但正如我读到的那样,这是不好的做法。有什么想法吗?
.controller('CtrlOne', function() {
this.filters = [...]; // this data is unique for controller one
// Want to abstract these into a service
this.isAllSelected = true;
this.handleChangeFilter = function(selected) {
...
}.bind(this);
this.handleShowFilter = function(filter) {
...
}.bind(this);
})
.controller('CtrlTwo', function() {
this.filters = [...]; // this data is unique for controller two
// Want to abstract this into a service
// it is the exact same logic as the other service
// only thing that changes is `this.filters`
this.isAllSelected = true;
this.handleChangeFilter = function(selected) {
...
}.bind(this);
this.handleShowFilter = function(filter) {
...
}.bind(this);
})
.directive('filtering', function() {
return {
restrict: 'E',
templateUrl: 'filtering.html',
scope: {},
bindToController: {
filters: '=',
onChangeFilter: '=',
onShowFilter: '='
},
controllerAs: 'filtering',
controller: function() {
}
}
})
// filtering.html
`
<ul>
<li ng-repeat="filter in filtering.filters"
ng-click="filtering.onChangeFilter(filter)"
ng-show="filtering.onShowFilter(filter)">
<span ng-style="{color: filter.isActive ? 'red' : 'inherit'}">
{{filter.name}}
</span>
</li>
</ul>
`
// Using the filtering directive
`
<filtering
on-change-filter="::ctrlOne.handleChangeFilter"
on-show-filter="::ctrlOne.handleShowFilter"
filters="::ctrlOne.filters">
</filtering>
`
答案 0 :(得分:0)
我最终做了以下操作,但我对其他解决方案持开放态度,因为我不确定这是否是惯用的Angular:
.controller('CtrlOne', function(filterHandler) {
this.filters = [...]; // this data is unique for controller one
this.filterHandler = filterHandler.create(this.filters);
})
.controller('CtrlTwo', function(filterHandler) {
this.filters = [...]; // this data is unique for controller two
this.filterHandler = filterHandler.create(this.filters);
})
.directive('filtering', function() {
return {
restrict: 'E',
templateUrl: 'filtering.html',
scope: {},
bindToController: {
filters: '=',
onChangeFilter: '=',
onShowFilter: '='
},
controllerAs: 'filtering',
controller: function() {
}
}
})
.service('filterHandler', function() {
return {
create: function() {
var isAllSelected = true;
return {
change: function(selected) {
...
},
show: function(filter) {
...
}
};
}
}
})
// filtering.html
`
<ul>
<li ng-repeat="filter in filtering.filters"
ng-click="filtering.onChangeFilter(filter)"
ng-show="filtering.onShowFilter(filter)">
<span ng-style="{color: filter.isActive ? 'red' : 'inherit'}">
{{filter.name}}
</span>
</li>
</ul>
`
// Using the filtering directive
`
<filtering
on-change-filter="::ctrlOne.filterHandler.change"
on-show-filter="::ctrlOne.filterHandler.show"
filters="::ctrlOne.filters">
</filtering>
`
答案 1 :(得分:0)
I was wrong in my comment about using a service. With a service there arises a chiken-egg problem when you need to inject the service before you create the controller. So I just wrote a globally available base controller function-class and here is a fully working runnable example which I believe is self-explanatory:
function BaseController() {
this.message = "Base controller message";
this.init();
// Common constructor code
}
BaseController.prototype = {
someFunction: function() {
// This is to show the output (alert does not work in sandbox)
this.output = this.message;
// Uncomment this to see an alert
// alert(this.message);
}
,init: function(){
throw('Cannot use abstract base class');
}
};
angular.module('myModule', [])
.controller('myFirstController', myFirstController)
.controller('mySecondController', mySecondController);
function myFirstController() {
BaseController.call(this);
}
myFirstController.prototype = Object.create(BaseController.prototype);
myFirstController.prototype.init = function() {
this.message = 'First Controller Message';
}
function mySecondController() {
BaseController.call(this);
}
mySecondController.prototype = Object.create(BaseController.prototype);
mySecondController.prototype.init = function() {
this.message = 'Second Controller Message';
}
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
</head>
<body>
<div ng-controller="myFirstController as ctl">
<button ng-click="ctl.someFunction()">Call method from first controller</button>
<div>
Output: {{ctl.output}}
</div>
</div>
<div ng-controller="mySecondController as ctl">
<button ng-click="ctl.someFunction()">Call method from second controller</button>
<div>
Output: {{ctl.output}}
</div>
</div>
</body>