想要将 ng-repeat 对象传递给自定义过滤器函数

want to pass ng-repeat object to custom filter function

目标:

用户应该能够在搜索字段中输入课程名称,并查看已注册该课程的学生列表。

型号:

course (has a course name and course code)
student (has a list of registered courses)
students (an array of student objects)

方法:

ng-重复遍历学生对象列表。对于每个学生对象,将对象传递给自定义过滤器函数 filterByCourse(byCourse, student)

待实现: filterByCourse 函数遍历student.courses。如果找到与 byCourse 具有相同名称或代码的课程,则将其添加到 filteredStudents 列表中。将 filteredStudents 列表传递给视图,以代替未过滤的学生列表。

代码如下:

<input class="form-control" type="text" ng-model="byCourse"
placeholder="Search by course id or course name..">

<ul ng-repeat="student in students | filter: filterByCourse(byCourse, student)">
        <li ng-init="index=0; classes=['list--students_item', 'list--students_item--active']" ng-click="stageMeToCourse($index)" 
            ng-class="classes[index % classes.length]" 
            class="col-xs-24">

            <img src="/img/profile_default.png">
            <h4>{{ student.first_name }} {{ student.last_name }} 
                <span class="role">{{ student.role }}</span>
                <i class="fa fa-chevron-right"></i>
            </h4>
            <p class="student_nr">{{ student._id }}</p>
        </li>
    </ul>
</div><!--list-students-->

问题:

当我将学生对象传递给 filterByCourse 时,第一行的 console.log 显示学生未定义,因此我无法遍历课程和 return 过滤学生列表如我所愿。

scope.filterByCourse = function(course, student){
    console.log(student); //student is undefined
}

我尝试过的事情:

进一步问题:

如果用户在输入字段中输入了一些字符串,我只希望以这种方式过滤结果。如果输入字段为空,则不应触发过滤功能。我不知道该怎么做!

函数

filterByCourse

只能在 html 中使用 'byCourse' 调用,并且它的实现应该只接收参数 'byCourse'。该函数还应该 return 一个接收学生对象的函数。 所以你 html 应该

<ul ng-repeat="student in students | filter: filterByCourse(byCourse)">

在 javascript 中应该是

$scope.filterByCourse = function (byCourse) {
  return function (student) {
      console.log(student);
  }
};

(过滤器 returns 可以访问 byCourse 参数的函数,因为它在相同的上下文中)。 这是一个有效的 jsFiddle

选项 1:

您尝试创建的称为谓词函数。您可以继续阅读 here(只需滚动到 function(value, index, array)

A predicate function can be used to write arbitrary filters. The function is called for each element of the array, with the element, its index, and the entire array itself as arguments.

The final result is an array of those elements that the predicate returned true for

请查看工作示例here

如果您输入“course”,您将看到两个学生,如果您输入“course1”,您将只看到第一个学生。课程代码“CC1”

也是如此

HTML:

<div ng-controller="TestController" class="panel panel-primary">
  <form class="form-inline">
    <div class="form-group">
      <input type="text" class="form-control" placeholder="Filter" ng-model="studentFilter">
    </div>
  </form>
  <div class="panel-heading">Students</div>
    <ul class="list-group">
      <li class="list-group-item" ng-repeat="student in students | filter:onFilterStudents">
      {{student.firstName}} {{student.surname}}
        <ul class="list-group">
          <li class="list-group-item" ng-repeat="course in student.courses">
            {{course.courseName}}-{{course.courseCode}}
          </li>
        </ul>
     </li>
  </ul>
</div>

JS:

var myApp = angular.module('myApp', []);

myApp.controller('TestController', ['$scope', function($scope) {
  $scope.students = [{
    firstName: 'John',
    surname: 'Doe',
    courses: [{
      courseName: 'course1',
      courseCode: 'CC1'
    }, {
      courseName: 'course2',
      courseCode: 'CC7'
    }]
  }, {
    firstName: 'Jane',
    surname: 'Doe',
    courses: [{
      courseName: 'course3',
      courseCode: 'CC2'
    }, {
      courseName: 'course4',
      courseCode: 'CC3'
    }]
  }];

  $scope.onFilterStudents = function(value, index, array) {
    if ($scope.studentFilter === '' || $scope.studentFilter === null || $scope.studentFilter === undefined) {
      return true;
    }    
    return value.courses.filter(function(course) {
    console.log(course);
      return course.courseName.toLowerCase().indexOf($scope.studentFilter.toLowerCase()) > -1 || course.courseCode.toLowerCase().indexOf($scope.studentFilter.toLowerCase()) > -1;
    }).length > 0;
  };
}]);

选项 2

您可以使用对象作为 filter expression(scroll to Object: A pattern ob...), please see working example here

A pattern object can be used to filter specific properties on objects contained by array. For example {name:"M", phone:"1"} predicate will return an array of items which have property name containing "M" and property phone containing "1". A special property name $ can be used (as in {$:"text"}) to accept a match against any property of the object or its nested object properties. That's equivalent to the simple substring match with a string as described above. The predicate can be negated by prefixing the string with !. For example {name: "!M"} predicate will return an array of items which have property name not containing "M".

HTML:

<div ng-controller="TestController" class="panel panel-primary">
  <form class="form-inline">
    <div class="form-group">
      <input type="text" class="form-control" placeholder="Filter" ng-model="studentFilter">
    </div>
  </form>
  <div class="panel-heading">Students</div>
  <ul class="list-group">
    <li class="list-group-item" ng-repeat="student in students | filter:{courses:{$:studentFilter}}">
      {{student.firstName}} {{student.surname}}
      <ul class="list-group">
        <li class="list-group-item" ng-repeat="course in student.courses">
          {{course.courseName}}-{{course.courseCode}}
        </li>
      </ul>
    </li>
  </ul>
</div>

JS:

var myApp = angular.module('myApp', []);

myApp.controller('TestController', ['$scope', function($scope) {
  $scope.students = [{
    firstName: 'John',
    surname: 'Doe',
    courses: [{
      courseName: 'course1',
      courseCode: 'CC1'
    }, {
      courseName: 'course2',
      courseCode: 'CC7'
    }]
  }, {
    firstName: 'Jane',
    surname: 'Doe',
    courses: [{
      courseName: 'course3',
      courseCode: 'CC2'
    }, {
      courseName: 'course4',
      courseCode: 'CC3'
    }]
  }];  
}]);

如果不需要自定义代码或高级过滤,我选择选项 2