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(); } }; });
В исходную директиву при помощи декоратора внесены незначительные изменения(создание события).
$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()
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.on('click', function(e) {
$rootScope.$broadcast('customSelect', scope.$selectMultiple.activeMatchIndex);
scope.$apply();
});
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();
}
};
});
Почему это срабатывает при последующих переключениях: внутри элемента с классом ui-select-match есть элемент с классом ui-select-match-item - у которого прописан ng-click
Таким образом при клике, сначала вызывается клик внутреннего элемента, проходит digest цикл, затем шлется твой broadcast и на этом все заканчивается. При следующем клике при проверке watch определяет, что tools изменился с предыдущего запуска digest - и отрисовывает, а затем в обработчике твоего события ты снова меняешь реальное значение tools.
Комментариев нет:
Отправить комментарий