AngularJS - aggregate values from various controllers - angularjs

I am building an app which aggregates data provided by Facebook GRAPH live. Specifically I want to read the number of likes from various Facebook pages and display a total number of likes. This information is being updated every 5 seconds. I have managed to pull in and update information from individual pages but can not figure out how to add these values together and display the total number. Here is the markup:
<div ng-controller="TotalController">
<span ng-controller="UpdateController" ng-init="init('331288023558058','fan_count')">{{output}}</span>
<span ng-controller="UpdateController" ng-init="init('20531316728','fan_count')">{{output}}</span>
<span>{{outputTotal}}</span>
</div>
and here is the script for it:
var app = angular.module('app', []);
app.controller('UpdateController', function($scope, $http) {
$scope.init = function(id, item) {
$scope.id = id;
$scope.item = item;
//retrieve data on the initial load
$scope.updateData();
};
$scope.updateData = function() {
$http({
method: 'JSONP',
url: 'https://graph.facebook.com/fql?q=select ' + $scope.item + ' from page where page_id = ' + $scope.id + '&callback=JSON_CALLBACK'
}).success(function(data) {
//load the new value
var currentValue = data['data'][0][$scope.item];
//output new value to view
$scope.output = currentValue;
}).error(function(data, status) {
console.log("error " + data + " " + status);
});
};
var timer = setInterval(function() {
$scope.$apply($scope.updateData);
}, 5000);
});
I have tried setting up a controller which encompasses the two Update controllers and watching the scope for changes but I couldn't get the data out of the two child controllers.
My understanding is that the best way to go about it would be to set up a service which aggregates the values, and then inject this service into a third 'Total' controller, but I haven't been able to implement this either. What would be the best way to tackle this problem? Is my approach with controllers completely wrong?

Related

AngularJS - Update a variable of a factory from a controller

I am developping a web app with Ionic 1 and AngularJS 1.
In my factory (UserFact) :
.factory('UserFact', function() {
var user = [];
return {
'setUser': function(user) {
this.user = user;
console.log('(2) User set: ' + this.user);
console.log('(3) User id is now: ' + this.user.uid);
},
'updateSport': function(sportid, registered) {
console.log('Update sport: ' + sportid + ' --> ' + registered);
console.log('(4) For user uid: ' + this.user.uid);
var ref = firebase.database().ref('users/' + this.user.uid + '/sports/');
// sync down from server
var list = [];
ref.on('value', function(snap) { list = snap.val(); });
if(registered) {
list.splice(0, 0, {id: sportid});
} else {
}
ref.set(list);
}
};
})
In my controller :
function ($scope, $stateParams, $state, DatabaseFact, UserFact) {
// variables
$scope.sports = [];
$scope.sports = DatabaseFact.getSports();
// functions
$scope.updateSport = UserFact.updateSport;
// execution
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
UserFact.setUser(user);
console.log('(1) Ctrl user uid: ' + user.uid);
}
});
}
According to the console: logs (1), (2) and (3) display a userid form my db but (4) is always undefined...
Any idea?
Thanks
UPDATE:
Manuel, sorry, I think I had missed the point of your question. You are correct, using a factory/service, is the correct way to store the state of your application. From the above, I do not see a reason for your code not work. The user must be getting re-assigned elsewhere for you to be seeing undefined in (4), if you are not seeing the same in (3). For simplicity sake, I removed references to firebase and created a working demo: https://plnkr.co/edit/vaN7ySche8GgRQmZgFsa?p=preview
While the demo may not solve your problem, I hope it illustrates that the factory variable (user) is persisted in memory and usable across multiple factory method calls.
ORIGINAL ANSWER (MISSED THE POINT) BELOW:
Update the state change handler to save the user on the controller scope:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
$scope.user = user;
UserFact.setUser(user);
console.log('(1) Ctrl user uid: ' + user.uid);
}
});
Then, in the template, invoke the updateSport method, using the user scope variable:
updateSport(user, true);
or
updateSport(user, false);
You need to pass the arguments while calling updateSport in controller,
$scope.updateSport = UserFact.updateSport(userid,registered);

Get JSON array object specific Id depending on which item i click on AngularJS

So i have a table with a list of teams, what i want to do is when i click on a team name it displays a new view with team details. There is 2 controllers, 1 to get league table and fixtures and then 1 for the team details. So far i have from the controller in the league table looped through the Json object array and gotten a list of links which contains the ID i need to pass in to the team details controller so i can specify which team it should display. Because the teams dont have the ID in the object i had to do it this way.
So the problem is that i can console.log all ID's but it only passes through the last ID logged. Which genereates the same team what ever team i click on. I want to get the specific ID for the team i click on and pass that to the team details controller id:.
I'm in the learning stages so excuse my poor code :).
If you see any improvements in my code writing please do let me know.
I get my data from:
http://api.football-data.org/
using the AngularJs factory library from:
https://github.com/JohnnyTheTank/angular-footballdata-api-factory
The View
<tbody>
<tr ng-repeat="team in teams.standing | filter:searchText | orderBy:orderByField:reverseSort">
// Where i want to somehow click on a team name and load that teams details
<td><strong>{{ team.teamName }}</strong></td>
</tr>
</tbody>
Controller1
.controller('AppCtrl', ['$scope', 'footballdataFactory', function($scope, footballdataFactory) {
$scope.date = new Date();
var apiKey = '***********************';
$scope.$back = function() {
window.history.back();
};
$scope.leagueId = function(id) {
$scope.id = id;
footballdataFactory.getLeagueTableBySeason({
id: $scope.id,
apiKey: apiKey, // Register for a free api key: http://api.football-data.org/register
}).success(function (data) {
$scope.teams = data;
$scope.leagueCaption = data.leagueCaption;
console.log("Get League", $scope.teams);
console.log('Loop through league and get team ids ----------------------------');
$scope.getTeamId = function(teamId) {
var dataLength = $scope.teams.standing.length;
for(var tUrl = 0; tUrl < dataLength; tUrl++) {
$scope.teamUrl = $scope.teams.standing[tUrl]._links.team.href.substr($scope.teams.standing[tUrl]._links.team.href.lastIndexOf('/') +1);
console.log('teamId: ' + $scope.teamUrl);
}
}
});
};
$scope.league = function(id) {
$scope.id = id;
footballdataFactory.getFixtures({
league: $scope.id,
apiKey: apiKey,
}).success(function(data){
$scope.games = data;
console.log("getFixtures", $scope.games);
});
};
}])
Controller2
// Team details controller
.controller('TeamCtrl', ['$scope', 'footballdataFactory', function($scope, footballdataFactory) {
var apiKey = '*************************';
footballdataFactory.getTeam({
id: $scope.teamUrl, ***Inserting the last 2 or 3 digits i get from the url***
apiKey: apiKey,
}).success(function(data){
$scope.teams = data;
$scope.name = data.name;
$scope.crestUrl = data.crestUrl;
$scope.squadMarketValue = data.squadMarketValue;
console.log("getTeam", $scope.teams);
});
footballdataFactory.getPlayersByTeam({
id: $scope.teamUrl,
apiKey: apiKey,
}).success(function(player){
$scope.players = player.players;
console.log("getPlayersByTeam", player);
});
}])
You can solve this problem easly with apiNG and the football-data plugin, that based on the same angular lib you even use. on the plugin page is a link to a working plnkr sample

Reading data from firebase in angularfire

