I was following a tutorial trying to get a directive to work that required ngModel
:
app.directive("contenteditable", function() {
return {
restrict: "A",
require: "ngModel",
/* etc. */
This failed to load saying:
Controller 'ngModel', required by directive 'contenteditable', can't be found!
Looking at similar code in the angular docs, I changed the require
line:
require: "?ngModel"
Now it works fine. I'm guessing that the ?
makes it optional but that doesn't make much sense to me. What is the question mark doing and (if it's not obvious) why is it allowing the directive to work?
These prefixes are used to bind the parent scope's methods and properties to the directive scope. There are 3 types of prefixes in AngularJS: '@' – Text binding / one-way binding. '=' – Direct model binding / two-way binding.
In some code snippets, you may have seen that Angular expressions have a question mark after them. Angular refers to it as 'Safe Navigation Operator'. It makes sure that we are not seeing null and undefined values in our application when we want to access properties of an object.
Locals definition is a hash of local scope property to its source: = or =attr - set up bi-directional binding between a local scope property and the parent scope property of name defined via the value of the attr attribute.
AngularJS directives are extended HTML attributes with the prefix ng- . The ng-app directive initializes an AngularJS application. The ng-init directive initializes application data. The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.
Just to add more details for @Igor Pantovic answer about ^
prefix from AngularJS $compile guide:
(no prefix) - Locate the required controller on the current element. Throw an error if not found.
? - Attempt to locate the required controller or pass null to the link fn if not found.
^ - Locate the required controller by searching the element and its parents. Throw an error if not found.
^^ - Locate the required controller by searching the element's parents. Throw an error if not found.
?^ - Attempt to locate the required controller by searching the element and its parents or pass null to the link fn if not found.
?^^ - Attempt to locate the required controller by searching the element's parents, or pass null to the link fn if not found.
It's exactly what you guessed: ?
makes a directive optional.
Basically, these are at your disposal when defining directive requirements:
someDirective
: Require someDirective on same element and pass it to linking function?someDirective
: Pass someDirective controller if available on same element to linking function. If not, pass null.^someDirective
: Require someDirective on one of the parent elements and pass it to linking function.?^someDirective
: Pass someDirective controller if available on one of parent elements to linking function. If not, pass null.If your directive requires multiple other directives, you can use the same thing but pass an array like so:
require: ['firstRequiredDirective', '^secondRequiredDirective']
This time, you will get an array of required directive's controllers passed to your linking function.
In your case, if element having your contenteditable
directive has ngModel
, ngModelController will get passed to your linking function.
If there is no ngModel
directive on it, it will pass null
.
You are correct that ?
makes the required directive optional. Meaning that null will be returned in the link function of the directive for that requirement. The way you are using it states that ngModel
maybe on the same element as contenteditable
but it is not actually required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With