5

First a brief description of what I want to do: I want to iterate through the elements of an array and displaying its content. Based on the information I get from the element inside the array, I want to show a button- or not.

But this seems not to work. Let's have a look at the code:

<div class="padding20" ui-view="create-event-form" ng-controller="detailedViewController" ng-init="loadDetails()">
 <button type="submit" class="button success" ng-if="getParticipationStatus(eventDetails._id)">Participate on this event!</button>

As you see, I access inside by ng-if a method from my detailedViewController. The detailedViewController contains the following method:

$scope.getParticipationStatus = function( eventId ) {
    var userName = cookieUserManagement.getUsername();
    userClient.getUserEvents( eventId, userName, function ( success, hostingList ) {
        var i = 0;
        var participationStatus;
        if ( success ) {
            hostingList = hostingList.ownEvents;
            if (hostingList.length > 0) {
                for (i = 0; i < hostingList.length; i++) {
                    if (hostingList[i]._id == eventId) {
                        participationStatus = true;
                    } else {
                        participationStatus =  false;
                    }
                }
                return participationStatus;
            }
        }
    } );
};

And now the problem: All parameters are handled in a correct way. I see the right ID's, right objects, everything seems to be correct. But this piece of code results in a endless loop (i.e. put in an alert and enjoy never ending alerts from your browser) and the following error message:

angular.js:13642TypeError: callback is not a function
at services.js:374
at angular.js:16104
at m.$eval (angular.js:17378)
at m.$digest (angular.js:17191)
at m.$apply (angular.js:17486)
at l (angular.js:11637)
at D (angular.js:11843)
at XMLHttpRequest.w.onload (angular.js:11776)(anonymous function) @ angular.js:13642


angular.js:13642Error: [$rootScope:infdig] http://errors.angularjs.org/1.5.6/$rootScope/infdig?p0=10&p1=%5B%5D
at Error (native)
at http://127.0.0.1:3000/node_modules/angular/angular.min.js:6:412
at m.$digest (http://127.0.0.1:3000/node_modules/angular/angular.min.js:143:281)
at m.$apply (http://127.0.0.1:3000/node_modules/angular/angular.min.js:145:401)
at l (http://127.0.0.1:3000/node_modules/angular/angular.min.js:97:250)
at D (http://127.0.0.1:3000/node_modules/angular/angular.min.js:101:373)
at XMLHttpRequest.w.onload (http://127.0.0.1:3000/node_modules/angular/angular.min.js:102:397)

As far as I see, I have declared everything in a right way. But I don't know why this is resulting in an endless loop.

Any help appreciated! Thanks in advance.

Karlo Kraljic
  • 173
  • 2
  • 11
  • 5
    Yes, because using a function inside `ngIf` is one of the worst practices you can have. It will call it over and over on each digest loop. You need to bind the expression to a property which represent the result of `getParticipationStatus()` (Rather than the function itself) – Alon Eitan Jun 02 '16 at 13:44
  • 1
    It looks like your function `getUserEvents` is async and you are returning from callback. No code will actually observe the value of `participationStatus`, You might need to save it in scope `$scope.participationStatus = participationStatus;` and use this value in `ng-if="participationStatus"` – Yury Tarabanko Jun 02 '16 at 13:50
  • Yes, you are very right. The keyword "asynchronity" lead me to the final solution. Thank you both! – Karlo Kraljic Jun 02 '16 at 15:23

1 Answers1

3

The function inside your ng-if is async so it does not return the boolean value as angular expects it. It could even not return the value at all because the callback would not be called.

I recommend changing the observed ng-if property to a scope variable instead of a function call. Then you can call your async function whenever you want (by setInterval or whatever...but you should asolutely find a better way) and in the callback, just set the scope variable to true or false. Ng-if "watches" for the variable's value and will fire a digest in which the element will or will not be rendered. So it should look something like this in the view:

<div class="padding20" ui-view="create-event-form" ng-controller="detailedViewController" ng-init="loadDetails()">
<button type="submit" class="button success" ng-if="participationStatus">Participate on this event!</button>

And the controller method:

$scope.getParticipationStatus = function( eventId ) {
    var userName = cookieUserManagement.getUsername();
    userClient.getUserEvents( eventId, userName, function ( success, hostingList ) {
        var i = 0;
        if ( success ) {
            hostingList = hostingList.ownEvents;
            if (hostingList.length > 0) {
                for (i = 0; i < hostingList.length; i++) {
                    if (hostingList[i]._id == eventId) {
                        $scope.participationStatus = true;
                    } else {
                        $scope.participationStatus =  false;
                    }
                }
            }
        }
    } );
};

The only thing left is to call the method for example upon controller intialization, so just $scope.getParticipationStatus($scope.eventDetails._id) inside the controller function's body.

Jaromír Šetek
  • 478
  • 2
  • 8
  • I think you should include the changes needed in the view and the controller, since it seen like the OP don't understand how async calls work – Alon Eitan Jun 02 '16 at 14:03
  • 1
    You're right. I tried to make as few changes as possible..Suppose this should work. – Jaromír Šetek Jun 02 '16 at 14:40
  • Thank you for your great work. I did not implement it in exactly this way. In my HTML I added, in the same way as you did it: And added to my controller the following line(s) (for more readability I did not copy the logic to get the result TRUE or FALSE): detailedObject.participateStatus = participationStatus ; And call the method to put this value to my JSON object with ng init. Thank you for your great example! – Karlo Kraljic Jun 02 '16 at 15:25