AngularJS Count Yes/No Values - angularjs

I'm currently working on a AngularJS / Parse.com web application
What I'm trying to achieve:
I would like to get the total amount of Yes & No values within an Array.
e.g Yes = 3 No = 6
Current Problems:
I've managed to get all Yes & No values from Parse and put them into an Array but I'm unable to count the amount of Yes or No values.
Any help / advice would be helpful!
HTML:
<md-card>
<md-card-content>
<canvas id="doughnut" class="chart chart-doughnut" data="widgetone_data" labels="widgetone_label"></canvas>
</md-card-content>
{{widgetone_data | json}}
</md-card>
Controller JS:
dashApp.controller("dashboardCtrl", function ($scope, $http, $filter) {
$scope.parseRecommendations = [];
$http({
method : 'GET',url : 'https://api.parse.com/1/classes/Customers',
headers: { 'X-Parse-Application-Id':'xxx', 'X-Parse-REST-API-Key':'xxx'}
})
.success(function(data, error) {
$scope.parseResults = data.results;
angular.forEach($scope.parseResults, function(results) {
$scope.parseRecommendations.push(results.question_4_p1);
});
})
.error(function(data, error) {alert('Failed, error code: ' + error.message);
});
// Recommend YES/NO
var yesAmount = $filter('filter')($scope.parseRecommendations, { isSelected: 'yes' }).length;
var noAmount = $filter('filter')($scope.parseRecommendations, { isSelected: 'no' }).length;
$scope.widgetone_label = ["Yes", "No"];
$scope.widgetone_data = [yesAmount,noAmount];
});

You can use the .filter() method.
Moreover, you made an error, because you start to filter your data when the controller is instantiated, but your API call is asynchronous, so you have to filter your data into the .success() callback, otherwise you will filter an empty array.
EDIT : To improve performance, you can count your by simulating an hashmap. See below
dashApp.controller("dashboardCtrl", function ($scope, $http, $filter) {
$scope.parseRecommendations = [];
var hashmap = {};
$http({
method : 'GET',url : 'https://api.parse.com/1/classes/Customers',
headers: { 'X-Parse-Application-Id':'wmWxU64vx0QgKBiNQkx9jCDNO6UZDRrM6WkxAbTL', 'X-Parse-REST-API-Key':'0FHcBHZdeUJHKT8j0VQH0hQdN4TZ8qsOBxyd1rG3'}
})
.success(function(data, error) {
$scope.parseResults = data.results;
angular.forEach($scope.parseResults, function(results) {
$scope.parseRecommendations.push(results.question_4_p1);
});
$scope.parseRecommendations.forEach(function(elm){
hashmap.hasOwnProperty(elm)
? ++hashmap[elm]
: hashmap[elm] = 1
});
//Filter yes
var yesAmount = hashmap.yes;
//Filter no
var noAmount = hashmap.no;
$scope.widgetone_label = ["Yes", "No"];
$scope.widgetone_data = [yesAmount,noAmount];
console.log($scope.widgetone_data);
})
.error(function(data, error) {alert('Failed, error code: ' + error.message);
});
});

Related

Undefined value return by Angular

