2015-08-21 3 views
0

Я создал директиву, которая на основе значения триггера отображает одно из нескольких комбинаций метки и ссылки действия в 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> 

ответ

0

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

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

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

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

Как простой $scope.$watch в атрибуте actions, вызывающий обновление внутренних переменных метки, решила проблему.

Смежные вопросы