在AngularJS中使用带有自定义指令的不同控制器?

时间:2016-08-31 15:17:03

标签: javascript angularjs angularjs-directive

我创建了一个搜索框,用于两个不同的视图,一个用于搜索作业,另一个用于搜索公司。我为两者和单独的服务制作了两个独立的控制器。

这是搜索框的html -

<span class="searchButton"><i class="fa fa-search fa-2x"></i></span>
<input ng-change="companies.search()" 
       ng-model="companies.searchTerm" 
       ng-keydown="companies.deleteTerm($event)" 
       type="text" id="search-box" 
       style="width: 0px; visibility:hidden;"/>

这是我用来设置样式的脚本 -

<script type="text/javascript"> 
var toggleVar = true;
    $('.searchButton').on('click', function() {
        if(toggleVar) {
            $('.searchButton').animate({right: '210px'}, 400);
            $('#search-box').css("visibility", "visible");
            setTimeout(function() {
                $('.searchButton').css("color", "#444444");
            }, 200);
            $('#search-box').animate({ width: 185 }, 400).focus();
            toggleVar = false;
        }
        else {
            $('#search-box').animate({ width: 0 }, 400);
            $('.searchButton').animate({right: '25px'}, 400);
            setTimeout(function() {
                $('.searchButton').css("color", "#eeeeee");
            }, 300);
            toggleVar = true;
        }
    });

    $('#search-box').focusout(function() {
        if(!toggleVar) {
            $('#search-box').animate({ width: 0 }, 400);
            $('.searchButton').animate({right: '25px'}, 400);
            setTimeout(function() {
                $('.searchButton').css("color", "#eeeeee");
            }, 300);
            toggleVar = true;
        }
    });
</script>

控制器 -

angular.module('jobSeekerApp')
  .controller('CompaniesallCtrl', ['getAllCompanies', function (companiesService) {
    var ctrl = this;
    var count;
    ctrl.pageNumber = 1;
    ctrl.searchPageNumber = 1;
    ctrl.isSearching = false;
    ctrl.searchTerm = "";

    // Initial page load
    companiesService.getCompanies(ctrl.pageNumber)
      .then(function(response) {
        ctrl.companiesList = response.data.results;
        count = response.data.count;
        checkCount();
      }, function(error) {
        console.log(error);
      });

    // User clicks next button
    ctrl.getNext = function() {
      // If search is not being used
      if(ctrl.searchTerm === "" && ctrl.isSearching === false) {
        ctrl.pageNumber = ctrl.pageNumber + 1;
        companiesService.getCompanies(ctrl.pageNumber)
          .then(function(response) {
            ctrl.companiesList = ctrl.companiesList.concat(response.data.results);
            checkCount(); 
          }, function(error) {
            console.log(error);
          });
      }
      // If search is being used
      else {
        ctrl.searchPageNumber = ctrl.searchPageNumber + 1;
        companiesService.searchCompany(ctrl.searchPageNumber, ctrl.searchTerm)
          .then(function(response) {
            ctrl.companiesList = ctrl.companiesList.concat(response.data.results);
            checkCount();
          }, function(error) {
            console.log(error);
          });
      } 
    };

    // User backspaces to delete search term
    ctrl.deleteTerm = function (event) {
      if(event.keyCode === 8) {
        ctrl.searchTermLen = ctrl.searchTermLen - 1;
      }
      // If search box is empty
      ctrl.isSearching = ctrl.searchTermLen !== 0;
    };

    // User clicks search button
    ctrl.search = function() {
      ctrl.searchTermLen = ctrl.searchTerm.length;
      // If search box is empty, show normal results
      if(ctrl.searchTerm === "" && ctrl.isSearching === false) {
        ctrl.pageNumber = 1;
        companiesService.getCompanies(ctrl.pageNumber)
          .then(function(response) {
            ctrl.companiesList = response.data.results;
            count = response.data.count;
            checkCount();
          }, function(error) {
            console.log(error);
          });
      }
      // If search box is not empty, search the input
      else {
        ctrl.isSearching = true;
        ctrl.searchPageNumber = 1;
        companiesService.searchCompany(ctrl.searchPageNumber, ctrl.searchTerm)
          .then(function(response) {
            ctrl.companiesList = response.data.results;
            count = response.data.count;
            checkCount();
          }, function(error) {
            console.log(error);
          });
      }
    };

    // Function to hide and show next button
    function checkCount() {
      console.log(count);
      $(".nextButton").toggle(count > 10);
      count = count - 10;
    }
  }]);

我正在尝试为此制定一个指令,因为所有这些代码都是针对两个视图重复的。但是如何使指令与不同的控制器交互。我如何使这部分ng-change="companies.search()" ng-model="companies.searchTerm" ng-keydown="companies.deleteTerm($event)"不依赖于控制器。 我是角色的新手,我不确定这是正确的方法还是我应该让代码分开?请帮忙。

2 个答案:

答案 0 :(得分:1)

服务器端搜索逻辑使其变得简单

如果您的搜索逻辑可能驻留在服务器上,并且只需在URL中设置查询变量就可以区分搜索作业或公司,那么就很容易了。您可以使用带有属性的1个搜索指令来说明要搜索的模块,并将其包含在您的HTTP请求中。

客户端搜索逻辑略微更具角度

如果您需要针对每种类型的搜索使用不同的客户端逻辑,请考虑这种方法,其中有1个常用search指令,以及每个自定义搜索的1个指令。

  1. 通用搜索指令控制视图+常用搜索功能

  2. 搜索公司指令restrict: 'A'require: 'search'并执行特定于公司搜索的功能

  3. 一个也是restrict: 'A'require: 'search'的搜索作业指令,并执行特定于求职的功能

  4. 概念是自定义搜索指令将其控制器/ api对象提供给公共搜索指令。公共搜索指令处理视图 - 控制器交互并调用提供的API函数以实现自定义搜索功能。

    在代码中,这可能类似于:

    angular.module('SearchDemo', [])
    .directive('search', function(){
        return {
            restrict: 'E',
            templateUrl: '/templates/search.tpl.html',
            controller: ['$scope', function($scope){
                $scope.results = [];
    
                this.setSearchAPI = function(searchAPI){
                    this.api = searchAPI;
                };
    
                $scope.doSearch = function(query){
                    $scope.results.length = 0;
    
                    // here we call one of the custom controller functions
                    if(this.api && angular.isFunction(this.api.getResults)){
                        var results = this.api.getResults(query);
    
                        // append the results onto $scope.results
                        // without creating a new array
                        $scope.results.push.apply($scope.results, results);
                    }
                };
            }]
        };
    })
    .directive('searchCompanies', function(){
        return {
            restrict: 'A',
            require: ['search', 'searchCompanies'],
            link: function(scope, elem, attr, Ctrl){
                // here we pass the custom search-companies controller
                // to the common search controller
                Ctrl[0].setSearchAPI(Ctrl[1]);
            },
            controller: ['$scope', function($scope){
                // you need to design your common search API and 
                // implement the custom versions of those functions here
    
                // example:
                this.getResults = function(query){
                    // TODO: load the results for company search
                };
            }]
        };
    })
    .directive('searchJobs', function(){
        return {
            restrict: 'A',
            require: ['search', 'searchJobs'],
            link: function(scope, elem, attr, Ctrl){
                // here we pass the custom search-jobs controller
                // to the common search controller
                Ctrl[0].setSearchAPI(Ctrl[1]);
            },
            controller: ['$scope', function($scope){
                // you need to design your common search API and 
                // implement the custom versions of those functions here
    
                // example:
                this.getResults = function(query){
                    // TODO: load the results for job search
                };
            }]
        };
    });
    

    在模板中使用它看起来像:

    <search search-companies></search>

    <search search-jobs></search>

    对一个指令进行多次搜索

    如果您需要一个搜索指令来搜索公司和工作,这个概念可以轻松扩展。

    更改将是将搜索控制器的this.api转换为数组。

    angular.module('SearchDemo', [])
    .directive('search', function(){
        return {
            restrict: 'E',
            templateUrl: '/templates/search.tpl.html',
            controller: ['$scope', function($scope){
                $scope.results = [];
    
                // this.api is now an array and can support 
                // multiple custom search controllers
                this.api = [];
                this.addSearchAPI = function(searchAPI){
                    if(this.api.indexOf(searchAPI) == -1){
                        this.api.push(searchAPI);
                    }
                };
    
                $scope.doSearch = function(query){
                    $scope.results.length = 0;
    
                    // here we call each of the custom controller functions
                    for(var i=0; i < this.api.length; i++){
                        var api = this.api[i];
                        if(angular.isFunction(api.getResults)){
                            var results = api.getResults(query);
    
                            $scope.results.push.apply($scope.results, results);
                        }
                    }
                };
            }]
        };
    })
    .directive('searchCompanies', function(){
        return {
            restrict: 'A',
            require: ['search', 'searchCompanies'],
            link: function(scope, elem, attr, Ctrl){
                // here we pass the custom search-companies controller
                // to the common search controller
                Ctrl[0].addSearchAPI(Ctrl[1]);
            },
            controller: ['$scope', function($scope){
                // you need to design your common search API and 
                // implement the custom versions of those functions here
    
                // example:
                this.getResults = function(query){
                    // TODO: load the results for company search
                };
            }]
        };
    })
    .directive('searchJobs', function(){
        return {
            restrict: 'A',
            require: ['search', 'searchJobs'],
            link: function(scope, elem, attr, Ctrl){
                // here we pass the custom search-jobs controller
                // to the common search controller
                Ctrl[0].addSearchAPI(Ctrl[1]);
            },
            controller: ['$scope', function($scope){
                // you need to design your common search API and 
                // implement the custom versions of those functions here
    
                // example:
                this.getResults = function(query){
                    // TODO: load the results for job search
                };
            }]
        };
    });
    

    在模板中使用它看起来像:

    <search search-companies search-jobs></search>