I have a Angular function to retrieve taxi annonces and i need to calculate the distance between the user connected et the author of annonce then I have something like this :
In my HTML :
<main class="main list_page" ng-controller="taxiRechercheCtrl" ng-init="loadRecherche()">
In Angular :
myApp.controller("taxiRechercheCtrl", ['$scope','$http','$location', 'TaxiService', 'UserService', function($scope, $http, $location, TaxiService, UserService){
$scope.loadRecherche = function(){
UserService.getPosition().then(function(position){
TaxiService.find($scope.recherche).then(function(response){
$scope.annonces = response.annonces;
for(var i=0;i<$scope.annonces.length;i++){
$scope.annonces[i].Distance = my calculate distance
}
}, function(err){
console.log(err);
});
}, function(err){
console.log(err);
});
};
$scope.calculeDistanceGoogle = function(origin, destination){
var origin1 = new google.maps.LatLng(origin.Latitude, origin.Longitude);
var destination1 = new google.maps.LatLng(destination.latitude, destination.longitude);
var args = {
origins: [origin1],
destinations: [destination1],
travelMode: 'DRIVING'
};
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(args, function(response, status) {
var elt = response.rows[0].elements[0];
$scope.distanceTxt = elt.distance.text;
});
return $scope.distanceTxt;
}
}
In $scope.annonces[i].Distance = my calculate distance, I want the distance value returned by my calculeDistanceGoogle function.
I tried :
$scope.calculeDistanceGoogle($scope.annonces[i].Ville, response.position).then(function(response){
console.log(response);
}, function(err){
console.log(err);
});
but I have the error : $scope.calculeDistanceGoogle(...).then is not a function.
I tried use $scope.distanceTxt variable, I try directly :
var myposition = $scope.calculeDistanceGoogle($scope.annonces[i].Ville, response.position);
The $scope.calculeDistanceGoogle(...) is not a function that return a Promise, so you can't call .then(...) clause.
And then, this code is wrong:
service.getDistanceMatrix(args, function(response, status) {
var elt = response.rows[0].elements[0];
$scope.distanceTxt = elt.distance.text;
});
return $scope.distanceTxt;
because probabily that service is asynchronous.
My suggestion is return a promise with the value of distanceTxt as data (add error if present on the promise too).

Angular - Trying to access value outside of $http get success and use it for a filter value

I'm building a silly little Football app. On the first page, I am trying to load the country's top division standings and the coming week's fixtures.
I retrieve the data, using a RESTful Web Service and so is done asynchronously. The table is fine, but not the fixtures.
There is an array of fixture objects, within them, there's a 'matchday' and 'status' property. If you look at the 'this.getFixtures' function, look at the success code block. What I am trying to do is only display the fixtures for a certain match day. If there is one game left to be played on a certain matchday, then I only want that fixture displayed. If not, display next matchday's fixtures.
The 'status' property typically has a value of 'SCHEDULED' or 'FINISHED'. In the success code block I am saying:
Loop through all fixtures retrieved.
If this fixture is scheduled, that means, we're on the matchday for this fixture.
In which case, break loop.
I am then trying to use that value outside the get method, but I keep getting undefined. Is there any way to access that value outside the success block?
I'll use the $scope.matchDay function as the filter.This will help me to only display scheduled fixtures in that matchday with ng-repeat.
Anyway, sorry for the long winded post, but here's the code:
HTML:
<div class="grid-x">
<div class="medium-8 medium-offset-2 cell">
<div id="premier-league-banner">
<div class="banner-shade">
<div class="grid-x">
<div class="medium-5 cell">
<table>
<tr ng-repeat="team in premierLeagueTable.standing | limitTo: 6">
<th>{{ $index + 1 }}</th>
<td><img class="prem-thumbnail" src="{{ team.crestURI }}" /></td>
<th>{{ team.teamName }}</th>
<th>{{ team.playedGames }}</th>
<th>{{ team.goalDifference }}</th>
<th>{{ team.points }}</th>
</tr>
</table>
</div>
<div class="medium-2 cell">
<img src="images/prem-logo.png" />
</div>
<div class="medium-5 cell">
<table>
<tr ng-repeat="fixture in premierLeagueFixtures.fixtures | filter:{matchday: 10}">
<th>{{fixture.homeTeamName}}</th>
<td>vs</td>
<th>{{fixture.awayTeamName}}</th>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
Angular JS
// MODULE
var quickEleven = angular.module('quickEleven', ['ngRoute', 'ngResource']);
// ROUTES
quickEleven.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'pages/home.htm',
controller: 'homeController'
})
});
// CONTROLLERS
quickEleven.controller('homeController', ['$scope', '$resource', '$log', 'footballData', function($scope, $resource, $log, footballData) {
function getMonday(date) {
var day = date.getDay() || 7;
if( day !== 1 )
date.setHours(-24 * (day - 1));
return date;
}
function convertDate(date) {
var yyyy = date.getFullYear().toString();
var mm = (date.getMonth()+1).toString();
var dd = date.getDate().toString();
var mmChars = mm.split('');
var ddChars = dd.split('');
return yyyy + '-' + (mmChars[1]?mm:"0"+mmChars[0]) + '-' + (ddChars[1]?dd:"0"+ddChars[0]);
}
var thisMonday = getMonday(new Date);
var nextMonday = getMonday(new Date);
nextMonday.setDate(nextMonday.getDate() + 7);
$log.info("Boom! " + convertDate(thisMonday));
$log.info("For! " + convertDate(nextMonday));
$scope.premierLeagueTable = footballData.getLeagueTable("http://api.football-data.org/v1/competitions/:competitionId/leagueTable", 445);
//http://api.football-data.org/v1/competitions/:competitionId/fixtures?timeFrameStart=2018-03-01&timeFrameEnd=2018-03-05
//"http://api.football-data.org/v1/competitions/:competitionId/fixtures/?matchday=9"
$scope.premierLeagueFixtures = footballData.getFixtures("http://api.football-data.org/v1/competitions/:competitionId/fixtures?timeFrameStart=" + convertDate(thisMonday) + "&timeFrameEnd=" + convertDate(nextMonday), 445);
$log.info($scope.premierLeagueFixtures);
$log.info($scope.premierLeagueTable);
$scope.matchdayValue = 9;
$scope.matchDay = function() {
return footballData.getMatchday();
};
}]);
quickEleven.service('footballData', ['$resource', '$log', function($resource, $log) {
//Referring to the latest matchday with the status as 'SCHEDULED'
var self = this;
var test;
self.latestScheduledMatchday = 0;
self.getMatchday = function() {
$log.info("This is: " + test);
return self.latestScheduledMatchday;
}
this.getLeagueTable = function (footballUrl, compId) {
this.footballAPI =
$resource(footballUrl, {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "f73808b698e84dccbe4886da3ea6e755"
}
}
})
.get({
competitionId: compId
}, function(data) {
this.fussball = data;
}, function(err) {
$log.error(err);
});
return this.footballAPI;
};
this.getFixtures = function (footballUrl, compId) {
// var self;
this.footballAPI =
$resource(footballUrl, {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "f73808b698e84dccbe4886da3ea6e755"
}
}
})
.get({
competitionId: compId
}, function(data) {
// self = data.fixtures;
self.latestScheduledMatchday = data.fixtures[0].matchday
for (var i = 0; i < data.fixtures.length; i++) {
var fixture = data.fixtures[i];
if (fixture.status == 'SCHEDULED') {
test = fixture.matchday;
break;
}
}
$log.info("Dollar signs... " + test);
}, function(err) {
$log.error(err);
});
return this.footballAPI;
};
}]);
I see 2 issues so far. One on the note of undefined values is your service might not be getting implemented correctly. AFAIK you should be returning the service in the "function($resource, $log) {" function.
Here's how I'd change it (note I've not tested this)
quickEleven.service('footballData', ['$resource', '$log', function($resource, $log) {
//Referring to the latest matchday with the status as 'SCHEDULED'
var wrappedService = {};
var test;
var latestScheduledMatchday = 0;
var getMatchday = function() {
$log.info("This is: " + test);
return latestScheduledMatchday;
}
wrappedService.getLeagueTable = function (footballUrl, compId) {
wrappedService.footballAPI =
$resource(footballUrl, {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "f73808b698e84dccbe4886da3ea6e755"
}
}
})
.get({
competitionId: compId
}, function(data) {
wrappedService.fussball = data;
}, function(err) {
$log.error(err);
});
return wrappedService.footballAPI;
};
wrappedService.getFixtures = function (footballUrl, compId) {
wrappedService.footballAPI =
$resource(footballUrl, {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "f73808b698e84dccbe4886da3ea6e755"
}
}
})
.get({
competitionId: compId
}, function(data) {
latestScheduledMatchday = data.fixtures[0].matchday
for (var i = 0; i < data.fixtures.length; i++) {
var fixture = data.fixtures[i];
if (fixture.status == 'SCHEDULED') {
test = fixture.matchday;
break;
}
}
$log.info("Dollar signs... " + test);
}, function(err) {
$log.error(err);
});
return wrappedService.footballAPI;
};
return wrappedService;
}]);
So instead of the function returning no service, you have your service wrapped and returned as I believe you were intending. I also removed references to "self" since your intention there (internal service variables) is more eloquently handled with var scoping in the function.
Second issue that you will see once your service is working.
$scope.premierLeagueTable = footballData.getLeagueTable("http://api.football-data.org/v1/competitions/:competitionId/leagueTable", 445);
This line does not return the request data, but returns the request object. In fact by the time $scope.premierLeagueTable is set, the request hasn't even completed yet. What you do get is access to a promise that you can put a callback function in. See the angular resource documentation for more info, specifically the third example in the user-resource section where you see .$promise https://docs.angularjs.org/api/ngResource/service/$resource#user-resource.
Whatever functionality you want to apply the data return to should live inside that .$promise.then(...) callback. I'm not entirely sure if the promise in there receives the response data, or your callback return. You'll have to read further or experiment to find that out.

Shared data between controllers using factory and promises

Ok so there is a lot out there about sharing data between controllers using factory/service, but I'm not finding what applies to my issue. Either I'm interpreting the answers incorrectly or this is a valid question I'm about to ask! Hopefully the latter.
I would like controller 2 to recognize when a new http call has been made and the factory images object has been updated. at the moment it resolves once and then ignores any subsequent updates. What am i overlooking?
My view:
<div>
<ul class="dynamic-grid" angular-grid="pics" grid-width="150" gutter-size="0" angular-grid-id="gallery" refresh-on-img-load="false" >
<li data-ng-repeat="pic in pics" class="grid" data-ng-clock>
<img src="{{pic.image.low_res.url}}" class="grid-img" data-actual-width = "{{pic.image.low_res.width}}" data-actual-height="{{pic.image.low_res.height}}" />
</li>
</ul>
</div>
factory:
.factory('imageService',['$q','$http',function($q,$http){
var images = {}
var imageServices = {};
imageServices.homeImages = function(){
console.log('fire home images')
images = $http({
method: 'GET',
url: '/api/insta/geo',
params: homeLoc
})
};
imageServices.locImages = function(placename){
console.log('fire locImages')
images = $http({
method: 'GET',
url: '/api/geo/loc',
params: placename
})
};
imageServices.getImages = function(){
console.log('fire get images', images)
return images;
}
return imageServices;
}]);
controller1:
angular.module('trailApp.intro', [])
.controller('introCtrl', function($scope, $location, $state, showTrails, imageService) {
// run the images service so the background can load
imageService.homeImages();
var intro = this;
intro.showlist = false;
intro.data = [];
//to get all the trails based on user's selected city and state (collected in the location object that's passed in)
intro.getList = function(location) {
intro.city = capitalize(location.city);
intro.state = capitalize(location.state);
//get placename for bg
var placename = {placename: intro.city + ',' + intro.state};
imageService.locImages(placename);
... do other stuff...
controller2:
angular.module('trailApp.bkgd', [])
.controller('bkgdCtrl', ['$scope','imageService', 'angularGridInstance', function ($scope,imageService, angularGridInstance) {
$scope.pics = {};
imageService.getImages().then(function(data){
$scope.pics = data;
console.log($scope.pics);
});
}]);
Your controller2 implementation only got the images once, you probably need a $watch to keep to updated:
angular.module('trailApp.bkgd', [])
.controller('bkgdCtrl', ['$scope','imageService', 'angularGridInstance', function ($scope,imageService, angularGridInstance) {
$scope.pics = {};
$scope.$watch(function(){
return imageService.getImages(); // This returns a promise
}, function(images, oldImages){
if(images !== oldImages){ // According to your implementation, your images promise changes reference
images.then(function(data){
$scope.pics = data;
console.log($scope.pics);
});
}
});
}]);

Angular ng-repeat custom filter giving unresolved variable

Im trying to complete this custom filter to filter a list of all "savings" created in the last 24 hours
Controller filter
angular.module('savings').filter('lessThan', function () {
return function(savings, requirement) {
var filterKey = Object.keys(requirement)[0];
var filterVal = requirement[filterKey];
var filtered = [];
if(filterVal !== undefined && filterVal !== ''){
angular.forEach(savings, function(saving) {
var today = new Date();
var date = new Date(saving.created.$date); <-- Unresolved variable $date
alert(date);
var diff = today - date;
diff = diff / (1000*60*60);
if(diff < filterVal) {
filtered.push(saving);
}
});
return filtered;
}
return savings;
};
});
And here is how i call it from the view
<div ng-repeat="saving in savings | orderBy: '-votesreal' | limitTo:6 | lessThan: {'created.$date':24}" class="col-lg-2 no-padding-spotlight text-center">
<div class=" thumbnail-spotlight thumbnail centred-image">
<img src="{{saving.image}}" /><br>
<a class="text-center" ng-href="/savings/{{saving._id}}" ng-bind="saving.title +' (€'+ saving.price +' # '+ saving.retailer+')'"></a>
</div>
</div>
Ive wrote a note where the unresolved variable is. How do i declare the "saving" object which is coming from the database. Without the filter it returns all results fine.
Controller Code
angular.module('savings').controller('SavingsController', ['$scope', '$timeout', '$stateParams', '$location', '$window', 'Authentication', 'Savings', 'FileUploader',
function($scope, $timeout, $stateParams, $location, $window, Authentication, Savings, FileUploader) {
$scope.authentication = Authentication;
$scope.user = Authentication.user;
$scope.savingImageURL = '/modules/users/client/img/profile/saveme-placeholder.png';
// $scope.user.imageURL = '/modules/users/client/img/profile/saveme-placeholder.png';
$scope.imageURL1 = '';
$scope.hottestsorted = true;
$scope.newestsorted = true;
$scope.brandLogo = '/modules/users/client/img/profile/argos-logo.png';
$scope.spotlightSort = Savings.votesreal;
$scope.savings = Savings;
//$scope.user.imageURL = '';
$scope.submitFormSaving = function(isValid) {
$scope.submitted = true;
};
}
]);
Client.service
//Savings service used for communicating with the savings REST endpoints
angular.module('savings').factory('Savings', ['$resource',
function ($resource) {
return $resource('api/savings/:savingId', {
savingId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
Well it's good to see that $scope.savings has snuck in there. Try something like this:
Instead of $scope.savings = Savings; use:
Savings.query({}, function(resp){
console.log(resp);
$scope.savings = resp;
});
If your api endpoint needs the savingId use:
Savings.query({ savingId: [something] }, function(resp){
console.log(resp);
$scope.savings = resp;
});
This should work for you.

Initialise AngularJS service - factory on the document load

Sorry for a very stupid question but I just started working with AngularJS and OnsenUI.
I have got a service to get a data from SQLite:
module.factory('$update', function () {
var update = {};
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM event_updates', [], function (tx, results) {
var rows = results.rows;
update.items = [];
if (!rows.length) {} else {
for (var index = 0; index < rows.length; index++) {
update.items.push({
"title": rows.item(index).title,
"date": rows.item(index).date,
"desc": rows.item(index).desc
});
}
}
}, function (error) {
console.log(error);
});
});
return update;
});
And a controller which is using the data:
module.controller('UpdatesController', function ($scope, $update) {
$scope.items = $update.items;
});
As soon as my page is loaded the content is not displayed and I need to click twice to call a page with the code below to see the content:
<ons-list ng-controller="UpdatesController">
<ons-list-item modifier="chevron" class="list-item-container" ng-repeat="item in items" ng-click="showUpdate($index)">
<div class="list-item-left">
</div>
<div class="list-item-right">
<div class="list-item-content">
<div class="name">{{item.title}}</div> <span class="desc">{{item.desc}}</span>
</div>
</div>
</ons-list-item>
</ons-list>
Can anybody help how can I initialise the controller as soon as page is loaded with all content. Sorry if it is a stupid question but I am really struggling. Appreciate your help a lot.
You could store the result of the request in the factory and retrieve those instead.
module.factory('$update', function () {
var update = {};
var requestValues = function(){ // store the results of the request in 'update'
// Your db.transaction function here
}
var getUpdates = function(){ // retrieve the values from 'update'
return update;
}
return{
requestValues : requestValues,
getUpdates : getUpdates
}
});
And then in you controller:
module.controller('UpdatesController', function ($scope, $update) {
$update.requestValues();
$scope.items = $update.getUpdates();
});
You could then get the values from anywhere in you solution (by using $update.getUpdates) without having to make an extra http request.

Resources