dev/core#651 Fix group by on export soft credits (possible recent regression, clearly...
[civicrm-core.git] / ang / crmRouteBinder.md
CommitLineData
67341f3c
CW
1# crmRouteBinder
2
3Live-update the URL to stay in sync with controller data.
4
5## Example
6
7```js
8angular.module('sandbox').config(function($routeProvider) {
9 $routeProvider.when('/example-route', {
10 reloadOnSearch: false,
11 template: '<input ng-model="filters.foo" />',
12 controller: function($scope) {
13 $scope.$bindToRoute({
14 param: 'f',
15 expr: 'filters',
16 default: {foo: 'default-value'}
17 });
18 }
19 });
20});
21```
22
23Things to try out:
24
25 * Navigate to `#/example-route`. Observe that the URL automatically
26 updates to `#/example-route?f={"foo":"default-value"}`.
27 * Edit the content in the `<input>` field. Observe that the URL changes.
28 * Initiate a change in the browser -- by editing the URL bar or pressing
29 the "Back" button. The page should refresh.
30
31## Functions
32
284ed4f0
CW
33**`$scope.$bindToRoute(options)`**
34*The `options` object should contain keys:*
35
36 * `expr` (string): The name of a scoped variable to sync.
37 * `param` (string): The name of a query-parameter to sync. (If the `param` is included in the URL, it will initialize the expr.)
38 * `format` (string): The type of data to put in `param`. May be one of:
39 * `json` (default): The `param` is JSON, and the `expr` is a decoded object.
40 * `raw`: The `param` is string, and the `expr` is a string.
41 * `int`: the `param` is an integer-like string, and the expr is an integer.
42 * `bool`: The `param` is '0'/'1', and the `expr` is false/true.
43 * `default` (object): The default data. (If the `param` is not included in the URL, it will initialize the expr.)
44 * `deep` (boolean): By default the json format will be watched using a shallow comparison. For nested objects and arrays enable this option.
67341f3c
CW
45
46## Suggested Usage
47
48`$bindToRoute()` was written for a complicated routing scenario with
49multiple parameters, e.g. `caseFilters:Object`, `caseId:Int`, `tab:String`,
50`activityFilters:Object`, `activityId:Int`. If you're use-case is one or
51two scalar values, then stick to vanilla `ngRoute`. This is only for
52complicated scenarios.
53
54If you are using `$bindToRoute()`, should you split up parameters -- with
55some using `ngRoute` and some using `$bindToRoute()`? I'd pick one style
56and stick to it. You're in a complex use-case where `$bindToRoute()` makes
57sense, then you already need to put thought into the different
58flows/input-combinations. Having two technical styles will increase the
59mental load.
60
61A goal of `bindToRoute()` is to accept inputs interchangably from the URL or
62HTML fields. Using `ngRoute`'s `resolve:` option only addresses the URL
63half. If you want one piece of code handling all inputs the same way, you
64should avoid `resolve:` and instead write a controller focused on
65orchestrating I/O:
66
67```js
68angular.module('sandbox').config(function($routeProvider) {
69 $routeProvider.when('/example-route', {
70 reloadOnSearch: false,
71 template:
72 '<div filter-toolbar-a="filterSetA" />'
73 + '<div filter-toolbar-b="filterSetB" />'
74 + '<div filter-toolbar-c="filterSetC" />'
75 + '<div data-set-a="dataSetA" />'
76 + '<div data-set-b="dataSetB" />'
77 + '<div data-set-c="dataSetC" />',
78 controller: function($scope) {
79 $scope.$bindToRoute({expr:'filterSetA', param:'a', default:{}});
80 $scope.$watchCollection('filterSetA', function(){
81 crmApi(...).then(function(...){
82 $scope.dataSetA = ...;
83 });
84 });
85
86 $scope.$bindToRoute({expr:'filterSetB', param:'b', default:{}});
87 $scope.$watchCollection('filterSetB', function(){
88 crmApi(...).then(function(...){
89 $scope.dataSetB = ...;
90 });
91 });
92
93 $scope.$bindToRoute({expr:'filterSetC', param:'c', default:{}});
94 $scope.$watchCollection('filterSetC', function(){
95 crmApi(...).then(function(...){
96 $scope.dataSetC = ...;
97 });
98 });
99 }
100 });
101});
102```
103
104(This example is a little more symmetric than a real one -- because the A,
105B, and C datasets look independent. In practice, their loading may be
106intermingled.)