Using custom filters, directives and http GET request inside angular filter?

I have been working on angularjs for past couple of weeks and I am sort of unable to understand how do I make my custom directive, my custom filter work with each other while adding a ajax request inside filter (not sure if adding a ajax request inside filter is a good idea).

First some background:

I have a list of items and a search field. It was really simple for me to create a list and add search/filter capability using angular's two way binding. Now, I want angular to filter only after a user stops typing. I have achieved this using debounce function provided by underscore/lodash. Next steps of the process is as soon as the user stops typing - i) grab the search text ii) make a http request and iii) filter the list based on the response from server, for e.g. if server returns filter by category:foo then filter using foo. So far I have managed to filter as the user stops typing and filter based on some hard coded category (without using ajax). I have added sample code http://plnkr.co/edit/s8sg5h1REd7n5opv0Vk2 - It is not functional but will provide the background of what I have done so far.

My issue is - 1. I am unable to filter while I wait for ajax to finish 2. I am certain this is not the best way to solve my problem, please suggest what is the best way to do achieve my goal.

Also I am unable to find anything related on google or SO.


Relevant Html View

<my-input type="search" data-ng-model="ts.search" placeholder="search"></c1-input>

<ul data-ng-repeat="car in cars">
  <li>{{car.name}} </li>
</ul>

Relevant javascript

app.controller('MainController', ['$scope', 'carsFactory', function ($scope, carsFactory) {
    $scope.cars = carsFactory.getCars();
    $scope.filteredCars = $scope.cars;
}]);

app.directive('myInput', function ($parse, $filter) {
  return {
    restrict: "E",
    replace: true,
    transclude: true,
    template: '<input ng-translude/>',
    compile: function (cElement, cAttrs) {
      var modelAccessor = $parse(cAttrs.ngModel);

      return function (scope, element, attrs, controller) {
        // Filter only after user has stopped typing
        scope.$watch(modelAccessor, _.debounce(function (val) {
          scope.typed = scope.typing;
          scope.$apply(function () {
            modelAccessor.assign(scope, val);
            scope.filteredCars = $filter('myFilter')(scope.cars, val);
          });
        }, 500))
      } 
    }
  }
});

app.factory('carsFactory',['$http', function ($http) {
  return {
    // This actually makes a ajax request
    getCars: function () {
      return cars;
    }
  }

  var cars = [{name: 'Focus ST', category: 'hatchback'}, 
  {name: 'Audi S5', category: 'coupe'},
  {name: 'Audi S4', category: 'sedan'},
  {name: 'Mazda 3', category: 'hatchback'},
  {name: 'Mazda 3', category: 'sedan'}]
}]);


app.filter('myFilter', ['$filter', function ($filter) {

  // should make http request
  // should grab response and apply custom filters on the transactions

  function makeHttpRequest (cars, searchText) {
    // Here it should make a http request and return category.
    // Next, filter should be applied based on category
    return cars;
  }

  return function (cars, searchText) {
    if (searchText) {
      cars =  makeHttpRequest(cars, searchText);
    }
    return cars;
  };
}]);

Answers:

Answer

Here is how I approached the problem. Correct me if I am wrong.

template

<h2>Cars</h2>

<my-input type="search" data-ng-model="myModel.searchField" placeholder="search"></my-input>

<ul data-ng-repeat="car in myModel.filteredCars">
   <li>{{car.name}} </li>
</ul>

Script

// Defining app with route dependency
var app = angular.module("myApp", ["ngRoute"]);
app.config(['$routeProvider', '$locationProvider', function ($routeProvider,  $locationProvider) {
  $routeProvider
    .when('/t', {
        controller: 'MainController',
        templateUrl: 'main.html'
      })
    .otherwise({ redirectTo: '/t' });

    $locationProvider.html5Mode(true);
}]);

app.controller('MainController', ['$scope', 'carsFactory','categoryFactory','$filter', function ($scope, carsFactory, categoryFactory, $filter) {
    $scope.myModel.searchField = {};
    $scope.myModel.cars = carsFactory.getCars();
    $scope.myModel.filteredCars = $scope.myModel.cars;
    $scope.myModel.search = function (query) {
      if (!query) return false;

      var filterCat = categoryFactory.getFilterCategory(query);

      $scope.myModel.filteredCars = $filter('myFilter')($scope.myModel.cars, filterCat.category);

    }
}]);

app.directive('myInput', function ($parse, $filter) {
  return {
    restrict: "E",
    replace: true,
    transclude: true,
    template: '<input ng-translude/>',
    link: function (scope, lElement, lAttrs) {
      var modelAccessor = $parse(cAttrs.ngModel);

      scope.$watch(modelAccessor, _.debounce (function (val) {
        scope.$apply(function () {
          scope.myModel.search(val);
        });
      }, 500));
    }
  };
});

app.factory('carsFactory',['$http', function ($http) {
  var cars = [{name: 'Focus ST', category: 'hatchback'}, 
  {name: 'Audi S5', category: 'coupe'},
  {name: 'Audi S4', category: 'sedan'},
  {name: 'Mazda 3', category: 'hatchback'},
  {name: 'Mazda 3', category: 'sedan'}];

  return {
    // This actually makes a ajax request and returns list of available cars
    getCars: function () {
      return cars;
    }
  }


}]);

app.factory('categoryFactory', function () {
  var category = {category: "sedan"};

  return {
  // make an ajax request with query parameter and return sample response
    getFilterCategory: function (query) {
      return category;
    }
  }

});


app.filter('myFilter', ['$filter', function ($filter) {

  function filter(cars, category) {
// Assuming we are doing some complex calculations here before we actually filter
    return $filter('filter')(cars, {category: category});
  }

  return function (cars, category) {

    cars =  filter(cars, category);

    return cars;
  };
}]);

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.