var app = angular.module('testApp', ['ui.bootstrap', 'ui.select']);
app.decorator('uiSelectMatchDirective', function($rootScope, $delegate) {
var originalLinkFn = $delegate[0].link;
$delegate[0].compile = function(element) {
return function(scope, elm, attrs, controller) {
elm.bind('click', function() {
$rootScope.$broadcast('customSelect', scope.$selectMultiple.activeMatchIndex);
});
originalLinkFn.apply($delegate, arguments);
};
};
return $delegate;
});
app.decorator('uiSelectMultipleDirective', function($delegate) {
var originalLinkFn = $delegate[0].link;
$delegate[0].compile = function(element) {
return function(scope, elm, attrs, controller) {
scope.$on('uis:select', function(event, item) {
scope.$selectMultiple.activeMatchIndex = controller[0].selected.length;
});
originalLinkFn.apply($delegate, arguments);
};
};
return $delegate;
});
app.controller('detailsController', function($scope, toolService) {
$scope.assembly = {
tools: []
};
$scope.$on('customSelect', function(event, value) {
$scope.tool = $scope.assembly.tools[value];
console.log('from handler custom select');
});
$scope.$watch('tool', function(value) {
console.log('from watch')
});
$scope.onSelectTool = function(tool) {
$scope.tool = $scope.assembly.tools[$scope.assembly.tools.indexOf(tool)];
};
$scope.tools = toolService.getTools();
});
app.factory('assemblyService', function() {
var assemblies = [{
"Position": 1.00,
"Tools": [{
"Id": 104,
"Type": "Центровочное сверло D10 ∠90°",
"OrderCode": "D5306100",
"Vendor": "YG-1",
"IsConsumables": true,
"Sequance": 14,
"Overhang": 40.00,
"AmountCuttingEdge": 0,
"AmountPlates": 0,
"Durability": 200.00,
},
{
"Id": 53,
"Type": "Термопатрон ",
"OrderCode": "50 10 A63 S",
"Vendor": "POKOLM",
"IsConsumables": false,
"Sequance": 6,
"Overhang": 40.00,
"AmountCuttingEdge": 0,
"AmountPlates": 0,
"Durability": 200.00
}
],
"Runtime": 1.00,
"Note": null
},
{
"Position": 5.00,
"Tools": [{
"Id": 889,
"Type": "Корпус фрезы D42 z5",
"OrderCode": "5 42 367",
"Vendor": "POKOLM",
"IsConsumables": false,
"Sequance": 14,
"Overhang": 43.00,
"AmountCuttingEdge": 2,
"AmountPlates": 5,
"Durability": 90.00
},
{
"Id": 750,
"Type": "Пластина r2",
"OrderCode": "04 67 896 R20 M40",
"Vendor": "POKOLM",
"IsConsumables": true,
"Sequance": 12,
"Overhang": 43.00,
"AmountCuttingEdge": 2,
"AmountPlates": 5,
"Durability": 90.00
},
{
"Id": 890,
"Type": "Патрон ",
"OrderCode": "HSK 63-16-50",
"Vendor": "KEMMLER",
"IsConsumables": false,
"Sequance": 6,
"Overhang": 43.00,
"AmountCuttingEdge": 2,
"AmountPlates": 5,
"Durability": 90.00
}
],
"Runtime": 40.00,
"Note": null
},
{
"Position": 9.00,
"Tools": [{
"Id": 891,
"Type": "Фреза D20 r1",
"OrderCode": "ф20R1z4 nACRo ТП",
"Vendor": "ТЕХНОПОЛИС",
"IsConsumables": true,
"Sequance": 14,
"Overhang": 70.00,
"AmountCuttingEdge": 0,
"AmountPlates": 0,
"Durability": 180.00
},
{
"Id": 223,
"Type": "Термопатрон ",
"OrderCode": "60 20 A63 S",
"Vendor": "POKOLM",
"IsConsumables": false,
"Sequance": 6,
"Overhang": 70.00,
"AmountCuttingEdge": 0,
"AmountPlates": 0,
"Durability": 180.00
}
],
"Runtime": 6.00,
"Note": null
},
{
"Position": 11.00,
"Tools": [{
"Id": 1241,
"Type": "Фреза D12 r2",
"OrderCode": "ф12R2z4 nACRo ТП",
"Vendor": "ТЕХНОПОЛИС",
"IsConsumables": true,
"Sequance": 14,
"Overhang": 55.00,
"AmountCuttingEdge": 0,
"AmountPlates": 0,
"Durability": 180.00
},
{
"Id": 51,
"Type": "Термопатрон ",
"OrderCode": "50 12 A63 S",
"Vendor": "POKOLM",
"IsConsumables": false,
"Sequance": 6,
"Overhang": 55.00,
"AmountCuttingEdge": 0,
"AmountPlates": 0,
"Durability": 180.00
}
],
"Runtime": 40.00,
"Note": null
},
{
"Position": 15.00,
"Tools": [{
"Id": 547,
"Type": "Сверло D5.60",
"OrderCode": "DH451056",
"Vendor": "YG-1",
"IsConsumables": true,
"Sequance": 14,
"Overhang": 25.00,
"AmountCuttingEdge": 0,
"AmountPlates": 0,
"Durability": 100.00
},
{
"Id": 78,
"Type": "Термопатрон ",
"OrderCode": "50 06 A63 S",
"Vendor": "POKOLM",
"IsConsumables": false,
"Sequance": 6,
"Overhang": 25.00,
"AmountCuttingEdge": 0,
"AmountPlates": 0,
"Durability": 100.00
}
],
"Runtime": 3.00,
"Note": null
}
];
return {
getAssemblies: () => {
return assemblies.slice();
}
};
});
app.factory('toolService', function() {
var tools = [{
"Id": 104,
"Type": "Центровочное сверло D10 ∠90°",
"OrderCode": "D5306100",
"Vendor": "YG-1",
"IsConsumables": true
},
{
"Id": 53,
"Type": "Термопатрон ",
"OrderCode": "50 10 A63 S",
"Vendor": "POKOLM",
"IsConsumables": false
},
{
"Id": 889,
"Type": "Корпус фрезы D42 z5",
"OrderCode": "5 42 367",
"Vendor": "POKOLM",
"IsConsumables": false
},
{
"Id": 750,
"Type": "Пластина r2",
"OrderCode": "04 67 896 R20 M40",
"Vendor": "POKOLM",
"IsConsumables": true
},
{
"Id": 890,
"Type": "Патрон ",
"OrderCode": "HSK 63-16-50",
"Vendor": "KEMMLER",
"IsConsumables": false,
},
{
"Id": 891,
"Type": "Фреза D20 r1",
"OrderCode": "ф20R1z4 nACRo ТП",
"Vendor": "ТЕХНОПОЛИС",
"IsConsumables": true
},
{
"Id": 223,
"Type": "Термопатрон ",
"OrderCode": "60 20 A63 S",
"Vendor": "POKOLM",
"IsConsumables": false
},
{
"Id": 1241,
"Type": "Фреза D12 r2",
"OrderCode": "ф12R2z4 nACRo ТП",
"Vendor": "ТЕХНОПОЛИС",
"IsConsumables": true
},
{
"Id": 51,
"Type": "Термопатрон ",
"OrderCode": "50 12 A63 S",
"Vendor": "POKOLM",
"IsConsumables": false
},
{
"Id": 547,
"Type": "Сверло D5.60",
"OrderCode": "DH451056",
"Vendor": "YG-1",
"IsConsumables": true
},
{
"Id": 78,
"Type": "Термопатрон ",
"OrderCode": "50 06 A63 S",
"Vendor": "POKOLM",
"IsConsumables": false
}
];
return {
getTools: () => {
return tools.slice();
}
};
});
<script src="https://code.angularjs.org/1.5.8/angular.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.19.4/select.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-touch.js"></script>
<script src="https://cdn.rawgit.com/angular-ui/bootstrap/gh-pages/ui-bootstrap-tpls-2.5.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.19.4/select.min.js"></script>
<div class="panel panel-default" ng-app="testApp" ng-controller="detailsController">
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-md-3">Инструмент</label>
<div class="col-md-9">
<ui-select multiple ng-model="assembly.tools" limit="100" on-select="onSelectTool($item)">
<ui-select-match placeholder="Введите строку для поиска">{{$item.OrderCode}}</ui-select-match>
<ui-select-choices repeat="tool in (tools| filter:$select.search | limitTo:$select.limit)">
<span ng-bind="tool.OrderCode"></span>
<p class="small" ng-bind="tool.Type"></p>
</ui-select-choices>
</ui-select>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Кол-во режущих граней</label>
<div class="col-md-9">
<input type="number" class="form-control" ng-model="tool.AmountCuttingEdge" />
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Кол-во пластин</label>
<div class="col-md-9">
<input type="number" class="form-control" ng-model="tool.AmountPlates" />
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Вылет</label>
<div class="col-md-9">
<input type="number" class="form-control" ng-model="tool.Overhang" />
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Стойкость</label>
<div class="col-md-9">
<input type="number" class="form-control" ng-model="tool.Durability" />
</div>
</div>
</div>
</div>
</div>
使用装饰器(创建事件)对原始指令进行了细微更改。
$rootScope.$broadcast('customSelect', scope.$selectMultiple.activeMatchIndex);
在控制器中处理此事件
$scope.$on('customSelect', function(event, value){
console.log('from custom select');
$scope.tool = $scope.assembly.tools[value];
});
我也跟随控制器的变化tool使用$watch
$scope.$watch('tool', function(value){
console.log('from watch');
});
我们在下拉列表中选择任意数量的工具,每个添加的位置都会变为活动状态,使用btn-primary引导程序中的一个类。
当您第一次单击控制台中的选定位置之一时,您可以看到事件处理程序已经工作,customSelect这反过来又发生了变化 $scope.tool,但由于某种原因,处理程序不起作用$watch,如果您再次单击相同的元素,您可以在控制台中看到两个处理程序都有效。
告诉我为什么会这样。
问题出在装饰器上。
如果您查看相同的来源
ngClick,您也可以在 jqLite 处理程序内部看到。$evalAsync$apply在你的情况下,你正在做
$broadcast,正如你从源代码中看到的那样,它没有运行$digest,因此没有检查watch因此,您需要自己运行它,例如使用
.$apply().为什么它适用于后续开关:在具有类的元素内部有一个具有类
ui-select-match的元素ui-select-match-item- 具有ng-click.Таким образом при клике, сначала вызывается клик внутреннего элемента, проходит digest цикл, затем шлется твой broadcast и на этом все заканчивается. При следующем клике при проверке
watchопределяет, чтоtoolsизменился с предыдущего запуска digest - и отрисовывает, а затем в обработчике твоего события ты снова меняешь реальное значение tools.