Make a Chart with multiple Sharepoint lists (using AngularJS)
-
26-01-2021 - |
Domanda
few days ago I posted a question on how to do a Chart with AngularJS of a sharepoint list, here's the link.
Now I have a more complicated one: how to make a chart with multiple lists? I'm using AngularJS and angular-chart.js
As I'm very new working with code (I'm no developer), I find it a little difficult to understand some things about this. I've found some coding on how to make a controller with multiple $http calls, like here.
Now my problem: I need to count the number of Items of each list and how many of these items have Status=="Completed". So I want to be able to make multiple $http requests in a single controller. Based on the code of the link I mentioned before, I made this:
<!DOCTYPE html>
<html>
<head>
<script src="jquery-2.1.4.min.js"></script>
<script src="angular.js"></script>
<script src="Chart.js"></script>
<script src="angular-chart.min.js"></script>
<script>
var spApp = angular.module("spApp", ["chart.js"]);
//I created a Factory to call the different lists
spApp.factory("myLists", function($http) {
return {
americaTracker: function() {
return $http.get("SiteURL/_api/web/lists/getByTitle('America List')/items");
},
europeTracker: function() {
return $http.get("SiteURL/_api/web/lists/getByTitle('Europe List')/items");
},
asiaTracker: function() {
return $http.get("SiteURL/_api/web/lists/getByTitle('Asia List')/items");
},
//This last one is a list where I write the names of the previous task lists
listSummary: function() {
return $http.get("SiteURL/_api/web/lists/getByTitle('Lists Summary')/items");
}
}
});
spApp.controller("BarCtrl", function(myLists, $scope) {
//each of these functions are supposed to count how many items the list have, and how many of those have Status "completed":
function americaTracker() {
var promise = myLists.americaTracker();
promise.then (
function(response) {
$scope.dataResults = response.data;
var items = $scope.dataResults,
ameItems = 0,
ameCompleted = 0;
for(var i = 0 ; i< items.length; i++){
ameItems++;
var currentItem = items[i];
if(currentItem.Status=="Completed"){
ameCompleted++;
}
};
return {
ameItems: ameItems,
ameCompleted: ameCompleted
}
}
);
}
function europeTracker() {
var promise = myLists.europeTracker();
promise.then (
function(response) {
$scope.dataResults = response.data;
var items = $scope.dataResults,
eurItems = 0,
eurCompleted = 0;
for(var i = 0 ; i< items.length; i++){
eurItems++;
var currentItem = items[i];
if(currentItem.Status=="Completed"){
eurCompleted++;
}
};
return {
eurItems: eurItems,
eurCompleted: eurCompleted
}
}
);
}
function asiaTracker() {
var promise = myLists.asiaTracker();
promise.then (
function(response) {
$scope.dataResults = response.data;
var items = $scope.dataResults,
asiItems = 0,
asiCompleted = 0;
for(var i = 0 ; i< items.length; i++){
asiItems++;
var currentItem = items[i];
if(currentItem.Status=="Completed"){
asiCompleted++;
}
};
return {
asiItems: asiItems,
asiCompleted: asiCompleted
}
}
);
}
//this function is supposed to collect the names of each item (which are the names of the other three lists)
function listSummary() {
var promise = myLists.listSummary();
promise.then (
function(response) {
$scope.dataResults = response.data;
var items = $scope.dataResults, arrayLabels = [];
for(var i = 0 ; i< items.length; i++){
var currentItem = items[i];
arrayLabels.push(currentItem.LinkTitle);
};
return arrayLabels;
}
)
}
//Here I'm trying to call the functions by their specific value: the number of items and the items with status "completed"
var ameList = americaTracker(),
eurList = europeTracker(),
asiList = asiaTracker(),
listSum = listSummary();
$scope.labels = listSum.arrayLabels;
$scope.series = ['Items', 'Items Completed'];
$scope.data = [
[ameList.ameItems, eurList.eurItems, asiList.asiItems],
[ameList.ameCompleted, eurList.eurCompleted, asiList.asiCompleted]
]
});
</script>
</head>
<body>
<div ng-app="spApp" ng-controller="BarCtrl">
<canvas id="bar" class="chart chart-bar"
chart-data="data" chart-labels="labels" chart-series="series">
</canvas>
</div>
</body>
</html>
The error the console is giving me is Cannot read property 'arrayLabels' of undefined
. But the thing is I don't really know how to do this, specially the call of multiple https.
I've been a lot of time doing this, I need help. Thanks!
P.D. Also I don't know if I have to call $scope.dataResults = data.d.results;
. That's how I usually call the data.
Soluzione
I found out the solution (after almost 2 months, I was kinda busy).
I decided to use $q.all to make the requests, this is a simpler solution instead of "promises" (which I wasn't very sure how it works):
<!DOCTYPE html>
<html>
<head>
<script src="jquery-2.1.4.min.js"></script>
<script src="angular.js"></script>
<script src="Chart.js"></script>
<script src="angular-chart.min.js"></script>
<script>
var spApp = angular.module("spApp", ["chart.js"]);
spApp.factory("myLists", ["$http", function($http) {
return {
americaTracker: function() {
//I decided to use the "traditional" way to call each list:
return $http({
method: "GET",
url: "siteURL/_api/web/lists/getByTitle('America List')/items",
headers: {"Accept": "application/json; odata=verbose"}
});
},
europeTracker: function() {
return $http({
method: "GET",
url: "siteURL/_api/web/lists/getByTitle('Europe List')/items",
headers: {"Accept": "application/json; odata=verbose"}
});
},
asiaTracker: function() {
return $http({
method: "GET",
url: "siteURL/_api/web/lists/getByTitle('Asia List')/items",
headers: {"Accept": "application/json; odata=verbose"}
});
},
listSummary: function() {
return $http({
method: "GET",
url: "siteURL/_api/web/lists/getByTitle('Lists Summary')/items",
headers: {"Accept": "application/json; odata=verbose"}
});
}
}
}]);
//I'm using $q.all to call each list data
spApp.controller("BarCtrl", function($scope, $http, myLists, $q) {
$q.all([
myLists.americaTracker().then(function onSuccess(response) {
var items = response.data.d.results,
totalItems = 0,
itemCompleted = 0;
for (var i=0;i<items.length;i++) {
totalItems++;
var currentItem = items[i];
if(currentItem.Status=="Completed"){
itemCompleted++;
}
};
$scope.ameItems = totalItems;
$scope.ameComp = itemCompleted;
}),
myLists.europeTracker().then(function onSuccess(response) {
//I'm using the same names for these variables, as they are all local
var items = response.data.d.results,
totalItems = 0,
itemCompleted = 0;
for (var i=0;i<items.length;i++) {
totalItems++;
var currentItem = items[i];
if(currentItem.Status=="Completed"){
itemCompleted++;
}
};
$scope.eurItems = totalItems;
$scope.eurComp = itemCompleted;
}),
myLists.asiaTracker().then(function onSuccess(response) {
var items = response.data.d.results,
totalItems = 0,
itemCompleted = 0;
for (var i=0;i<items.length;i++) {
totalItems++;
var currentItem = items[i];
if(currentItem.Status=="Completed"){
itemCompleted++;
}
};
$scope.asiItems = totalItems;
$scope.asiComp = itemCompleted;
}),
myLists.listSummary().then(function onSuccess(response) {
var items = response.data.d.results,
arrayLabels = [];
for (var i=0;i<items.length;i++) {
var currentItem = items[i];
arrayLabels.push(currentItem.LinkTitle);
};
$scope.labels = arrayLabels;
})
]).then(function() {
//Here I call the values for each $scope object
//except "labels" which was already defined in "listSummary()"
$scope.series = ['Items', 'Items Completed'];
$scope.data = [
[$scope.ameItems, $scope.eurItems, $scope.asiItems],
[$scope.ameComp, $scope.eurComp, $scope.asiComp]
];
});
});
</script>
</head>
<body>
<div ng-app="spApp" ng-controller="BarCtrl">
<canvas id="bar" class="chart chart-bar"
chart-data="data" chart-labels="labels" chart-series="series">
</canvas>
</div>
</body>
</html>
Altri suggerimenti
You are trying to use listSum.arrayLabels
but what you have done in your code in function listSummary()
is returned arrayLabels. So, as per your code, listSum = arrayLabels
(listSum is nothing but arrayLabels). So you can directly try using listSum as given below:
$scope.labels = listSum;