Angular 1 - share data from rest call to another controller - angularjs

I have two partial pages. In the first page a rest call is made in the ManageUsersTreeViewController. I want this data to get to the second controller ManageUsersTableController. $scope.userData = data; in the getUserData() function is what i need to get to the second controller.
First Controller
app.controller('ManageUsersTreeViewController',['$rootScope', '$scope', '$http', function($rootScope, $scope, $http) {
$scope.getAllUsers = function() {
$http.get('rest/useraccess/users/').
success(function (data) {
$scope.users = data;
}).
error(function (error) {
console.log(error);
});
};
$scope.getUserData = function(user){
$http.get('rest/useraccess/' + user ).
success(function (data) {
$scope.userData = data;
console.log("user data returned:" + $scope.userData);
}).
error(function (error) {
console.log(error);
});
};
}]);
Second Controller
app.controller('ManageUsersTableController',[ '$scope', '$http', '$rootScope', function($rootScope, $scope, $http) {
$scope.maxSize = 3;
$scope.pageNumber = 1;
$scope.pageSize = 20;
$scope.pageSizesForSelect =[5,10,20,50];
}]);
How can i share the $scope.userData in the ManageUsersTreeViewController to the ManageUsersTableController? Any help is much appreciated.

you can use $emit function. this stackoverflow answer explains $emit, $broadcast, $on.
app.controller('ManageUsersTreeViewController',['$rootScope', '$scope', '$http', function($rootScope, $scope, $http) {
$rootScope.$emit('ManageUserData.Event_or_name_it_yourself', { data: $scope.userData });
}
then, in your other controllers, you can listen to this event. *make sure your view loaded both controllers.
app.controller('ManageUsersTableController',[ '$scope', '$http', '$rootScope', function($rootScope, $scope, $http) {
// destory the rootscope watcher on scope destory event, as garbage collection. otherwise your rootscope will keep listen on the event
$scope.$on('$destory', $rootScope.$on('ManageUserData.Event_or_name_it_yourself', function (event, params) {
$scope.userData = params.data;
// do what you need to do.
});
}

You're probably going to want to build an angular service to share that data across controllers. Another "down n dirty" option is to attach your userData to the $rootScope (shown below). I think you'll find your app will outgrow that solution quickly, however.
$rootScope.getUserData = function(user){
$http.get('rest/useraccess/' + user ).
success(function (data) {
$rootScope.userData = data;
console.log("user data returned:" + $rootScope.userData);
// ... now just access $rootScope.userData in other controllers
}).
error(function (error) {
console.log(error);
});

You cannot use $emit, $broadcast, $on inorder to message data between controllers. the problem with this approch is that the receiving controller may not be loaded yet and there for didnt register it's $on function.
For example if you have 2 page app with seperate controller when the first is loaded it's controller is loaded as well but the seconde page controller isn't there for there will be no controller to catch the first controller $emit or $broadcast.
The above will work only if all involved controllers were allready loaded.
As metion before you can use a service to do the work for you and store the receiving data in the $rootScope. The probllem with this approach is that when your app will grow bigger and will have more and more controller that you will want to communicate between each other , storing all this data in the rootScope is bad approach.
If you wish to use a service, i suggest that you will design a communication system as follow.
Create an array at the size of the number of your conroller in your service.
Each cell in the above array will also be an array , starting with the size of zero.
Inside this service create a const array containing all of your controllers names.
inject ths service into each one of your controllers.
Each Time a controller wants to send data to another controller, it need to iterate the service's names array until it finds the controller name it want to pass data to. one the receiving controller name is found the sending controller know it's index and can push a new message into the receiving controller cell in the array described in 1+2.
The "message" can be an object such as : {from:'controller-name', data:{}}.
when a controller start runing it check it's "mailbox" retrive the data and delete the cell if it no longer needed.
Another way you can try out is the creat a Root controller and place it on you body element in your index, such as : ...
this controller will run at the moment your app start and can use to store data as i described above

Related

AngularJS Service issue on sharing data with the Controller

I have the following service which successfully connects to a php file for me and grabs data from the database:
(function(){
'use strict';
angular.module('app.services')
.factory('myService', [ 'getContent', function(getContent, $resource, $scope) {
return {
//list of things returned by this service:
getEventTypes: function(dir, file) {
var getAllTypes = getContent.getphp(dir, file);
getAllTypes.query(function(data){
$scope.mytypes = data;
});
}
};
}])
;
})();
But I cannot assign data to any variables through it. In fact, $scope.mytypes gives me a "Cannot set property 'etypes' of undefined"... I am not sure what's going on? If I remove $resource and $scope then it doesn't work as I am injecting another service into this service... Blegh. Suggestions?
Don't use $scope in the service which is not advisable.
As Angulajs is a MVC framework M-model should be bound between the
V-view and the C-controller where $scope here is the model - the
entity which connects the view to the controller.
Hence, we should not use this in the service and won't work as expected.
We usually use one controller per view and if we have any generic logics should be reused in multiple controllers like generic validation, API call etc, it should be used in the service. That's why Service is built as a singleton object which means only one instance will be created in the SPA (Single Page Application) and shared across multiple controllers. But unique controller and $scope should be created per view.
Hope you understand this. Hence your above service can be modified as below to return the promise of the API call where you can use the same inside the controller to call and assign the object to the $scope.
Service
return {
//list of things returned by this service:
getEventTypes: function(dir, file) {
var getAllTypes = getContent.getphp(dir, file);
return getAllTypes;
}
};
Controller
myService.getEventTypes(/* params */).query(function(data) { $scope.myTypes = data; });
This is an alternative way by which you can have your Service do all the work for you reducing the lines of code in your controller.
(function(){
'use strict';
angular.module('app.services')
.factory('myService', [ 'getContent', function(getContent, $resource, $scope) {
return {
//list of things returned by this service:
getEventTypes: function(dir, file,successcallback) {
getContent.getphp(dir, file)
.query()
.success(function (data, status, headers, config) {
successcallback(data);
})
.error(function (data, status, headers, config) {
$log.warn(data, status, headers, config);
})
}
};
}]);
})();
Assigning to scope object will be like this
myService.getEventTypes(/*you params comma separate if needed*/,function(successcall){
$scope.data=successcall;
});

Angular JS - service not working

I am using a service to get data from the server using $http.get() method. I am calling the function in the service and then accessing its variable from the controller. But it is not working this way.
The code is below
'use strict';
var mission_vision_mod = angular.module('myApp.mission_vision', ['ngRoute']);
mission_vision_mod.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/mission_vision', {
templateUrl: 'partials/mission_vision/mission_vision.html',
controller: 'mission_visionCtrl'
});
}]);
mission_vision_mod.controller('mission_visionCtrl', ['$scope','getMissionData','$http', function($scope, $http, getMissionData) {
$scope.visiontext = "Here is the content of vision";
getMissionData.getmissiondata();
$scope.missions = getMissionData.missiondata;
$scope.len = $scope.missions.length;
}]);
mission_vision_mod.service('getMissionData', ['$rootScope','$http', function($rootScope, $http){
var missiondata;
function getmissiondata(){
$http.get('m_id.json').success(function(data){
missiondata = data;
});
}
}]);
When i write the$http.get() function in the controller itself, it works. I am new to angular JS.
Try writing your service like this
mission_vision_mod.service('getMissionData', ['$rootScope','$http', function($rootScope, $http){
this.getMissionData=function(){
return $http.get('m_id.json');
}
}]);
Use Service in controller like this:
mission_vision_mod.controller('mission_visionCtrl', ['$scope','getMissionData','$http', function($scope,getMissionData,$http) {
$scope.visiontext = "Here is the content of vision";
getMissionData.getMissionData().success(function(response){
$scope.missions=response;
$scope.len = $scope.missions.length;
}).error(function(errorl){
//handle error here
});
}]);
Also I suggest using a better name for service -'MissionDataService' :)
EDIT- Your sequence of injected service should match sequence of injectable names specified in the array..See my last edit
['$scope','getMissionData','$http',
function($scope, $http, getMissionData
The service names don't match with the variable names.
My advice: stop using this array notation. It clutters the code and is a frequent source of bugs. Use ng-annotate.
That said, your service is not correctly defined. It doesn't have any member function that would allow it to be called. Re-read the documentation of services. Defining services using factory() is easier than defining them using service(), BTW. And the service should return the promise returned by $http. Trying to access the value returned by an asynchronous call right after making the asynchronous call will never work. Read http://blog.ninja-squad.com/2015/05/28/angularjs-promises/
Try:
mission_vision_mod.service('getMissionData', ['$rootScope','$http', function($rootScope, $http){
var missiondata;
function getmissiondata(){
$http.get('m_id.json').success(function(data){
missiondata = data;
return missiondata;
});
}
}]);

how to share data between two controllers in angularjs

Iam trying to share the data returned by $http to another controller.
$scope.getClickData=function(dataId){
var postData={"containerInstanceId" : "3842a251-1708-4df0-b941-db27a03d91ab","fetchMetadata":true,"parameters":{"#{organizationTypeID}":"abf1c91f-fea8-4033-a731-136c339525c7"}};
$http.post('http://latest.tapplent.info/api/app/layouts/v1/container-instance/data',postData).
success(function(data, status, headers, config) {
$scope.data=data;
console.log(data.containerData[0].propertyData.NULL[0].organizationTypeName.value);
}).
error(function(data, status, headers, config) {
console.log("error");
});
}
});
app.controller('webView', ['$scope', function($scope) {
console.log($scope.data);
}]),
How can i get data to webview controller. Please help me friends how can i solve this problem.
Thanks in advance.
By Three ways.
1.) You can use Angular factory/services.
myApp.factory('unicornLauncher', ["apiToken", function(apiToken) {
return new UnicornLauncher(apiToken);
}]);
https://docs.angularjs.org/guide/providers
2.) By use of broadcast and Emit.
You can share data via $broadcast or $Emit and then catch this data in any controller via $on.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope
I prefer Angular factory/services over broadcast/emit due to performance.
3.) Or you can use $rootscope. But that is least preferred as rootscope is your global scope. You should not litter your global scope.
The absolutely simplest way to do this would be to write the data to the rootScope.
$rootScope = data;
A better way would be to wrap the $http call in a service with methods to perform the call and retrieve the data and inject that into both controllers.
Other Way That I Usually Do like Angularjs Wire up a Backend 2nd last Example
controller1.js
from controller1 just pass dataId to controller2 and controller2 will contain request code that will bring data and populate in scope.
$scope.onButtonClick = function () {
$location.url('/controller2?dataId='+33);
//$scope.getClickData=function(dataId){}); add this func to controller2.js
}
This Code in controller1.js will
pass small dataId to other controller2.js
also navigate you to other controller2.js
controller2.js
app.controller('controller2', function($scope, $location)
{
var ID = $location.search();
$scope.getClickData=function(ID.dataId){
//REQUEST YOUR DATA
});
});
Note : As we remove (request/angular promise) getClickData() function
from controller1.js and add it to controller2.js .by doing this
controller2 will be responsible for its own data controller2 don't have to
depend on controller1 for data

