0

I know that the ng-if directive creates a new child scope and I would like to know HOW and IF it is possible to play a ng-if into an other one.

For now I can't see any icons. I've tried ng-hide, but I saw the two icons in the same time, impossible to fix that problem...I also tried ng-show, but with the same results as ng-if.

Set() function returns true or false, it's working because I can see the result in the console.

Any ideas ?

$scope.set = function($r)
{
    firebase.database().ref('events/'+$r.selfID).once("value").then(function(snapshot)
    {   
        var nbPerson = snapshot.val().nbPerson;
        var varPerson = snapshot.val().varPerson;

        //console.log("nbPerson :", nbPerson);
        //console.log("varPerson", varPerson);

        if(nbPerson === varPerson)
        {
            //console.log("true");
            return true;
        }
        else
        {
            //console.log("false");
            return false;
        }
    });
};
<button ng-if ="give(f) === false" class="badge badge-positive" ng-click="joinEvent(e)">

    <span ng-if ="set(r) === true">
        <ion-icon class="ion-person-add give-var"></ion-icon>
    </span>


    <span ng-if ="set(r) === false">
        <ion-icon class="ion-person-add var"></ion-icon>
    </span>

</button>

EDIT :

I added the set() function, $r is a record from a Firebase DB, it has a "selfID" variable with his record ID.

I'm sure that give() function is working, because I have an other button running with the ng-if="give(f) === true".

This entire code is working on the same controller.

EDIT 2 : (new snippet)

EDIT 3 : (add $q in dependency)

function ($scope, $rootScope, $q, $stateParams, $firebase, $firebaseArray, $state, $ionicPopup) {

    $scope.set = function($r)
    {
        $scope.varPerson = "";
        $scope.nbPerson = "";

        var basePromise = firebase.database().ref('events/'+$r.selfID).once("value");

        $q.when(basePromise).then(function(snapshot)
        {
            $scope.nbPerson = snapshot.val().nbPerson;
            $scope.varPerson = snapshot.val().varPerson;

            if($scope.nbPerson === $scope.varPerson)
            {
                return true;
            }
            else
            {
                return false;
            }
        });
    }
};

EDIT 4 : (Finally)

Ok, I wasn't able to cope with the synchronous problems, so I simply add a test inside the two ng-if, so without the set() function.

Thanks a lot for those who helped me, and especially @georgeawg for his expertise !

    <span ng-if ="r.nbPerson === r.varPerson">
        <ion-icon class="ion-person-add give-var"></ion-icon>
    </span>

    <span ng-if ="r.nbPerson > r.varPerson">
        <ion-icon class="ion-person-add var"></ion-icon>
    </span>

Memphis
  • 410
  • 5
  • 23
  • Are you sure give(f) is returning the expected result? – Achshar Apr 21 '17 at 17:20
  • Are these `give` and `set` functions modifying the state of the controller? Could you provide these JS snippets? – sp00m Apr 21 '17 at 17:20
  • Please provide all relevant code in an [mcve]. Right now, there's no way of knowing what's wrong. It could be that your `set` function, in the scope of the `ng-if`, is returning `undefined`, which would not match `true` or `false`... – Heretic Monkey Apr 21 '17 at 17:26
  • Doesn't `ion-icon` use the `name` attribute and not the `class` attribute for setting the icon? – Lex Apr 21 '17 at 17:30
  • As I edited my post, yes give(f) provides me the right results. Give() and set() are in the same controlleur, the first one is working, the other one not... – Memphis Apr 21 '17 at 17:40
  • The [return statements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return) in side `.then` blocks do not return values to the parent function. The code inside `.then` blocks execute asynchronously *after* the parent function completes. The Angular expression for an `ng-if` needs to be synchronous and idempotent. Also the promises returned by the firebase API are not integrated with the Angular framework. – georgeawg Apr 21 '17 at 19:06

2 Answers2

2

I suggest to use the controllerAs syntax to ensure correct scope access and control.

HTML:

<body ng-controller="MainCtrl as ctrl">
  <div ng-if="ctrl.showParent()">
    <h3>Parent is allowed</h3>
    <div ng-if="ctrl.showChildren()">Children are allowed</div>
    <div ng-if="ctrl.showChildren()">Children are allowed</div>
  </div>
  <button ng-click="ctrl.toggle()">Toggle Children</button>
</body>

JS

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  var allowParent_ = true;
  var allowChildren_ = false;
  this.toggle = function() {
    allowChildren_ = !allowChildren_;
  }
  this.showParent = function(){
    return allowParent_;
  }

  this.showChildren = function() {
    return allowChildren_;
  }
});
Phix
  • 9,364
  • 4
  • 35
  • 62
  • Thanks for this answer, but I tried and neither the button or icon appears... But I'm not sure I implemented your exemple very well – Memphis Apr 21 '17 at 17:44
2

Firebase promises are not AngularJS promises

Promises returned by the firebase API are not integrated with the AngularJS framework.

Use $q.when to create an AngularJS promise from a firebase promise:

var basePromise = firebase.database().ref('events/'+$r.selfID).once("value");
$q.when(basePromise).then(function(snapshot)
    {
       //.then block code   
    });

AngularJS modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and AngularJS execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc.

The firebase promise needs to be converted to an AngularJS promise to bring the event into the AngularJS execution context.


To debug the $scope.set function:

Save the returned value and log it.

$scope.set = function($r) {
    var value = set($r);
    console.log(value);
    return value;
}); 

//BUGGY function
function set($r)
{
    firebase.database().ref('events/'+$r.selfID).once("value").then(function(snapshot)
    {   
        var nbPerson = snapshot.val().nbPerson;
        var varPerson = snapshot.val().varPerson;
        
        //console.log("nbPerson :", nbPerson);
        //console.log("varPerson", varPerson);
        
        if(nbPerson === varPerson)
        {
            //console.log("true");
            return true;
        }
        else
        {
            //console.log("false");
            return false;
        }
    });
};
  

By using this simple debugging technique, you will quickly understand the problem.


the result of my set() function is unreachable... :( Is my new function (Edit 3), correct ?

The return statements inside .then blocks do not return values to the parent function. The code inside .then blocks execute asynchronously after the parent function completes.

JavaScript is single-threaded. Functions complete immediately. They can not return values created in .then blocks. They can only return values that are produced immediately and synchronously or they can return pending promises that later asynchronously resolve to some value.

Expaination of Promise-Based Asynchronous Operations

console.log("Part1");
console.log("Part2");
var promise = $http.get(url);
promise.then(function successHandler(response){
    console.log("Part3");
});
console.log("Part4");

pic

The console log for "Part4" doesn't have to wait for the data to come back from the server. It executes immediately after the XHR starts. The console log for "Part3" is inside a success handler function that is held by the $q service and invoked after data has arrived from the server and the XHR completes.

For more information, see How to use $http promise response outside success handler.


Demo

console.log("Part 1");
console.log("Part 2");
var promise = new Promise(r=>r());
promise.then(function() {
    console.log("Part 3");
});
console.log("Part *4*");
Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Oooh thank you ! I didn't noticed the synchronous problems between Firebase and AngularJS, indeed when I check there were nothing coming out from the firebase request. That seemed like a delay... I tried (EDIT 2, of the main post) what you suggested to me, but I got a "$q is not defined error", am I forgetting something ? – Memphis Apr 21 '17 at 19:47
  • You need to inject `$q` into the controller. See [AngularJS Developer Guide - Dependency Injection](https://docs.angularjs.org/guide/di). – georgeawg Apr 21 '17 at 19:56
  • Arf, I added $q, and I'm sure I'm close to something, but still from ng-if, the result of my set() function is unreachable... :( Is my new function (Edit 3), correct ? – Memphis Apr 21 '17 at 20:05