简体   繁体   中英

ng-bind-html not displaying until click of anchor tag or ng-click

I have a little method that computes user rating average and outputs it as a visual representation to the user.

The problem I'm running into is the method's results for both rating and rateDisplay aren't displayed until I click on an anchor tag or executing an ng-click. I can't figure out why, as the method and any anchor tag/ng-clicks are completely independent of each other. I've tried logging to make sure it's executing when I want it to and it is. Before, when I was using handlebars, I didn't have any problems displaying the visual representation with the triple bracket escaping. But since moving to Angular, I'm having problems with this. I have included ngSanitize as a dependency.

quickblox.js

    listRatings: function(names, businesses) {
            var data = { _parent_id: names };

            QB.data.list("Comments", data, function(err, result) {

                if (err) {
                    // console.log("There was an error: " + err);
                } else {
                    console.log('ok we start nao');    // confirm we execute when we need to
                    var comps = {};

                    for (var i=0, len=result.items.length; i<len; i++) {
                        if (!comps[result.items[i]._parent_id]) {
                            comps[result.items[i]._parent_id] = [];
                        }
                        comps[result.items[i]._parent_id].push(result.items[i]);
                    }

                    for (var name in names) {
                        if (!(names[name] in comps)) {
                            for (var business in businesses) {
                                if (businesses[business].id == names[name]) {
                                    businesses[business].rating = '';
                                    businesses[business].rateDisplay = '  No comments yet, be the first!'.substr(1);
                                }
                            }
                        } else {
                            var sum = 0;

                            for (var j=0, len=comps[names[name]].length; j<len; j++) {
                                sum += parseInt(comps[names[name]][j].rating);
                            }

                            var avg = sum/comps[names[name]].length;

                            var avgFinal = 0;

                            if (avg.toFixed(1) % 1 === 0) {
                                avgFinal = avg + '/5';
                            } else if (avg.toFixed(1) % 1 !== 0) {
                                avgFinal = avg.toFixed(1) + '/5';
                            }

                            var needsHalf = (avg.toFixed(1) % 1);

                            var fullRating = '';

                            for (var k=0; k<5; k++) {
                                if (k < Math.floor(avg)) {
                                    fullRating += '<span class="icon-circle"></span>';
                                }
                                else if (needsHalf) {
                                    fullRating += '<span class="icon-half"></span>';
                                    needsHalf = false;
                                }
                                else {
                                    fullRating += '<span class="icon-none"></span>';
                                }
                            }

                            for (var business in businesses) {
                                if (businesses[business].id === names[name]) {
                                    businesses[business].rating = avgFinal;
                                    businesses[business].rateDisplay = fullRating;
                                }
                            }
                        }
                    }
                }
            });
        }

results.js

    $scope.businesses = [];
    $scope.results = [];       // didn't show how I populate this, not necessary 
    var names = [];

    // grab data to be applied to $scope.businesses
    getData.getBusinesses()
        .then(function(data) {

            var tempBusinesses = data,
                tempConditionData;

            for (var business in tempBusinesses) {

                tempConditionData = tempBusinesses[business].conditionData;

                for (var condition in tempConditionData) {
                    if (tempConditionData[condition].id === $scope.results.id && tempConditionData[condition].published === true) {
                        names.push(tempBusinesses[business].id);
                        $scope.businesses.push(tempBusinesses[business]);
                    }   
                }
            }
        })
        .then(function() {
            quickblox.listRatings(names, $scope.businesses);
        })
        .then(function() {
            $scope.dataLoaded = true;
        }, 
        function(err) {
            $log.log('something went wrong: ' + err);
        });

Lastly,

results.html

<tr ng-repeat="business in businesses | orderBy:sortBy:reverse">
    <td class="4u provider-info">
        {{business.name}} 
        <br> 
        <span ng-bind-html="business.rateDisplay"></span> <small>{{business.rating}}</small> 
    </td>
</tr>

I've also ran a JSHint several times and I'm not coming up with any errors. Any thoughts?

EDIT

As per requested, here's my code for getBusinesses()

appData.factory('getData', ['$q', '$http', function($q, $http) {
    'use strict';

    var baseURL = 'http://someapiurl.com/';

    return { 
        // ...
        getBusinesses:function() {
            return $http.get(baseURL + 'businesses')
                .then(function(res) {
                    if (typeof res.data === 'object') {
                        return res.data;
                    } else {
                        return $q.reject(res.data);
                    }
                },
                function(err) {
                    return $q.reject(err.data);
                });
        }
    };
});

Without fully knowing what is going on under the covers, I'm going to take a guess that you have an async operation happening outside of the "Angular-world". In other words, Angular is not aware that a change to a scope-exposed variable has happened and a digest cycle is not triggered, until you have clicked on a button with ng-click , for example, that triggers a digest.

The likely place where it is happening is here:

QB.data.list("Comments", data, function(err, result) {

});

This is an async operation, correct? With the handler function invoked on completion?

If you assign anything to the scope variable there, it would not be visible to Angular, unless you invoke $scope.$apply . Let's assume you factored out the current handler function as yourCurrentHandler :

function yourCurrentHandler(err, result){
   // whatever you do right now
   // ...
}

QB.data.list("Comments", data, function(err, result) {
   $scope.$apply(function(){ 
      yourCurrentHandler(err, result); 
   }); 
});

plunker with an illustrative example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM