Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit e65928e

Browse files
authored
docs($compile): add more info about optional bindings
This centralizes the info about optional bindings. Also adds more examples to the $compile:iscp error. Closes #15989 Closes #16025
1 parent 3bce707 commit e65928e

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
lines changed

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

+9-7
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ 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', // OK
18+
'localName6': 'attr', // ERROR: missing mode @&=<
19+
'localName7': 'attr=', // ERROR: must be prefixed with @&=<
20+
'localName8': '=attr?', // ERROR: ? must come directly after the mode
21+
'localName9': '<*' // ERROR: * is only valid with =
2022
}
2123
...
2224
}

src/ng/compile.js

+38-7
Original file line numberDiff line numberDiff line change
@@ -303,21 +303,22 @@
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`})
309-
* will be thrown upon discovering changes to the local value, since it will be impossible to sync
310-
* them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
306+
* `localModel` and vice versa. If the binding expression is non-assignable, or if the attribute
307+
* isn't optional and doesn't exist, an exception
308+
* ({@link error/$compile/nonassign `$compile:nonassign`}) will be thrown upon discovering changes
309+
* to the local value, since it will be impossible to sync them back to the parent scope.
310+
*
311+
* By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
311312
* method is used for tracking changes, and the equality check is based on object identity.
312313
* However, if an object literal or an array literal is passed as the binding expression, the
313314
* equality check is done by value (using the {@link angular.equals} function). It's also possible
314315
* to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
315-
* `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
316+
* `$watchCollection`}: use `=*` or `=*attr`
316317
*
317318
* * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
318319
* expression passed via the attribute `attr`. The expression is evaluated in the context of the
319320
* parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
320-
* local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
321+
* local name.
321322
*
322323
* For example, given `<my-component my-attr="parentModel">` and directive definition of
323324
* `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
@@ -347,6 +348,36 @@
347348
* and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
348349
* then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
349350
*
351+
* All 4 kinds of bindings (`@`, `=`, `<`, and `&`) can be made optional by adding `?` to the expression.
352+
* The marker must come after the mode and before the attribute name.
353+
* See the {@link error/$compile/iscp Invalid Isolate Scope Definition error} for definition examples.
354+
* This is useful to refine the interface directives provide.
355+
* One subtle difference between optional and non-optional happens **when the binding attribute is not
356+
* set**:
357+
* - the binding is optional: the property will not be defined
358+
* - the binding is not optional: the property is defined
359+
*
360+
* ```js
361+
*app.directive('testDir', function() {
362+
return {
363+
scope: {
364+
notoptional: '=',
365+
optional: '=?',
366+
},
367+
bindToController: true,
368+
controller: function() {
369+
this.$onInit = function() {
370+
console.log(this.hasOwnProperty('notoptional')) // true
371+
console.log(this.hasOwnProperty('optional')) // false
372+
}
373+
}
374+
}
375+
})
376+
*```
377+
*
378+
*
379+
* ##### Combining directives with different scope defintions
380+
*
350381
* In general it's possible to apply more than one directive to one element, but there might be limitations
351382
* depending on the type of scope required by the directives. The following points will help explain these limitations.
352383
* For simplicity only two directives are taken into account, but it is also applicable for several directives:

0 commit comments

Comments
 (0)