Using formatters as filters

Formatters are helper tools to view your data differently from how they are stored in the model. Angular has built-in formatters, for example, Date to format date-times, Currency to format money data, and LimitTo to limit the view to a certain number of results. The Filter class displays items based on whether they satisfy the criteria set up in the filter. Sorting works through an orderBy attribute in ng-repeat. In this recipe, we will show you how to use filters to make different views on your data possible. You can follow along with the code in the project angular_formatter.

How to do it...

The job listing is now preceded by an input field; when you start typing the job type, the list of only those jobs that start with these letters are shown. The checkboxes allow you to filter on company, and the type of job is shown in uppercase in the job details section, as shown in the following screenshot:

How to do it...

Using formatters to limit the view

Perform the following steps to use formatters as filters:

  1. We've added two filters: the first on the job type, the second on the company. They are expressed through HTML in angular_formatter.html. Have a look at the following code:
      <div id="filters">
      <div>
      <label for="type-filter">Filter jobs by type</label>
      <input id="type-filter" type="text"
             ng-model="ctrl.typeFilterString">
      </div>
      <div> Filter jobs by company:
        <span ng-repeat="company in ctrl.companies">
          <label>
          <input type="checkbox"
         ng-model="ctrl.companyFilterMap[company]">{{company}}
          </label>
        </span>
      </div>
      <input type="button" value="Clear Filters" ng-click="ctrl.clearFilters()">
    </div>
  2. The actual filtering takes place in the same file; instead of a simple ng-repeat = "job in ctrl.jobs", we now have the following:
    ng-repeat="job in ctrl.jobs 
     orderBy:'type'filter:{type:ctrl.typeFilterString}companyfilter:ctrl.companyFilterMap"

    We have shown here the different filter parts on consecutive lines for readability, but in HTML, they must be on one line.

    In the controller code (libjob_listing.dart), we now have two lists:

      List<Job> jobs;
      List companies = [];

    The _loadData() option now returns jobs, and in the constructor companies is filled through as follows:

    for (job in jobs) {
          companies.add(job.company);
    }

    The filters need the following code:

    final companyFilterMap = <String, bool>{};
    String typeFilterString = "";
    
    void clearFilters() {
        companyFilterMap.clear();
        typeFilterString = "";
    }

    Furthermore, we have refactored the model code (class Job) in its own file libmodeljob.dart.

    The company filter is a custom formatter that has to be coded. We find it in libformattercompany_filter.dart as follows:

    library company_filter;
    
    import 'package:angular/angular.dart';
    
    @Formatter(name: 'companyfilter')
    class CompanyFilter {
      List call(JobList, filterMap) {
        if (JobList is Iterable && filterMap is Map) {
          // If there is nothing checked, treat it as "everything is checked"
          bool nothingChecked = filterMap.values.every((isChecked) => !isChecked);
      return nothingChecked
        ? JobList.toList()
        : JobList.where((i) => filterMap[i.company] == true).toList();
      }
    return const [];
     }
    }
  3. In <div job-listing> in angular_formatter.html, we now format the job type as {{job.type | uppercase}}.
  4. In libformatter, we code this uppercase formatter as follows:
    import 'package:angular/angular.dart';
    
    @Formatter(name: 'uppercase')
    class UppercaseFormatter {
      call(String name) {
        if (name == null || name.isEmpty) return '';
        return name.toUpperCase();
      }
    }
  5. The angular_formatter.dart script has two additional import statements and two bind statements for the formatters, as follows:
    import 'package:angular_formatter/formatter/company_filter.dart';
    import 'package:angular_formatter/formatter/uppercase_formatter.dart';
    
    class AppModule extends Module {
      AppModule() {
        bind(JobListingController);
        bind(SalaryComponent);
        bind(CompanyFilter);
       bind(UppercaseFormatter);
    }

How it works...

In step 1, we see the two filters. The filter on type is done with an input text field that has a special attribute, ng-model="ctrl.typeFilterString". This tells us that the JobListingController must have a property typeFilterString, which is bound to this input field by ng-model. The same goes for the checkboxes, which are bound to a controller property, companyFilterMap:

ng-model="ctrl.companyFilterMap[company]"

Indeed, we see these properties declared in the additional controller code in step 3. Note that companyFilterMap is a map built from the company names and the Boolean values of the checkboxes. Step 2 shows us the filtering declaration: first the jobs are ordered by type, then the type filter is applied (if any), and then the company filters (if any). The results are piped (or chained) with a | operator from one filter to the other.

Step 4 shows the code for the company filter: it has to be a separate class, CompanyFilter, that is annotated with @Formatter(name: 'companyfilter'), where the name is used in the ng-repeat attribute. This class must have a call method, as first argument the model object to be formatted (here, JobList), the second argument filterMap is the filter to be applied. So the return value of call is the filtered (formatted) job list. The filterMap parameter is the data that comes from the checkbox inputs. Steps 5 and 6 show how to add a simple uppercase formatter. In step 7, we add our custom filters and formatters to our AppModule.

See also

  • The Angular.dart framework here makes use of the special method call, which is explained in the Using the call method recipe in Chapter 4, Object Orientation
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset