This question already has answers here:
Passing data between controllers in Angular JS?
(18 answers)
Closed 6 years ago.
Hi i am displaying data using ng repeat.
I am displaying 3 persons in a template.. now when i click on 1 of them. I want to display in detail information of that person... so i need to make new controller and new template...but i know one way that is to pass one of the unique parameter like mobile no to the controller.. which then changes path with having mobile number to another controller and template.using location.path().search().. now in that 2nd controller i can request information again using 2nd parameter.. is this okay ??
I wanted to pass whole persons data from 1 controller to other but i don't know how can i do it...
Use a service to set the selected person's information and access the information using a routeParam for the user's unique id.
The code structure would look something like below
angular
.module('app')
.controller('ParentController', function (UserService) {
$scope.onSelect = function (user) {
UserService.setCurrentUser(user);
}
})
.controller('ChildController', function ($routeParams, UserService) {
$scope.user = UserService.getCurrentUser($routeParams.userId);
})
.factory('UserService', function () {
var currentuser = {};
return {
getCurrentUser: getCurrentUser,
setCurrentUser: setCurrentUser
};
function getCurrentUser () {
return currentuser;
}
function setCurrentUser (user) {
currentuser = user;
}
})
You can make the second controller child of the first controller.
All the data of the first controller can then be accessed in the second controller.
It also depends on the use cases, you can use the following methods to share data between controllers (if you do not want to do the above mentioned)
1) $localStorage
2) $sessionStorage
3) create a service
Related
This question already has answers here:
AngularJS: Service vs provider vs factory
(30 answers)
Closed 5 years ago.
i am new in angular. so trying to know how to share data between two controller and search google. i visited few pages and found most of the time people use factory to share data. i just like to know can't we do it by service instead of factory ?
1st example
<div ng-controller="FirstCtrl">
<input type="text" ng-model="data.firstName">
<br>Input is : <strong>{{data.firstName}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{data.firstName}}
</div>
myApp.factory('MyService', function(){
return {
data: {
firstName: '',
lastName: ''
},
update: function(first, last) {
// Improve this method as needed
this.data.firstName = first;
this.data.lastName = last;
}
};
});
// Your controller can use the service's update method
myApp.controller('SecondCtrl', function($scope, MyService){
$scope.data = MyService.data;
$scope.updateData = function(first, last) {
MyService.update(first, last);
}
});
2nd example
var myApp = angular.module('myApp', []);
myApp.factory('Data', function(){
var service = {
FirstName: '',
setFirstName: function(name) {
// this is the trick to sync the data
// so no need for a $watch function
// call this from anywhere when you need to update FirstName
angular.copy(name, service.FirstName);
}
};
return service;
});
// Step 1 Controller
myApp.controller('FirstCtrl', function( $scope, Data ){
});
// Step 2 Controller
myApp.controller('SecondCtrl', function( $scope, Data ){
$scope.FirstName = Data.FirstName;
});
examples are taken from this url Share data between AngularJS controllers
please guide me.
Both .service() and .factory() are both singletons as you’ll only get one instance of each Service regardless of what API created it.
Remember that .service() is just a Constructor, it’s called with new, whereas .factory() is just a function that returns a value.
Using .factory() gives us much more power and flexibility, whereas a .service() is essentially the “end result” of a .factory() call. The .service() gives us the returned value by calling new on the function, which can be limiting, whereas a .factory() is one-step before this compile process as we get to choose which pattern to implement and return.
I want to know how to dynamically change an $http call so that the $http request URL differs based on the element that is clicked in an ng-repeat list. But I'm stuck.
Currently, I have an ng-repeat set up on my index page:
<div ng-repeat="team in nt.getStandings">
<h2>{{team.team_name}}</h2>
<p>Team ID = {{team.team_id}}</p>
</div>
The variable getStandings is taken from an API via an $http call. Like so:
In StandingsService
return $http.get(
'http://api.com/standings/1005?Authorization=xxxx'
)
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
And then StandingsService is attached to the getStandings variable in my controller.
"1005" is a property which calls a specific array, in this case a particular sporting competition, from an array of competitions.
So, on my index page I'm using ng-repeat to list all teams within that competition.
As you can see on the html above, I have linked each team so that it dynamically generates a URL which appends the team_id to the end, which using $routeParams I define as the variable whichTeam.
Team Details Page
<h1>Dynamic Team ID = {{whichTeam}}</h1>
This works fine, the team ID is generated dynamically according the team that is clicked.
Just like 'StandingsService' above, I have another service called 'TeamService' which makes an $http request to pull team data. Currently though it is set up statically to make a call to one individual team - I want to make the service take in the whichTeam variable so that the call changes depending on which team was clicked.
This is the static team $http request (I've broken the URL apart and concatenated to make it clearer):
return $http.get(
'http://api.com/team/' + '16110' + '?Authorization=xxxx'
)
I want the 16110 part, which refers to ONE team, to be a the whichTeam variable, allowing it to pull in the correct individual team data, but I don't know how to write this (or indeed if it's possible).
I hope I've been clear - happy to clarify further if needed. Thanks in advance.
Make a factory:
app.factory("DataService", ["$http", function($http) {
return {
getTeamDetailsById: function(teamId) {
return $http.get('path/to/api' + teamId + '?Auth=xxxx')
}
};
}]);
Use it in a controller:
app.controller("MainCtrl", ["$scope", "DataService", function($scope, DataService) {
$scope.teamDetails = {};
$scope.getTeamDetailsById = function(event, teamId) {
//prevent click navigation
event.preventDefault();
//call factory service
DataService.getTeamDetailsById(teamId).then(function(response) {
//success callback
$scope.teamDetails = response.data;
}, function(response) {
//an error has occurred
});
}
}]);
In the ng-repeat element:
<div ng-repeat="team in teams">
<a href ng-click="getTeamDetailsById($event, team.team_id)">{{team.team_name}}</a>
</div>
The above assumes you have only one state and are storing in only one controller. If you want to use different states usving $stateProvider, then you'd have to use parameters, by making use of ui-sref and passing in team Id.
If indeed you are using $states and parameters, do this:
<a href ng-click="goToState($event, team.team_id)">{{ team.team_name }}</a>
$scope.goToState = function(e, teamId) {
$state.go("teamDetailsState", { "teamId": teamId });
}
I have a service with the following:
.service('TasksService', function ($http) {
return $http.jsonp('http://blabla/json/?callback=JSON_CALLBACK');
});
My controller:
.controller("TasksCtrl", function ($scope, TasksService) {
TasksService.then(function (TasksService) {
$scope.Tasks = TasksService;
});
});
This shows list with many items.
But I have another service and another controller. I change an item there and when I save and post data to database and I get back to initial list, I still see the old listed items. I must refresh the browser to see what I have edited.
In the second controller I have save function with this:
$scope.saveTask = function () {
$http.post('http://blabla', $scope.Task.data).then(function (data) {
// This shows the very first state with all the listed items
$state.go('tasks');
});
};
When I save the changes and state.go() shows me the first screen I do not know why the data is not with the new changes from the service returned data. It seems like the screen is just changed but the new data is not returned from the service. Any ideas how to fix this?
I got it working. I changed my service and controller. In my service I returned an object with another method and then I changed my controller also to use the returned method.
The service:
.service('TasksService', function ($http) {
return {
getTasks: function() {
return $http.jsonp('http://blabla/json/?callback=JSON_CALLBACK');
}
};
});
And the controller:
.controller("TasksCtrl", function ($scope, TasksService) {
TasksService.getTasks().then(function (data) {
$scope.Tasks = data;
});
});
Now it is working and I see the items list the new saved and returned data. Thank you!
All you need is to reflect the changed data into your html
Angular has a method for this
$scope.$apply();
This method works both with parameters as well as without parameters.
Hope this helps.
EDIT: As asked, I'll explain a bit more efficiently !
I've been sitting in front of an annoying problem recently, which is that whenever I update a value inside a directive, the controllers I'm not currently "in" are the only ones to be updated properly.
Scenario example: Profile page is made of two controllers. Navbar_controller which is just currently displaying the user name :
<div ng-if="Auth.isAuthenticated">Hello, {{Auth.getCurrentUser().name}}</div>
The second controller , Profile_controller is here to update user values. This is a simple function in the angular first controller, which updates CurrentUser:
$scope.updateUser = function (type, form) {
if (!$scope.modif)
return ;
$http.put('/api/users/' + Auth.getCurrentUser()._id + '/update', {type:type, modif:$scope.modif})
.success(function (data, status) {
$scope.user = Auth.setNewUser(data);
})
.error(function () {
console.log("error");
});
};
When I update, for example, the name. I can see that the database has been modified properly. And indeed, navbar_controller got the update because a new name is printed in the div. However, Profile_controller doesn't get the update: the name printed in the profile page didn't change.
Here are the two basic functions in Auth.service.js :
getCurrentUser: function() {
return currentUser;
},
// 'user' is the data retrieved in http put request dot success
setNewUser: function(user) {
currentUser = user;
$rootScope.$broadcast(); // Navbar_controller is updated with or without this line
return currentUser;
}
Anyway, if I look at the navbar and its controller, which is calling Auth.getCurrentUser() method, the user values are instantly modified. I'e been using an ugly method consisting in modifying the controller values manually or by refreshing the page... But this isn't the way to go, right ?
There must be something with "$rootScope.$broadcast();", but I'm really new to Angular and other questions on stackoverflow are too specific to help me understand properly.
Thank you !
Your question was a little difficult to understand, but I think the problem is that you are reference a changing object in your various controllers. Here is an example to explain:
Service:
var myObject = { ... };
return {
getObject() { return myObject; }
setObject(obj) { myObject = obj; }
};
Controller 1:
$scope.myObjA = Service.getObject();
Controller 2:
$scope.myObjB = Service.getObject();
Now on initialisation both controllers will be referencing the same object, so if you changed a property inside either controller (eg. $scope.myObjB.name = 'bob';), then the other controller would also see the name.
However if you changed the object itself in a controller (eg. Service.setObject(newObj);), then the controller will be referencing the new object, while the other controller will still be referencing the old one.
You can fix this by wrapping your service object in a container:
var cont = {
user: ...
};
function getContainer() { return cont; }
function setNewUser(user) { cont.user = user; }
Then inside your controllers, get the container (not the user):
$scope.cont = Service.getContainer();
And inside your html:
<div>{{cont.user.name}}</div>
Now when you update the user, all attached controllers will be updated.
Well I'd try to change and store the user information in $rootScope, for your scenario could be a good fit.
getCurrentUser: function() {
$rootScope.currentUser===undefined ? 'no User': $rootScope.currentUser;
},
setNewUser: function(user) {
$rootScope.currentUser = user;
//$rootScope.$broadcast(); no need to broadcast
return getCurrentUser();
}
in that way currentUser will be updated in different scopes as needed!
I'll quote AnuglarJs FAQ regarding to $rootscope:
$rootScope exists, but it can be used for evil
Occasionally there are pieces of data that you want to make global to
the whole app. For these, you can inject $rootScope and set values on
it like any other scope. Since the scopes inherit from the root scope,
these values will be available to the expressions attached to
directives like ng-show just like values on your local $scope.
Of course, global state sucks and you should use $rootScope sparingly,
like you would (hopefully) use with global variables in any language.
In particular, don't use it for code, only data. If you're tempted to
put a function on $rootScope, it's almost always better to put it in a
service that can be injected where it's needed, and more easily
tested.
Conversely, don't create a service whose only purpose in life is to
store and return bits of data.
I'm creating a quiz and I want to add the answer the user gives to an array (myAnswers), when the quiz is finished, I redirect my user to the summary page, where he can see the correct answer and the answer he has given. Those are both different controllers. I tried experementing with a service, but this doesn't work out...
Can someone help me with this one please?
service
var lycheeServices = angular.module('lycheeControllers', [])
lycheeServices.service('myAnswerService', function () {
var myAnswers= [];
this.AddAnswer = function(number, a){
myAnswers[number-1] = a;
};
this.getAnswer = function(number){
return myAnswers[number-1];
};
});
controller quiz
lycheeControllers.controller('quizCtrl', ['$scope', '$http', 'myAnswerService',
function ($scope, $http, myAnswerService) {
$scope.checked = function (answer) {
myAnswerService.addAnswer(number, answer.answer);
}
controller summary
lycheeControllers.controller('summaryCtrl', ['$scope', '$http', 'myAnswerService', function ($scope, $http, myAnswerService) {
$scope.myAnswer = myAnswerService.getAnswer(number);
]
In your controller summary, when you retrieve a value using your myAnswerService.getAnswer(number);, it returns a new value and your $scope.myAnswer is a copy of the value.
If your answer is a value type, any changes on it will not affect the value in your service answer array.
If your answers array contains objects (reference type), then manipulating the properties of $scope.myAnswer will update the properties of the same object referenced by the answer inside the service's array. But if you replace it with another answer, your answer inside the answers array will not notice the change
I don't know what you're trying to achieve, but a sensible solution is you store the service object to the scope. Like this:
$scope.myAnswer = myAnswerService
Note: When you do redirects, ensure that you don't do full page refresh because your data will be cleared completely.