jcuenod
jcuenod

Reputation: 58425

Question Mark in Directive Require

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?

Upvotes: 31

Views: 9083

Answers (3)

Jenya
Jenya

Reputation: 1145

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.

Upvotes: 33

Igor Pantović
Igor Pantović

Reputation: 9246

It's exactly what you guessed: ? makes a directive optional.

Basically, these are at your disposal when defining directive requirements:

  1. someDirective : Require someDirective on same element and pass it to linking function
  2. ?someDirective : Pass someDirective controller if available on same element to linking function. If not, pass null.
  3. ^someDirective : Require someDirective on one of the parent elements and pass it to linking function.
  4. ?^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.

Upvotes: 44

Enzey
Enzey

Reputation: 5254

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.

Upvotes: 1

Related Questions