答案 1 :(得分:0)

您必须将数据源或服务传递给指令并从那里绑定事件。

<body ng-app="customSearchDirective">
  <div ng-controller="Controller">

  <input type="text" placeholder="Search a Company" data-custom-search data-source="companies" />
  <input type="text" placeholder="Search for People" data-custom-search data-source="people" />

  <hr>
  Searching In: {{ searchSource }}
  <br/>
  Search Result is At: {{ results }}
</div>
</body>

在此示例中,我使用data-source传递数组,但您当然可以使用服务。

然后你的指令应该使用scope属性将你在source中作为参数传递的内容分配给指令的范围。

您将使用elem参数中的指令输入绑定所需的所有参数。

(function(angular) {
  'use strict';

  angular.module('customSearchDirective', [])


  .controller('Controller', ['$scope', function($scope) {
    $scope.companies = ['Microsoft', 'ID Software', 'Tesla'];
    $scope.people = ['Gill Bates', 'Cohn Jarmack', 'Melon Musk'];
    $scope.results = [];
    $scope.searchSource = [];
  }])


  .directive('customSearch', [function() {
    function link(scope, element, attrs) {
      element.on("change", function(e) {
        var searchTerm = e.target.value;
        scope.$parent.$apply(function() {
          scope.$parent.searchSource = scope.source;
          scope.$parent.results = scope.source.indexOf(searchTerm);
        });
      });
    }

    return {
      scope: {
        source: '='
      },
      link: link
    };
  }]);
})(window.angular);

使用scope.$parent我觉得有点hacky并限制使用此指令成为控制器的直接子项,但我认为这是让你入门的好方法。

您可以尝试一下:https://plnkr.co/edit/A3jzjek6hyjK4Btk34Vc?p=preview

这个例子中只有几个注释。

  • 从文本框中删除焦点后的更改事件(而不是在您键入时
  • 您必须搜索确切的字符串才能获得匹配

希望它有所帮助。