简体   繁体   中英

Calling controller function in a directive

I am trying to call a callback on a controller from my custom directive. My aim to generate a search directive that can be re-used in multiple place. I want to pass it the function it needs to call on the attached controller via the function specified in the directive's attribute.

Plunkr URL is here

The code is as follows

<html ng-app="demo">

<head>
   <title>My Angular App</title>
   <link data-require="bootstrap@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
   <script data-require="bootstrap@*" data-semver="3.3.1" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
   <script data-require="jquery@*" data-semver="2.1.3" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller='carsController'>
  <search-box placeholder="Search Cars" do-search="doSearch()"></search-box>
  <!--
  <form class="form-inline">
    <div class="form-group">
      <input type="text" class="form-control" ng-model="searchText" placeholder="Search Cars" />
    </div>
    <button type="button" class="btn btn-default" ng-click="doSearch()">search</button>    
  </form>
  -->
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Make</th>
        <th>Model</th>
      </tr>
    </thead>
    <tbody ng-repeat="car in cars">
      <tr>
        <td>{{car.make}}</td>
        <td>{{car.model}}</td>
      </tr>
    </tbody>
  </table>
</div>
</body>


app = angular.module('demo',[]);
//controllers
app.controller("carsController", ['$scope', function($scope) {
$scope.searchText = "";
$scope._cars = [
{
  'model': 'A4',
  'make':'Audi'
},
{
  'model':'328i',
  'make':'BMW'
}
];

$scope.cars = $scope._cars; 
$scope.doSearch = function() {
if($scope.searchText.length > 0) {
  $scope.cars = [];
  $scope._cars.forEach(function(car, index) {
  if(car.make.indexOf($scope.searchText) > -1) {
    $scope.cars.push(car);   
  }
}); 
} else {
  $scope.cars = $scope._cars;
}
}

$scope.resetSearch = function() {
  $scope.searchText = "";
  $scope.cars = $scope._cars;
}
}]);

// directives
app.directive("searchBox", searchBox);
function searchBox(){
  return {
    restrict: 'E',
    transclude: true,
    scope: {
       placeholder: '@',
       doSearch: '&'
    },
    link: searchBoxLink,
    templateUrl:'search.html'
  }
}

function searchBoxLink(scope, element, attrs, controller) {
    scope.search = function() {
    scope.doSearch();
  }
}

<form class="form-inline">
  <div class="form-group">
    <input type="text" class="form-control" placeholder="{{placeholder}}" />
    <button type="button" class="btn btn-default" ng-click="search()">
      Search
    </button>
 </div>
</form>

I am a ng-noob and have read the documentation multiple times. Needless to say ng-directive still remains a mystery.

Thank you for the help

The problem with your code was not about the controller doSearch method. I could see the controller method is successfully invoked when the search button is clicked.

The issue was with the controller scope property searchText . Ideally, when you change the search text, this property should be set.

I modified your code a bit to pass the searchText to the directive and set to the search box input as ng-model.

see the plunk

There were a few things wrong with your code. I fixed them in a fork of your Plunkr .

Not binding the search text

You were relying on $scope.searchText to be the text the user entered in the filter's textbox, but didn't bind to that anywhere. Instead, in my version, I chose to make a searchText parameter available to the do-search="doSearch(searchText)" attribute expression. This means the doSearch function on the controller becomes:

$scope.doSearch = function(searchText) {
  // make sure its a string and lowercased
  searchText = (searchText || '').toString().toLocaleLowerCase();
  if (searchText.length > 0) {
    $scope.cars = [];
    $scope._cars.forEach(function(car, index) {
      if (car.make.toLocaleLowerCase().indexOf(searchText) > -1) {
        $scope.cars.push(car);
      }
    });
  } else {
    $scope.cars = $scope._cars;
  }
}

You will notice I also used .toLocaleLowerCase() (effectively the same as .toLowerCase() but theoretically deals with unicode/funky characters better) to make sure I did a case insensitive search.

Other minor improvements

I added ng-submit="search()" to the form in the template for your directive so the user can press Enter to apply the filtering.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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