Я создал директиву, которая на основе значения триггера отображает одно из нескольких комбинаций метки и ссылки действия в div.AngularJS: передать функцию области действия в директиву внутри объекта JSN
Метка и значение триггера указаны в их собственных атрибутах - никаких проблем до сих пор.
Действия, видя, что может быть любое число, определены в атрибуте actions
. Это JSON-кодированный массив объектов, каждый из которых представляет одну возможную ссылку на действие.
Все работает отлично, когда я использую его так:
<record-milestone
label="'Login Details'" test-value="member.login_details_sent"
action="sendLoginDetails(member)"
actions="[
{'test': 'testResult !== null', 'label': member.login_details_sent.toDateString(), 'actionable': false, 'className': 'progressmsgyes'},
{'test': 'testResult === null', 'label': 'Send...', 'actionable': true, 'className': 'progressmsgno', 'default': true}
]">
</record-milestone>
Примечание особенно member.login_details_sent.toDateString()
немного.
Я хочу, чтобы вместо того, чтобы использовать функцию, определенную как часть $scope
для производства этикетки - вот так ...
<record-milestone
label="'Membership Fee'" test-value="member.membership_fee_paid"
action="setDate(member, 'membership_fee_paid')"
actions="[
{'test': 'testResult !== null', 'label': getDateString(member.membership_fee_paid), 'actionable': false, 'className': 'progressmsgyes', 'default': true},
{'test': 'testResult === null', 'label': 'Paid...', 'actionable': true, 'className': 'progressmsgno'}
]">
</record-milestone>
В этом случае метка действия, которые следует принять значение getDateString(member.membership_fee_paid)
пустым , Добавление предупреждения к самой функции показывает, что она вообще не называется. Мое лучшее предположение заключается в том, что директива не рассматривает его как функцию.
Есть ли способ передать функцию области действия в директиву через массив, подобный этому, или я полностью отключен?
Я все еще изучаю AngularJS, и это мое первое усилие в нетривиальной директиве, поэтому я не выше переписывания, если не ошибаюсь.
Остальная часть кода.
recordmilestone.js
/**
* Displays a bar showing a label and value, allowing an action. Action can vary depending on the value.
*
* Attributes:
* - label - The label for the bar
* - testValue - An expression to be evaluated an d compared against the 'test' element of the actions array
* - action - An expression to be executed when the action button is clicked
* - actions - Array of Objects. For each object:
* - 'test' is an expression that is evaluated to determine whether this action is used. This is executed in the
* directive's isolated scope so does not have access to the controller's scope variables. testResult can be used
* to represent the expression in the testValue attribute.
* - 'label' is the label to be displayed for the action button if the test resolves to true,
* - 'actionable' determines whether the action link should be clickable - if true a link is shown, if false it is
* shown simply as text
* - 'className' is the class to apply to the element
* - 'default' (optional) if true, this action is applied if no other rules match. If more than one action is
* specified as default, the last action with `default: true` is used.
*
* Example usage:
* <record-milestone
* label="Stage 1" test-value="stage1.complete" action="item.complete = true"
* actions="[
* {'test': true, 'label': 'Completed', 'actionable': false, 'className': 'progressmsgyes'},
* {'test': false, 'label': 'Mark complete', 'actionable': true, 'className': 'progressmsgno', 'default': true}
* ]">
*
*/
directives.directive('recordMilestone',
[
function() {
//Define the controller
var controller = ['$scope', '$parse', '$rootScope',
function($scope, $parse, $rootScope) {
//Watch the value
$scope.$watch(function() {
return $parse($scope.testValue)();
},
function(newValue) {
$scope.testResult = newValue;
//Evaluate actions array
//Array.some() executes the callback for each element until one returns true. Better than forEach() which
//can't be interrupted
$scope.actions.some(function(action) {
if($parse(action.test)($scope) || action.default) {
$scope.actionLabel = action.label;
$scope.actionLabelBackup = action.label;
$scope.className = action.className;
$scope.actionable = action.actionable;
$scope.uploadAction = action.uploadAction | false;
//Return true if the value matched, false otherwise
return $parse(action.test)($scope);
}
return false;
});
});
$scope.doAction = function() {
$scope.action();
}
$scope.uploadStarted = function(files) {
$scope.actionLabel = 'Uploading...';
}
$scope.uploadFailed = function (response) {
$scope.actionLabel = $scope.actionLabelBackup;
alert("Upload failed: " + response.data.errormessage);
}
}];
return {
restrict: 'E',
templateUrl: '/app/shared/directives/recordMilestoneTemplate.html',
controller: controller,
scope: {
label: '=',
testValue: '&',
actions: '=',
action: '&',
uploadUrl: '=',
uploadComplete: '&'
}
}
}]);
recordMilestoneTemplate.html
<div ng-class="className">
<a ng-if="actionable && !uploadAction" ng-click="doAction()">{{actionLabel}}</a>
<div class="btn-upload"
ng-if="actionable && uploadAction"
upload-button
url="{{uploadUrl}}"
on-upload="uploadStarted(files)"
on-error="uploadFailed(response)"
on-success="uploadComplete(response)"
>{{actionLabel}}</div>
<div ng-if="!actionable">{{actionLabel}}</div>
{{label}}
</div>