简体   繁体   English

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

[英]Using different controllers with custom directive in AngularJS?

I have created a search box which is being used on two different views, one is for searching jobs and the other is for searching companies. 我创建了一个搜索框,用于两个不同的视图,一个用于搜索作业,另一个用于搜索公司。 I have made two separate controllers for both and separate services as well. 我为两者和单独的服务制作了两个独立的控制器。

Here is the html for the searchbox - 这是搜索框的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;"/>

Here is a script i am using for styling it - 这是我用来设置样式的脚本 -

<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>

Controller - 控制器 -

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;
    }
  }]);

I am trying to make a directive for this, since all this code is being repeated for the both the views. 我正在尝试为此制定一个指令,因为所有这些代码都是针对两个视图重复的。 But how do I make the directive interact with different controllers. 但是如何使指令与不同的控制器交互。 And how do i make this part ng-change="companies.search()" ng-model="companies.searchTerm" ng-keydown="companies.deleteTerm($event)" not dependent on the controllers. 我如何使这部分ng-change="companies.search()" ng-model="companies.searchTerm" ng-keydown="companies.deleteTerm($event)"不依赖于控制器。 I am new to angular and am not sure if this is the right approach or should i let the keep the code separate? 我是角色的新手,我不确定这是正确的方法还是我应该让代码分开? Please help. 请帮忙。

Server-Side search logic makes it simple 服务器端搜索逻辑使其变得简单

If it is possible that your search logic resides on the server and searching jobs or companies could be distinguished by simply setting a query variable in the URL, then it easy. 如果您的搜索逻辑可能驻留在服务器上,并且只需在URL中设置查询变量就可以区分搜索作业或公司,那么就很容易了。 You could use 1 search directive with an attribute to say which module to search and include this in your HTTP request. 您可以使用带有属性的1个搜索指令来说明要搜索的模块,并将其包含在您的HTTP请求中。

Client-Side search logic slightly more angularjs 客户端搜索逻辑略微更具角度

If you need different client-side logic for each type of search, consider this approach where there is 1 common search directive, plus 1 directive for each customized search. 如果您需要针对每种类型的搜索使用不同的客户端逻辑,请考虑这种方法,其中有1个常见search指令,以及每个自定义搜索的1个指令。

  1. the common search directive controls view + common search functionality 通用搜索指令控制视图+通用搜索功能

  2. a search-companies directive that is restrict: 'A' and require: 'search' and performs functions specific to the company search restrict: 'A'的搜索公司指令restrict: 'A'require: 'search'并执行特定于公司搜索的功能

  3. a search-jobs directive that is also restrict: 'A' and require: 'search' and performs functions specific to the job search 一个也restrict: 'A'的搜索作业指令restrict: 'A'require: 'search'并执行特定于作业搜索的功能

The concept is that the custom search directives will provide their controller/api object to the common search directive. 概念是自定义搜索指令将其控制器/ api对象提供给公共搜索指令。 The common search directive handles the view-controller interaction and calls the provided API functions for customized search functionality. 公共搜索指令处理视图 - 控制器交互并调用提供的API函数以用于自定义搜索功能。

In Code , this could look something like: 在Code中 ,这可能看起来像:

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
            };
        }]
    };
});

And using it in template would look like: 在模板中使用它看起来像:

<search search-companies></search>

and

<search search-jobs></search>

Multiple searches on one directive 对一个指令进行多次搜索

This concept could be easily expanded if you need to have one search directive that searches both companies and jobs. 如果您需要一个搜索指令来搜索公司和作业,则可以轻松扩展此概念。

The change would be to turn the search controller's this.api into an array. 改变是将搜索控制器的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
            };
        }]
    };
});

And using it in template would look like: 在模板中使用它看起来像:

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

You will have to pass your data source or service to the directive and bind the events from there. 您必须将数据源或服务传递给指令并从那里绑定事件。

<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>

In this sample I am using data-source to pass an array but you can use a service of course. 在此示例中,我使用data-source传递数组,但您当然可以使用服务。

Then your directive should use the scope attribute to assign what you passed as parameter in source to the scope of the directive. 那么你的指令应该使用scope属性来分配你作为参数传递source的指令范围。

You will have the input that is using the directive in the elem parameter to bind all the parameters your desire. 您将获得使用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);

Using scope.$parent feels a bit hacky I know and limits the use of this directive to be a direct child of the controller but I think it's a good way to get you started. 使用scope.$parent我觉得有点hacky并限制使用该指令成为控制器的直接子项,但我认为这是一个让你入门的好方法。

You can try it out: https://plnkr.co/edit/A3jzjek6hyjK4Btk34Vc?p=preview 你可以尝试一下: https//plnkr.co/edit/A3jzjek6hyjK4Btk34Vc?p = preview

Just a couple of notes from the example. 这个例子中只有几个注释。

  • The change event work after you remove focus from the text box (not while you're typing 从文本框中删除焦点后,更改事件将起作用(而不是在您键入时)
  • You will have to search the exact string to get a match 您必须搜索确切的字符串才能获得匹配

Hope it helps. 希望能帮助到你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM