Skip to content

Commit fb0e617

Browse files
committed
docs($compile): add more info about optional bindings
This also deletes the incorrect info that a missing attribute in a non-optional binding will throw. Closes angular#15989
1 parent 3bce707 commit fb0e617

File tree

2 files changed

+40
-11
lines changed

2 files changed

+40
-11
lines changed

docs/content/error/$compile/iscp.ngdoc

+7-7
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ myModule.directive('directiveName', function factory() {
1010
return {
1111
...
1212
scope: {
13-
'attrName': '@', // OK
14-
'attrName2': '=localName', // OK
15-
'attrName3': '<?localName', // OK
16-
'attrName4': ' = name', // OK
17-
'attrName5': 'name', // ERROR: missing mode @&=
18-
'attrName6': 'name=', // ERROR: must be prefixed with @&=
19-
'attrName7': '=name?', // ERROR: ? must come directly after the mode
13+
'localName': '@', // OK
14+
'localName2': '=attr', // OK
15+
'localName3': '<?attr', // OK
16+
'localName4': ' = attr', // OK
17+
'localName5': 'attr', // ERROR: missing mode @&=
18+
'localName6': 'attr=', // ERROR: must be prefixed with @&=
19+
'localName7': '=attr?', // ERROR: ? must come directly after the mode
2020
}
2121
...
2222
}

src/ng/compile.js

+33-4
Original file line numberDiff line numberDiff line change
@@ -303,16 +303,15 @@
303303
* name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
304304
* localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
305305
* value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
306-
* `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
307-
* `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
308-
* optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
306+
* `localModel` and vice versa. If the binding expression is non-assignable, an exception
307+
* ({@link error/$compile/nonassign `$compile:nonassign`})
309308
* will be thrown upon discovering changes to the local value, since it will be impossible to sync
310309
* them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
311310
* method is used for tracking changes, and the equality check is based on object identity.
312311
* However, if an object literal or an array literal is passed as the binding expression, the
313312
* equality check is done by value (using the {@link angular.equals} function). It's also possible
314313
* to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
315-
* `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
314+
* `$watchCollection`}: use `=*` or `=*attr`
316315
*
317316
* * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
318317
* expression passed via the attribute `attr`. The expression is evaluated in the context of the
@@ -347,6 +346,36 @@
347346
* and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
348347
* then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
349348
*
349+
* All 4 kinds of bindings (`@`, `=`, `<`, and `&`) can be made optional by adding `?` to the expression.
350+
* The marker must come before the attribute name.
351+
* See the {@link error/$compile/iscp the Invalid Isolate Scope Definition error} for definition examples.
352+
* This is useful to refine the interface directives provides.
353+
* One subtle difference between optional and non-optional happens **when the binding attribute is not
354+
* set**:
355+
* - the binding is optional: the property will not be defined
356+
* - the binding is not optional: the property is defined
357+
*
358+
* ```js
359+
*app.directive('testDir', function() {
360+
return {
361+
scope: {
362+
notoptional: '=',
363+
optional: '=?',
364+
},
365+
bindToController: true,
366+
controller: function() {
367+
this.$onInit = function() {
368+
console.log(this.hasOwnProperty('notoptional')) // true
369+
console.log(this.hasOwnProperty('optional')) // false
370+
}
371+
}
372+
}
373+
})
374+
*```
375+
*
376+
*
377+
* ##### Combining directives with different scope defintions
378+
*
350379
* In general it's possible to apply more than one directive to one element, but there might be limitations
351380
* depending on the type of scope required by the directives. The following points will help explain these limitations.
352381
* For simplicity only two directives are taken into account, but it is also applicable for several directives:

0 commit comments

Comments
 (0)