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

weird behavior with already resolved promises inside a digest in 1.4.1 with ngShow and ngAnimate #12143

Closed
jlowcs opened this issue Jun 17, 2015 · 7 comments

Comments

@jlowcs
Copy link

jlowcs commented Jun 17, 2015

I have stumbled upon a weird behavior when migrating to angular 1.4.

I'll try to create a plunkr example when/if I have the time later.

For the time being, here's the issue's description.

Here's a simple controller:

var promises = {};

function getElt(eltId) {
  var p = promises[eltId];

  if (!p) {
    promises[eltId] = p = getEltPromise(eltId);
  }

  return p;
}

function MyCtrl($scope) {
  $scope.$digest('eltId', function (eltId) {
    this.elt = null;
    getElt(eltId)
    .then(function (elt) {
      this.elt = elt;
    })
  }  
}

The controller watches an id, and updates an elt when the id changes.

The elt is retrieved using a function that returns a $q promise. elt is set to null to indicate the loading state.

The function uses a cache of $q promises, so that it will return the already resolved promise if it is called with an id it already knows.

When the function returns an already resolved promise, the digest seems to be in a strange state. The template still considers that the elt is null, although, when consulting the scope in the console, this.elt is not null. Calling $rootScope.$digest() doesn't change anything.

This also happens when I return a new promise that's resolved when the intiial promise is resolved (next tick since it's already resolved).

function getElt(eltId) {
  var p = promises[eltId];

  if (!p) {
    promises[eltId] = p = getEltPromise(eltId);
  }

  let d = $q.defer();
  p.then(function (chat) {
    d.resolve(chat);
  });

  return d.promise;
}

This issue does not happen if I return a completely new promise, or if I wrap the function call inside a setTimeout.

function getElt(eltId) {
  var p = promises[eltId];

  if (!p) {
    promises[eltId] = p = getEltPromise(eltId);
  }

  let d = $q.defer();
  setTimeout(function () {
    p.then(function (chat) {
      d.resolve(chat);
    });
  });

  return d.promise;
}
@lgalfaso lgalfaso added this to the Ice Box milestone Jun 17, 2015
@lgalfaso
Copy link
Contributor

Without a clean plunker that shows the error, it is not possible to even know if this is a bug or not.

I will close this as without this, there is nothing to work on. If you can get a plunker in place that shows the error, then feel free to reopen this issue.

@jlowcs
Copy link
Author

jlowcs commented Jun 18, 2015

Here's the plunkr.

http://plnkr.co/edit/52OvOOunfY0fdLelyxWR

The element sometimes has multiple values (null and undefined at the same time) when evaluated by the ng-show directives.

Juste follow the insctrutions in the plunkr.

It seems to be linked to angular-animate, since it works well without it. The issue is with ng-show, but not with ng-if.

@jlowcs
Copy link
Author

jlowcs commented Jun 18, 2015

I can't reopen the issue myself btw.

@pkozlowski-opensource
Copy link
Member

//cc: @matsko

@pkozlowski-opensource pkozlowski-opensource modified the milestones: 1.4.2, Ice Box Jun 18, 2015
@jlowcs jlowcs changed the title weird behavior with already resolved promises inside a digest in 1.4.1 weird behavior with already resolved promises inside a digest in 1.4.1 with ngShow and ngAnimate Jun 18, 2015
@petebacondarwin petebacondarwin modified the milestones: 1.4.2, 1.4.3 Jul 6, 2015
@JasonStoltz
Copy link

I wanted to +1 this.

I've been struggling with a very similar scenario recently, though I haven't been able to reproduce it in a Plunkr. In both this case and my case, we a situation where ng-show gets itself into an invalid state where the expression passed to ng-show evaluates correctly ... but the ng-show does not update the element accordingly.

This case: The expression evaluates to false, yes no ng-hide class is applied

<h1 ng-show="myCtrl.elt === null">Loading (elt is null)</h1>
scope.$eval('myCtrl.elt === null') //false

My case: The expression evaluates to true, yet the ng-hide class is never removed

<span ng-show="thing.$onStatus || isThingOn()" class="ng-hide">
scope.$eval('thing.$onStatus || isThingOn()') //false

In my case, it appears to be related to ngAnimate as well. If you trace the calls through the ngShow directive, everything looks fine, and it's not until here that things fall apart:

function queueAnimation(element, event, options) {
.

In my case ... the watched value "thing.$onStatus || isThingOn()" changes very quickly back and forth briefly ... and it seems that whenever it gets itself into this state, the hasExistingAnimation flag is true inside of the function.

Anyway, not sure if this helps or not, if i can debug this any further or reproduce in a plunk I will leave some additional information.

Note: I worked around this in the meantime by simply using ng-if, instead.

@matsko matsko modified the milestones: 1.4.3, 1.4.4 Jul 14, 2015
@sreeramu
Copy link
Contributor

@matsko I had check this issue , This issue is fixed with #12277 PR merge.

@matsko
Copy link
Contributor

matsko commented Jul 21, 2015

Works fine in 1.4.x master: http://plnkr.co/edit/dsdJKzuoC4hNYHSNk7hg?p=preview

@matsko matsko closed this as completed Jul 21, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants