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

Using different controllers with custom directive in AngularJS?

本文关键字:控制器 自定义 指令 AngularJS      更新时间:2023-09-26

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

这是搜索框的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)"不依赖于控制器。我是新的角度,我不确定这是否是正确的方法,或者我应该让保持代码分开?请帮助。

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

如果您的搜索逻辑可能驻留在服务器上,并且可以通过简单地在URL中设置查询变量来区分搜索作业或公司,那么这很容易。你可以使用一个带有属性的搜索指令来指定搜索哪个模块,并将其包含在HTTP请求中。

客户端搜索逻辑稍微偏重angularjs

如果您需要为每种类型的搜索提供不同的客户端逻辑,请考虑这种方法,其中有1个通用search指令,加上每个自定义搜索的1个指令。

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

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

  3. 一个search-jobs指令,也是restrict: 'A'require: 'search',并执行特定于job search的功能

这个概念是自定义搜索指令将提供它们的控制器/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>

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

<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

只是例子中的几个注意事项。

  • 更改事件在您从文本框中移除焦点后工作(而不是当您键入
  • 时)
  • 你必须搜索精确的字符串来获得匹配

希望能有所帮助。