This file is indexed.

/usr/share/civicrm/ang/crmRouteBinder.md is in civicrm-common 4.7.30+dfsg-1ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
# crmRouteBinder

Live-update the URL to stay in sync with controller data.

## Example

```js
angular.module('sandbox').config(function($routeProvider) {
  $routeProvider.when('/example-route', {
    reloadOnSearch: false,
    template: '<input ng-model="filters.foo" />',
    controller: function($scope) {
      $scope.$bindToRoute({
        param: 'f',
        expr: 'filters',
        default: {foo: 'default-value'}
      });
    }
  });
});
```

Things to try out:

 * Navigate to `#/example-route`. Observe that the URL automatically
   updates to `#/example-route?f={"foo":"default-value"}`.
 * Edit the content in the `<input>` field. Observe that the URL changes.
 * Initiate a change in the browser -- by editing the URL bar or pressing
   the "Back" button.  The page should refresh.

## Functions

**`$scope.$bindToRoute(options)`**
*The `options` object should contain keys:*

 * `expr` (string): The name of a scoped variable to sync.
 * `param` (string): The name of a query-parameter to sync. (If the `param` is included in the URL, it will initialize the expr.)
 * `format` (string): The type of data to put in `param`. May be one of:
    * `json` (default): The `param` is JSON, and the `expr` is a decoded object.
    * `raw`: The `param` is string, and the `expr` is a string.
    * `int`: the `param` is an integer-like string, and the expr is an integer.
    * `bool`: The `param` is '0'/'1', and the `expr` is false/true.
 * `default` (object): The default data. (If the `param` is not included in the URL, it will initialize the expr.)
 * `deep` (boolean): By default the json format will be watched using a shallow comparison. For nested objects and arrays enable this option.

## Suggested Usage

`$bindToRoute()` was written for a complicated routing scenario with
multiple parameters, e.g.  `caseFilters:Object`, `caseId:Int`, `tab:String`,
`activityFilters:Object`, `activityId:Int`.  If you're use-case is one or
two scalar values, then stick to vanilla `ngRoute`. This is only for
complicated scenarios.

If you are using `$bindToRoute()`, should you split up parameters -- with
some using `ngRoute` and some using `$bindToRoute()`?  I'd pick one style
and stick to it.  You're in a complex use-case where `$bindToRoute()` makes
sense, then you already need to put thought into the different
flows/input-combinations.  Having two technical styles will increase the
mental load.

A goal of `bindToRoute()` is to accept inputs interchangably from the URL or
HTML fields.  Using `ngRoute`'s `resolve:` option only addresses the URL
half.  If you want one piece of code handling all inputs the same way, you
should avoid `resolve:` and instead write a controller focused on
orchestrating I/O:

```js
angular.module('sandbox').config(function($routeProvider) {
  $routeProvider.when('/example-route', {
    reloadOnSearch: false,
    template:
      '<div filter-toolbar-a="filterSetA" />'
      + '<div filter-toolbar-b="filterSetB" />'
      + '<div filter-toolbar-c="filterSetC" />'
      + '<div data-set-a="dataSetA" />'
      + '<div data-set-b="dataSetB" />'
      + '<div data-set-c="dataSetC" />',
    controller: function($scope) {
      $scope.$bindToRoute({expr:'filterSetA', param:'a', default:{}});
      $scope.$watchCollection('filterSetA', function(){
        crmApi(...).then(function(...){
          $scope.dataSetA = ...;
        });
      });

      $scope.$bindToRoute({expr:'filterSetB', param:'b', default:{}});
      $scope.$watchCollection('filterSetB', function(){
        crmApi(...).then(function(...){
          $scope.dataSetB = ...;
        });
      });

      $scope.$bindToRoute({expr:'filterSetC', param:'c', default:{}});
      $scope.$watchCollection('filterSetC', function(){
        crmApi(...).then(function(...){
          $scope.dataSetC = ...;
        });
      });
    }
  });
});
```

(This example is a little more symmetric than a real one -- because the A,
B, and C datasets look independent.  In practice, their loading may be
intermingled.)