将函数插入到没有隔离范围的指令中

时间:2017-12-05 18:53:16

标签: angularjs angular-directive

我不确定我是否会以正确的方式进行此操作。我使用的ui-select指令似乎不支持HTML required指令。所以我建立了自己的ui-select-required。似乎我无法使用隔离范围,因为ui-select已经实例化隔离范围。

我想让ui-select-required将函数作为属性。如果属性存在,则应使用此函数的返回值进行验证。如果该属性不存在,那么它应该在存在值时进行验证。这都是组件的一部分。

product_details.js

angular
  .module('ProductComponents')
  .component('productDetails', {
    bindings:{
      product: '=product',
    },
    templateUrl: "/template/admin/products/details",
    controllerAs: 'prodDetails',
    controller: [
      'v3Stitcher',
      'AjaxLoaderSvc',
      'ModelInformationSvc',
      '$filter',
      '$http',
      'current_site',
      function(
        v3Stitcher,
        AjaxLoaderSvc,
        ModelInformationSvc,
        $filter,
        $http,
        current_site
      ){
        var prodDetails = this;

        ...

    prodDetails.templateRequired = function(){
      // Product types requiring a template
      // 3 - customizable_downloadable
      // 6 - static_variable_downloadable
      var productTypes = [3, 6];

      // Specification types requiring a template
      var specificationTypes = ["print_on_demand"];

      if(productTypes.indexOf(prodDetails.product.product_type) > -1){
        return true;
      }
      if(specificationTypes.indexOf(prodDetails.specification.specification_type) > -1){
        console.log('here'); // this gets called
        return true;
      }

      return false;
    };

.directive('uiSelectRequired',function(){
  return {
    restrict:'A',
    require:'ngModel',
    link:function(scope, elem, attrs, ctrl){
      var form = angular.element(document).find('form');
      var input = angular.element(elem.find('input')[0]);
      var requiredFn = scope[attrs['requiredFn']];

      if(requiredFn){
        ctrl.$validators.uiSelectRequired = function(){
          return requiredFn();
        };
      } else {
        ctrl.$validators.uiSelectRequired = function(modelValue){
          return !ctrl.$isEmpty(modelValue)
        };
      }

      form.on('submit', function(){
        if(ctrl.$invalid){
          elem.find('span').removeClass('ng-valid').addClass('ng-invalid');
        }
      });

      elem.on('change', function(){
        if(ctrl.$invalid){
          elem.find('span').removeClass('ng-invalid').addClass('ng-valid');
        }
      });
    }
  };
});

details.slim

label(ng-class="{'label label-danger': prodDetails.templateRequired()}")
  | Template
ui-select(ng-model="prodDetails.product.template_id" name="template" ng-model-options="{ debounce: { default:500, blur: 0 } }" ui-select-required required-fn="prodDetails.templateRequired")
  ui-select-match(placeholder="Search Templates...")
    | {{$select.selected.name}}
  ui-select-choices(position="down" repeat="template.id as template in prodDetails.templates" refresh="prodDetails.refreshTemplates($select.search)" minimum-input-length="1" refresh-delay="0")
    | {{ template.name }}
    br
    | id: {{template.id}}
    br
    | created: {{template.created_at | date : 'yyyy-MM-dd'}}

我遇到的问题是变量requireFn未定义。但是,如果在HTML中我单独发送控制器变量prodDetails,则requireFn具有正确的控制器变量值。

1 个答案:

答案 0 :(得分:0)

我认为你的问题是:

  • 你正在做控制器:' prodDetails'在您的隔离范围和
  • 您希望直接在uiSelectRequired指令的范围内引用该函数

我想如果你改变这个:

var requiredFn = scope[attrs['requiredFn']];

为:

var requiredFn = scope.$eval(attrs.requiredFn);

你应该得到你想要的东西。这假设已将templateRequired属性添加到productDetails组件的控制器实例中。

重申一下,您的问题是您直接在隔离范围本身上寻找属性,并将其添加到控制器参考中。通过执行scope.$eval,您将基本上解析路径prodDetails.templateRequired - 这将有希望解析为您希望首先获得的函数引用。

编辑:因此,评论中您问题的第二部分让我相信您从不需要将功能转换为具有隔离范围的指令。我认为你要做的是有条件地使模板模型成为必需。 Angular已通过必需和ng-required指令为您提供此功能。你在问题中说明这些在ui-select上是不可用的,但它们是" helper"使用ngModel的指令。我相信this是我想要做的事情的一个主要工作示例,我切换到所需的/ ng-required并消除了对自定义指令的需求。