I have an app where I need to store artists and their details in database.Now I want to retrieve all the artists and render some of their details in front end.How to do that.
Secondly, if I get the artist rating in some input field by using ng-model, then how to store that value in a particular artist to update details.
The database structure is:
{
"artists": {
"Atif":{
"name":"atif",
"rating":8
},
"Himesh":{
"name":"himesh",
"rating":5
}
}
}
and this is angular.js
(function()
{
var app = angular.module("myapp", ["firebase"]);
app.controller("maincontroller", function($scope, $firebaseObject,$firebaseArray)
{
var ref = new Firebase("https://gigstart.firebaseio.com/");
var artists=ref.child("artists");
// download the data into a local object
$scope.data = $firebaseObject(ref);
// putting a console.log here won't work, see below
ref.on("value", function(snapshot)
{
console.log(snapshot.val());
}, function (errorObject)
{
console.log("The read failed: " + errorObject.code);
});
var artistsRef=new Firebase("https://gigstart.firebaseio.com//artists");
}); //end of controller
Now I want to render the name and rating of each artist in front end.Can I do something like
<div ng-repeat="artist in artists">
{{artist.name}}
{{artist.rating}}
</div>
You have a list of artists, which you want to ng-repeat over in your Angular view. You can accomplish that by:
app.controller("maincontroller", function($scope, $firebaseArray)
{
var ref = new Firebase("https://gigstart.firebaseio.com/");
var artists = ref.child("artists");
$scope.artists = new $firebaseArray(artists);
}
Please take a moment to go through the AngularFire quickstart before starting on your own project. This is covered in step 5.

How to remove unwanted databinding in Angularjs

I have an angularjs web page page which allows me to edit some fields. I load the data from my DB, edit it in the page then save the revised data back to the DB. the DB api requires me to submit for amendments the existing DB data and the revised data. Unfortunately when I save the existing data it is binding to the change which I don't want to do !
function providerCtrl($scope, $location, $routeParams, $http)
{
$scope.getProvider = function () {
$http.get(
'/admin/api/'+$routeParams.channel+
'/'+$routeParams.provider).success(function(data){
inputData = data[0];//i want to save this initially but never have it change again, unfortunately its binding with this $scope.settings field changes :-(
$scope.settings = data[0];
});
}
$scope.amendProvider = function (settings) {
console.log($scope.inputData);
var data = {'old': inputData, 'new' : $scope.settings}
console.log(data);
$http({
url: '/admin/api/' + $routeParams.channel + '/' + $routeParams.provider,
method: "PUT",
data: {'old': inputData, 'new' : $scope.settings}
})
.success(function(data){
});
}
$scope.settings = {};
var inputData = {};
$scope.getProvider();
}
when I save the existing data it is binding to the change which I don't want to do !
use angular.copy() utility to clone new instance.
See Documentation HERE

Can you bind data from one scope to update when another changes in angularJS

My web app depends on one specific variable changing throughout the user's visit. It controls what data the user will see at any given time, essentially akin to a TAG.
If the $scope.tagid = 1, is it possible to have another angular model to instantly update its own dataset when tagid is changed to $scop.tagid = 2?
<script >
function PageCtrl($scope) {
$scope.text = '<?=$tagid?>';
}
$scope.showThread = function(tagid) {
$http({method: 'GET', url: 'api/example/thread/id/' + tagid}).
success(function(data, status, headers, config) {
$scope.appDetail = data; //set view model
$scope.view = './Partials/detail.html'; //set to detail view
}).
error(function(data, status, headers, config) {
$scope.appDetail = data || "Request failed";
$scope.status = status;
$scope.view = './Partials/detail.html';
});
}
</script>
<div ng-controller="PageCtrl">
<input ng-model='text' />
<ul>
<li >
<span>{{text}}</span>
</li>
</ul>
</div>
Above is the skeleton of what i'm looking to do.
I realize that if I wanted to, I could call showThread() after each user action and update the data...however, because of the awy I'm looking to set up the site, It makes more sense to only change the tagid, then have everything else update immediately after, rather than picking and choosing each part of the site I want to update. i.e. there may, in addition to showThread(), be updateHeader(), changeSidebar() etc.
Thanks!
I have personally had success using a service; **Assuming that you are using 2 controllers on 1 page, I would create a service like this:
MyApp.app.service("tagDataSvc", function () {
var _tagId = {};
return {
getTagId: function () {
return _tagId;
},
setTagId: function (value) {
_tagId = value;
}
};
});
Next, inject this service into the controllers where this will be used.
In your main controller where you are controlling the TagId (PageCtrl), you would need to set the shared tagId value with a call to the service: tagDataSvc.setTagId($scope.text) You can do this explicitly, or add a $watch on $scope.text, or whatever you prefer.
Finally, in the second controller that you want to automagically update, add a $watch on this service's getTagId() function like so:
$scope.$watch(function () { return tagDataSvc.getTagId(); }, function (newValue, oldValue) {
if (newValue != null) {
$scope.tagId2 = newValue;
//reload whatever needs updating here
}
}, true);

Resources