Is there a way to hold off rendering the AngularJS view before all the AngularJS $scope data has been retrieved?

This might be a beginner question, but I am retrieving data via http calls in AngularJS and setting them as properties in the $scope variable. However, since http calls take a while, my page tries to load AngularJS more than once in order to render different parts of the page as more the data is retrieved. Is there a way around this? (to hold off on loading the page before all data has been retrieved)
What you could do is to use ng-hide or ng-cloak, so that whatever should not be displayed until the http call fully loaded the data would remain hidden.
take a look at the resolve property in the route settings. If you set something to be resolved the router will resolve this before going to the controller.
app.config(function ($routeProvider) {
$routeProvider
.when('/',
{
templateUrl: "app.html",
controller: "AppCtrl"
resolve: {
app: function ($q, $timeout) {
YourFactory.getData({});
}
}
}
)
});
then create a Factory that will get the data you need
app.factory('YourFactory', ['$http', '$q',
function($http, $q) {
var url = '/api2.php/api';
var YourFactory = {};
var factory_data = [];
var messages = [];
YourFactory.getData = function(params) {
console.log("into GET data");
var deferred = $q.defer();
$http.get(url).success(function(response) {
angular.copy(factory_data, response.data);
deferred.resolve();
}).error(function(response) {
//couldn't resolve therefore it's rejected
deferred.reject();
});
//returns a promise that indicates that something is being resolved and will be returned for the app to continue
return deferred.promise;
};
YourFactory.data = function() {
return factory_data;
};
return YourFactory;
}
]);
then in your controller you need to input the factory and set the scope data from the Factory. Remember that Angular used the Factory to get data before the controller using the resolve property.
app.controller("AppCtrl", ['$scope','YourFactory',
function($scope, YourFactory) {
$scope.data = YourFactory.data();
});
(I haven't tested the code, I simply wrote an example based on an app that I'am doing and in which I passed through the same things as you)
Look at this links if you have any doubt.
https://egghead.io/lessons/angularjs-resolve
http://www.javierlerones.com/2013/07/preloading-data-using-deferred-promises-in-angular-js.html

Angular.JS share a single JSON object between controllers

I´m trying to code a CRUD app with Angular.JS, and I need your help to move on.
This is the scenario:
View 1 (index) gets JSONP data from a remote API and stores it.
View 2 (master) shows data filtered on a grid
View 3 (detail) shows an specific item selected on View 2
I did it already, but requesting the very same JSON object on each view, , but I think one only api call is enough.
I can´t figure out how to properly share this JSON object for all the controllers. I tried several tutorials on ngResource, $http, factories and services but still have not a clear path to go through.
How can I do this?
Any snippet or code sample you may share will be very useful to keep on tryin this thing...
Thanks in advance,
Ariel
You can implement a base controller to store common functionality that's shared between the controllers. I wrote a blog post about it recently, here's the code snippet showing how it works:
'use strict';
angular.module('Diary')
// base controller containing common functions for add/edit controllers
.controller('Diary.BaseAddEditController',
['$scope', 'DiaryService',
function ($scope, DiaryService) {
$scope.diaryEntry = {};
$scope.saveDiaryEntry = function () {
DiaryService.SaveDiaryEntry($scope.diaryEntry);
};
// add any other shared functionality here.
}])
.controller('Diary.AddDiaryController',
['$scope', '$controller',
function ($scope, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
}])
.controller('Diary.EditDiaryController',
['$scope', '$routeParams', 'DiaryService', '$controller',
function ($scope, $routeParams, DiaryService, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
$scope.diaryEntry = data;
});
}]);
Using services to cache and share the data across controllers would be the way to go. Since services in angular are singleton, the same copy of data can be shared. A service such as
angular.module('myApp').factory('dataService', function($q, $resource) {
var items=[];
var service={};
service.getItems=function() {
var itemsDefer=$q.defer();
if(items.length >0)
itemsDefer.resolve(data);
else
{
$resource(url).query({},function(data) {
items=data;
itemsDefer.resolve(data)
});
}
return itemsDefer.promise;
}
return service;
});
Now in the controller you can inject the dataService and call the getItems method. This method returns a promise, which is either resolved using the cached data or by making remote request.
And the controller code would look something like
angular.module('myApp').controller('MyCtrl', function($scope,dataService) {
dataService.getItems().then(function(items) {
$scope.items=items;
}
});

Resources