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.