I have two controllers in my app. A MenuController and a LeagueController. The MenuController exists on the main index.html page. The LeagueController manages the set of League specific pages.
When the app boots the MenuController loads all the leagues available via the restful api I put together with Strongloop creating an entry in a dropdown at the top of the page for each league so the user can jump quick to it.
I create Leagues via a create-league.client.view.html template which is controlled by the LeagueController.
Below is the MenuController code:
angular.module('app')
.controller('MenuController',
['$scope', '$state', 'League', function ($scope, $state, League) {
$scope.leagues = [];
function getLeagues() {
League
.find()
.$promise
.then(function (results) {
$scope.leagues = results;
});
}
getLeagues();
}]);
and below this is the LeagueController
angular.module('app')
.controller('LeagueController', ['$scope', '$state', 'Leagues',
function($scope,$state, League) {
$scope.leagues = [];
$scope.addLeague = function() {
League
.create($scope.newLeague)
.$promise
.then(function(result) {
$scope.newLeague = '';
$scope.leagueForm.name.$setPristine();
$('.focus').focus();
getLeagues();
});
};
function getLeagues() {
League
.find()
.$promise
.then(function(leagues) {
$scope.leagues = leagues;
});
}
getLeagues();
$scope.removeLeague = function(item) {
League
.deleteById(item)
.$promise
.then(function() {
getLeagues();
});
};
}]);
in both cases I use the strongloop lb-services.js generated by running lb-ng server/server.js client/js/services/lb-services.js
The problem arises in that the $scope.leagues created for each controller is obviously seperate but I can't get the MenuControllers leagues array to update when a user creates a new league so the dropdown at the top doesn't change.
I was trying to create a service which relied on the lb-services.js file but to no avail.
I've googled every example I could find of sharing data between controllers but I haven't been able to get any of them to work. Any help would be hugely appreciated. I'm a Java developer trying to get to grips with AngularJS and am struggling with the way angular houses and encapsulates the data. I can see how effective it is when it's done correctly I just haven't had that 'Eureka!!' moment yet.
Thanks, Mark.
*************Solution Hi all, Thanks to Pauls help below I was able to come up with a solution.
I've created a SharedLeagues service which has the generated League service injected into it. Then the SharedLeagues service is injected into both controllers. The controllers keep a reference to the SharedLeagues service object itself as opposed to the underlying leagues array. Then in the templates the ng-repeat attributes are bound to the SharedLeagues.getLeagues() method.
SharedLeagues.service.js angular.module('app').service('SharedLeagues', function(League) {
var leagues= {};
return {
retrieveLeagues: function() {
League
.find()
.$promise
.then(function(foundLeagues) {
leagues = foundLeagues;
});
},
getLeagues: function() {
return leagues;
},
setLeagues: function(leaguesToSet) {
// setter
leagues = leaguesToSet;
}
}
});
The MenuController.js initialises the SharedLeagues underlying leagues array by making the call to the back end upon construction.
angular.module('app')
.controller('MenuController',
['$scope', '$state', 'SharedLeagues', function ($scope, $state, SharedLeagues) {
SharedLeagues.retrieveLeagues();
$scope.SharedLeagues = SharedLeagues;
}]);
The LeagueController has methods to addLeague and deleteLeague. As part of the callback, the SharedLeagues setLeagues method is called which also updates the MenuController's bindings.
angular .module('app') .controller('LeagueController', ['$scope', '$state', 'SharedLeagues','League', function($scope, $state, SharedLeagues, League) {
$scope.SharedLeagues = SharedLeagues;
$scope.addLeague = function() {
League
.create($scope.newLeague)
.$promise
.then(function(createdLeague) {
$scope.newLeague = '';
$scope.leagueForm.name.$setPristine();
$('.focus').focus();
var leagues = SharedLeagues.getLeagues();
leagues.push(createdLeague)
SharedLeagues.setLeagues(leagues);
});
};
$scope.removeLeague = function(item) {
League
.deleteById(item)
.$promise
.then(function() {
SharedLeagues.retrieveLeagues();
});
};
}]);
The League view binds to the SharedLeagues and lists newly created Leagues for deletion as follows
<div class="list-group col-lg-2">
<a class="list-group-item" ng-repeat="league in SharedLeagues.getLeagues()">{{league.name}} at {{league.venue}}
<i class="glyphicon glyphicon-remove pull-right"
ng-click="removeLeague(league)"></i></a>
</div>
The Menu view binds to the SharedLeagues as follows
<ul class="dropdown-menu">
<li ng-repeat="league in SharedLeagues.getLeagues()"><a href="/edit/{{league.id}}">{{league.name}}</a></li>
<li class="enabled"><a href="/#/leagues/create">Create new League...</a></li>
</ul>
Hope this helps someone else looking to accomplish a similar task. Thanks a lot for your help Paul!
Mark.
A service is a good way to share data between two controllers, here's an example of how that works:
create a service:
app.service('SharedData', function() {
var data = [1,2,3,4,5,6];
return {
getData: function() {
// getter
return data;
},
setData: function(toSet) {
// setter
data = toSet;
}
}
});
then inject the service into both your controllers:
app.controller('yourCtrl', function($scope, SharedData) {
...
you can then get/set the data from either controller and it'll be reflected in the other:
// in the controller
...
SharedData.setData('somevalue');
var someVal = SharedData.getData();
...
Here's a basic working example of the idea: http://plnkr.co/edit/Yt2t6D7P29ytCm4tyQn9?p=preview