我在Angular应用程序中使用了一个Dashboard框架,它有很多指令。
在main指令中,有一些范围函数可以使用ng-click从html模板调用,例如,当用户通过下拉菜单将小部件添加到仪表板时:
<div class="btn-group" ng-if="options.widgetButtons">
<button ng-repeat="widget in widgetDefs"
ng-click="addWidgetInternal($event, widget);" type="button" class="btn btn-primary">
{{widget.name}}
</button>
</div>
但是,我希望能够从我的主控制器代码中调用addWidgetInternal()
。
例如,在处理丢弃事件时,我想通过调用addWidgetInternal
来添加新窗口小部件:
(function () {
'use strict';
angular.module('rage')
.controller('MainCtrl',
['$scope', '$interval', '$window', 'widgetDefinitions',
'defaultWidgets', 'gadgetInitService', initOptions]);
function initOptions($scope, $interval, $window, widgetDefinitions, defaultWidgets, gadgetInitService) {
this.userName = 'Bob';
this.userRole = 'Risk Analyst';
this.descriptionText = 'Risk Engine';
$scope.dashboardOptions = {
widgetDefinitions: widgetDefinitions,
defaultWidgets: defaultWidgets,
storage: $window.localStorage,
storageId: 'rage.ui',
};
// DRAG AND DROP EVENTS
$scope.handleDrop = function () {
// $scope.addWidgetInternal(); // *** CANNOT MAKE THIS CALL DIRECTLY TO OTHER DIRECTIVE !
// **** UPDATE: a work-around to access scope function in 'dashboard' directive
angular.element(document.getElementById('dash')).scope().addWidgetInternal();
}
}
})();
但是在上面调用$scope.addWidgetInternal()
时出现错误:
TypeError: undefined is not a function
这是主仪表板指令的片段 - 具体来说,是link
函数:
link: function (scope) {
scope.widgetDefs = new WidgetDefCollection(scope.options.widgetDefinitions);
scope.addWidgetInternal = function (event, widgetDef) {
event.preventDefault();
scope.addWidget(widgetDef);
};
}
droppable指令如下:
.directive('droppable', function () {
return {
restrict: 'A',
scope: {
drop: '&',
},
require: '?dashboard', // 'dashboard' directive is optionally requested; see 'drop' below
link: function (scope, element, attributes, dashboardCtrl) {
var el = element[0];
el.addEventListener('drop', function (e) {
if (e.preventDefault) { e.preventDefault(); }
this.classList.remove('over');
var item = document.getElementById(e.dataTransfer.getData('Text'));
this.appendChild(item.cloneNode(true));
// call the drop function passed in from the dashboard.html 'drop' attribute
scope.$apply(function (scope) {
var fn = scope.drop();
if ('undefined' !== typeof fn) {
fn(e); // PASS THE EVENT TO CALLING FUNCTION
}
});
return false;
}, false);
}
}
});
这里是dashboard.html视图,其中我放置了droppable和dashboard指令:
<div class="col-lg-12" data-droppable drop="handleDrop">
<div id="dash" dashboard="dashboardOptions" class="dashboard-container"></div>
</div>
我使用的可拖动指令放在<img>
内,如下所示(因此,上述控制器代码中提到的放置事件):
<tr>
<td >
<img data-draggable id="chart_gridhier" src="images/chart_gridhier.jpg" title="TreeGrid" alt="Hierarchy Grid" width="80" height="95">
</td>
<td><img data-draggable "id="chart_area" src="images/chart_area.jpg" title="Area Chart" alt="Area Chart" width="80" height="95"></td>
</tr>
底线:我不是从html视图模板文件中触发ng-click="addWidgetInternal($event, widget);"
,而是需要从控制器触发它。
****更新****
我最终将一些拖放指令逻辑移植到仪表板指令代码中。这样我就可以在与仪表板小部件定义相同的范围内处理DROP事件。
这是dashboard
指令中更新的链接代码:
link: function (scope, element) {
// handle drop event from the gadgets drag-drop operation (see gadgets-include.html)
var el = element[0];
el.ondrop = function (e) {
e.dataTransfer.dropEffect = 'move';
var item = document.getElementById(e.dataTransfer.getData('text'));
this.appendChild(item.cloneNode(true));
var newWidget = _.findWhere(scope.widgetDefs, { name: item.id });
// This will add the new widget div to the dashboard
scope.addWidgetInternal(e, newWidget);
};
}
的问候,
鲍勃
答案 0 :(得分:2)
这通常不是一种强烈推荐的方法来实现这一点,但我发现这可以很方便 - 特别是在集成Angular之外的代码时。
我精心设计了一个简洁的代码,以提供一个可以随意构建的工作演示。基本上,我正在通过id抓住你的元素并且挖掘&#39;进入它的范围,然后调用范围函数。在我的示例中,我将您的chart_area
称为
angular
.element(document.getElementById('dash')).scope().addWidgetInternal();
.scope()
.addWidgetInternal(message);
message
只是我从UI发送的一个字符串,并在指令中的addWidgetInternal()
中注销,从控制器调用