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

One time binding does not work with expression bindings #11416

@fenduru

Description

@fenduru

I am writing a directive that has an expression (&) binding, and I want my consumers to be able to pass a one time binding if they wish. For instance, both of the following uses should be valid:

<my-directive option="::someOption"></my-directive>
<my-directive option="someOption"></my-directive>

I want to do this because the consumer of my directive knows whether or not their expression is ever going to change, and would like them to be able to add this optimization.

The problem is that if I use scope.$watch to watch the option, the listener still runs multiple times:

{
  restrict: 'E',
  scope: {
    option: '&'
  },
  link: function( scope ) {
    scope.$watch( 'option()', function() {
      // may run multiple times even if the user provided the expression "::someoption"
    }
}

The workaround for this is to use scope.$parent.$watch, but this seems like it should not be the primary way of consuming expressions. I think that expression bindings should benefit from one time bindings automatically, without the directive-writer having to think about whether or not the consumer might have a valid use-case to use a one time binding.

I think reason this is happening is due to the fact that while the parsed expression has metadata indicating that it should only be run once, the & binding wraps that function in order to pre-bind it to the correct scope, but does not copy the relevant metadata.

Here is a plunker demonstrating the behavior

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions