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

(bug) ngAnimate options.domOperation is not a function #11713

Closed
paveleremin opened this issue Apr 24, 2015 · 12 comments
Closed

(bug) ngAnimate options.domOperation is not a function #11713

paveleremin opened this issue Apr 24, 2015 · 12 comments

Comments

@paveleremin
Copy link

Few days ago at production error occured:

TypeError: options.domOperation is not a function
options.domOperation();
angular...mate.js (line 2747, col 8)

https://github.com/angular/angular.js/blob/master/src/ngAnimate/animateQueue.js#L432

First I don't have this error at local machine, but after update Bower dependencies(bower update) I got it.

Here is my bower.json
...
"angular": "~1.4.0",
"angular-animate": "~1.4.0",
...

@seldary
Copy link

seldary commented Apr 25, 2015

It happens in our app as well.
It is definitely a bug introduced in v1.4.0-rc.0.
I just downgraded angularjs to v1.4.0-beta.6, and it works fine.

@paveleremin
Copy link
Author

@seldary, can you provide hash of the commit v1.4.0-beta.6, please?
Also, seems we must add author of it to the issue

@Narretz
Copy link
Contributor

Narretz commented Apr 27, 2015

Can you try to isolate the problem and put a repro in a plnkr etc.?

@seldary
Copy link

seldary commented Apr 27, 2015

I recreated the issue, as isolated as possible.
It uses angular-strap. I now suspect that this plugin simply doesn't support angular 1.4. I might be wrong.

It fails on the call to $digest here (angularStrap code):

    function safeDigest(scope) {
      scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
    }

@e-oz
Copy link

e-oz commented Apr 27, 2015

it's not bug of the angular-strap. I wrapped all calls of options.domOperation() by if (angular.isFunction(options.domOperation)) check and now all my e2e tests are green again. So I think options.domOperation is not declared somewhere.

@Narretz
Copy link
Contributor

Narretz commented Apr 28, 2015

The API for animations has changed a bit, so it's alos possible that angular-strap needs to change something.

@paveleremin
Copy link
Author

@mgcrea what do you think about that?

@mgcrea
Copy link
Contributor

mgcrea commented Apr 29, 2015

I've not investigated this issue due to lack of time, but I know that I'd like to keep 1.2+ backward compatibility for angular-strap. I'm quite confident we will find a suitable workaround for the v1.4 release, even if this issue does make it to the final release. Though it looks like this could be handled on the ngAnimate side, I would understand them not patching it since it's not a patch release and things are expected to break, I'm fine with the idea of having the burden of retro-compat carried by the libs if it can lead to a cleaner core.

Ideally we should try to come up with a simple failing test. Had glimpse at the changelog, it looks like the issue might come from c8700f0, especially the new auto-digest on chained promise breaking change.

For reference, AngularStrap uses this code for its tooltip (and therefore all derivatives), the choice was historically made to manually manage local-only digests on the tooltip scope during show/hide events to prevent triggering full root digests on every tooltip-enabled element hovering.

          // Hide any existing tipElement
          if(tipElement) destroyTipElement();
          // Fetch a cloned element linked from template
          tipScope = $tooltip.$scope.$new();
          tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});

          // Set the initial positioning.  Make the tooltip invisible
          // so IE doesn't try to focus on it off screen.
          tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});

          // Append the element, without any animations.  If we append
          // using $animate.enter, some of the animations cause the placement
          // to be off due to the transforms.
          after ? after.after(tipElement) : parent.prepend(tipElement);

          $tooltip.$isShown = scope.$isShown = true;
          safeDigest(scope);

          // Now, apply placement
          $tooltip.$applyPlacement();

          // Once placed, animate it.
          // Support v1.3+ $animate
          // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9
          var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);
          if(promise && promise.then) promise.then(enterAnimateCallback);
          safeDigest(scope);

          $$rAF(function () {
            // Once the tooltip is placed and the animation starts, make the tooltip visible
            if(tipElement) tipElement.css({visibility: 'visible'});
          });

A potential fix for v1.4 might be something like:

          if(promise && promise.then) promise.then(enterAnimateCallback);
          else safeDigest(scope);

But that would break v1.3.

I'll try to investigate further in the coming days.

@matsko
Copy link
Contributor

matsko commented May 4, 2015

The bug has nothing to do with digests. The issue is that there is a function being passed in to the final parameter of enter:

var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);

So towards the end of the close function inside of ngAnimate we get the following value for the options value when console.log(options) is called:

function enterAnimateCallback() {
  scope.$emit(options.prefixEvent + '.show', $tooltip);
}

Long story short, the final param needs to be omitted for 1.3+ (due to promises). So @mgcrea do you have a clean way of doing this? We could patch ngAnimate to ignore non-object params for the 4th parameter but you would still be doing this in 1.3.

@e-oz
Copy link

e-oz commented May 5, 2015

Maybe not only angular-strap doing it, if it was valid in previous versions... Maybe it's the breaking change that should be announced. Or @matsko could make it non-breaking by additional check.

matsko added a commit to matsko/angular.js that referenced this issue May 7, 2015
…passed in

Earlier versions of Angular expected a function to be passed into the
same param as the options value. This causes a nasty issue since the
internal animation code expects the options value to be an object
instead of a function. This patch adds the code to convert a function
value into an empty object when that occurs.

Closes angular#11713
@matsko
Copy link
Contributor

matsko commented May 7, 2015

In this situation it's better to have the 1.4 $animate code do the checking: #11826

matsko added a commit to matsko/angular.js that referenced this issue May 7, 2015
…passed in

Earlier versions of Angular expected a function to be passed into the
same param as the options value. This causes a nasty issue since the
internal animation code expects the options value to be an object
instead of a function. This patch adds the code to convert a function
value into an empty object when that occurs.

Closes angular#11713
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue May 11, 2015
…hods

As of bf0f550 (released in 1.3.0) it is no longer
valid to pass a callback to the following functions: `enter`, `move`, `leave`, `addClass`,
`removeClass`, `setClass` and `animate`.

To prevent confusing error messages, this change asserts that this parameter is
not a function.

Closes angular#11826
Closes angular#11713
petebacondarwin added a commit that referenced this issue May 14, 2015
…hods

As of bf0f550 (released in 1.3.0) it is no longer
valid to pass a callback to the following functions: `enter`, `move`, `leave`, `addClass`,
`removeClass`, `setClass` and `animate`.

To prevent confusing error messages, this change asserts that this parameter is
not a function.

Closes #11826
Closes #11713
@mgcrea
Copy link
Contributor

mgcrea commented May 20, 2015

Fixed in angular-strap by mgcrea/angular-strap@afd4fc7, thanks @matsko for the bug insights.

netman92 pushed a commit to netman92/angular.js that referenced this issue Aug 8, 2015
…hods

As of bf0f550 (released in 1.3.0) it is no longer
valid to pass a callback to the following functions: `enter`, `move`, `leave`, `addClass`,
`removeClass`, `setClass` and `animate`.

To prevent confusing error messages, this change asserts that this parameter is
not a function.

Closes angular#11826
Closes angular#11713
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.