@@ -109,13 +109,20 @@ change will be reflected in the parent component. For components however, only t
109
109
the data should modify it, to make it easy to reason about what data is changed, and when. For that reason,
110
110
components should follow a few simple conventions:
111
111
112
- - Inputs are realized with `@` and `=` bindings
112
+ - Inputs should be using `<` and `@` bindings. The `<` symbol denotes {@link $compile#-scope- one-way bindings} which are
113
+ available since 1.5. The difference to `=` is that the bound properties in the component scope are not watched, which means
114
+ if you assign a new value to the property in the component scope, it will not update the parent scope. Note however, that both parent
115
+ and component scope reference the same object, so if you are changing object properties or array elements in the
116
+ component, the parent will still reflect that change.
117
+ The general rule should therefore be to never change an object or array property in the component scope.
118
+ `@` bindings can be used when the input is a string, especially when the value of the binding doesn't change.
113
119
```js
114
120
bindings: {
115
- hero: `=`,
121
+ hero: `<`,
122
+ comment: '@'
116
123
}
117
124
```
118
- - Outputs are realized with `&` bindings, which function as callbacks to component events
125
+ - Outputs are realized with `&` bindings, which function as callbacks to component events.
119
126
```js
120
127
bindings: {
121
128
onDelete: '&',
@@ -153,11 +160,11 @@ above:
153
160
Instead of an ngController, we now have a heroList component that holds the data of
154
161
different heroes, and creates a heroDetail for each of them.
155
162
156
- The heroDetail component now contains the following new functionality:
157
- - a delete button that calls the bound onDelete function of the heroList component
163
+ The heroDetail component now contains new functionality:
164
+ - a delete button that calls the bound ` onDelete` function of the heroList component
158
165
- an input to change the hero location, in the form of a reusable editableField component. Instead
159
- of manipulating the hero object itself, it sends the changes upwards to the heroDetail, which sends
160
- it upwards to the heroList component, which updates it .
166
+ of manipulating the hero object itself, it sends a changeset upwards to the heroDetail, which sends
167
+ it upwards to the heroList component, which updates the original data .
161
168
162
169
<example name="heroComponentTree" module="heroApp">
163
170
<file name="index.js">
@@ -212,7 +219,7 @@ it upwards to the heroList component, which updates it.
212
219
templateUrl: 'heroDetail.html',
213
220
controller: HeroDetailController,
214
221
bindings: {
215
- hero: '= ',
222
+ hero: '< ',
216
223
onDelete: '&',
217
224
onUpdate: '&'
218
225
}
@@ -252,8 +259,8 @@ it upwards to the heroList component, which updates it.
252
259
templateUrl: 'editableField.html',
253
260
controller: EditableFieldController,
254
261
bindings: {
255
- fieldValue: '@ ',
256
- fieldType: '@',
262
+ fieldValue: '< ',
263
+ fieldType: '@? ',
257
264
onUpdate: '&'
258
265
}
259
266
});
@@ -269,7 +276,7 @@ it upwards to the heroList component, which updates it.
269
276
<hr>
270
277
<div>
271
278
Name: {{$ctrl.hero.name}}<br>
272
- Location: <editable-field field-value="{{ $ctrl.hero.location}} " field-type="text" on-update="$ctrl.update('location', value)"></editable-field><br>
279
+ Location: <editable-field field-value="$ctrl.hero.location" field-type="text" on-update="$ctrl.update('location', value)"></editable-field><br>
273
280
<button ng-click="$ctrl.onDelete({hero: $ctrl.hero})">Delete</button>
274
281
</div>
275
282
</file>
@@ -303,17 +310,25 @@ application, every view is a component:
303
310
```
304
311
<br />
305
312
When using {@link ngRoute.$routeProvider $routeProvider}, you can often avoid some
306
- boilerplate, by assigning the resolved dependencies directly to the route scope:
313
+ boilerplate, by passing the resolved route dependencies directly to the component. Since 1.5,
314
+ ngRoute automatically assigns the resolves to the route scope property `$resolve` (you can also
315
+ configure the property name via `resolveAs`). When using components, you can take advantage of this and pass resolves
316
+ directly into your component without creating an extra route controller:
317
+
307
318
```js
308
319
var myMod = angular.module('myMod', ['ngRoute']);
309
320
myMod.component('home', {
310
321
template: '<h1>Home</h1><p>Hello, {{ $ctrl.user.name }} !</p>',
311
- bindings: {user: '='}
322
+ bindings: {
323
+ user: '<'
324
+ }
312
325
});
313
326
myMod.config(function($routeProvider) {
314
327
$routeProvider.when('/', {
315
328
template: '<home user="$resolve.user"></home>',
316
- resolve: {user: function($http) { return $http.get('...'); }}
329
+ resolve: {
330
+ user: function($http) { return $http.get('...'); }
331
+ }
317
332
});
318
333
});
319
334
```
@@ -349,7 +364,9 @@ angular.module('docsTabsExample', [])
349
364
})
350
365
.component('myPane', {
351
366
transclude: true,
352
- require: {tabsCtrl: '^myTabs'},
367
+ require: {
368
+ tabsCtrl: '^myTabs'
369
+ },
353
370
bindings: {
354
371
title: '@'
355
372
},
0 commit comments