AngularJS: передать функцию видимости в директиву внутри объекта JSN

0

Я создал директиву, которая на основе значения триггера отображает одно из нескольких комбинаций метки и ссылки действия в div.

Метка и значение триггера указаны в их собственных атрибутах - никаких проблем до сих пор.

Действия, видя, что может быть любое число, определяются в атрибуте 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 isolated scope so does not have access to the controller 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>

1 ответ

0
Лучший ответ

Нашел решение моей проблемы.

Проблема заключалась не в том, что он не знал, как запустить функцию, определенную в массиве, а в том, что цикл преобразования не был запущен, когда результат функции изменился.

Элемент, определенный в директиве, создается, когда отображаются данные для записи (после щелчка пользователя). Затем следует HTTP GET для извлечения самой информации.

Когда директива сначала создается, значение member.membership_fee_paid является пустым. Директива создается (с пустой меткой из-за недостающего значения), а затем данные заполняются.

Как просто $scope.$watch на actions атрибута заставляя внутренние переменные этикетки для обновления решить эту проблему.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню