I have some issue with AngularJS scope and location. Here is an example :
function CreateAccountCtrl($scope, $http, $location) {
...
$http.post(url,$scope.form).
success(function(data){
$location.path('/'); // I need to transfert data to the location
}
}
My problem is : I want to transfer the data to the / controller, I thought to use the rootScope but I don't think it is the best way to do this.
Any idea ?
You can use $rootScope to send data between controllers. $routeParams doesn't allow send complex data structures.
Let's see it.
Assign returned data of success callback to variable in $rootScope.
Navigate to the AccountController.
function CreateAccountCtrl($scope, $http, $location,$rootScope ) {
...
$http.post(url,$scope.form).
success(function(data){
$rootScope.accountInfo = data;
$location.path('/account');
}
}
Configure the route in the $routeProvider:
$routeProvider.when('/account', {
template: 'account.html',
controller: AccountCntl
});
In the AccountController can access the data on $rootScope.
function AccountCtrl($scope, $rootScope) {
$scope.accountInfo = $rootScope.accountInfo;
}
Use the $routeParams service.
function CreateAccountCtrl($scope, $http, $location) {
...
$http.post(url,$scope.form).
success(function(data){
$location.path('/account/' + data.accountId);
}
}
Configure the route in the $routeProvider:
$routeProvider.when('/account/:accountId', {
template: 'account.html',
controller: AccountCntl
});
Your AccountController can now access the data:
function AccountCtrl($scope, $routeParams) {
$scope.accountId = $routeParams.accountId;
}
Related
I am working on angularjs (1.6) and want to made a functionality in angular service, its call when a controller call and its service have an ajax code like
app.service('myServ', function($http, $window){
this.backdoor=function(){
$http({
method : 'get',
url : 'web_services/backdoor.php'
}).then(function(res){
// console.log(res.data);
// console.log(res.data.length);
if(res.data.length==0)
{
$window.location.href="index.html";
}
});
}});
and my controller code is :
app.controller('myCtrl', function($scope, $http, $window, myServ, $routeParams){
myServ.backdoor();
});
so the above code (service) is check a user session is created or not, but the problem is when session is not created on server side then my html page load for a second then server will call $window.location.href so please help me about the right way to do this....
I believe you need a resolve in angular.config. Its job is to run some code before you are being redirected to your route/state (for ngRoute or ui.router).
To do that you would need to have:
app.service('myServ', function($http, $window){
this.backdoor=function(){
return $http({ // return the promise if you need to use the values in the controller
method : 'get',
url : 'web_services/backdoor.php'
}).then(function(res){
if(res.data.length==0){ $window.location.href="index.html"; }
else{ return res.data; } // return the values
});
}});
and main part:
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/your_page/:route_params', {
templateUrl: 'your_page_partial.html',
controller: 'myCtrl',
resolve: {
resolvedVal: function resMyService(myServ, $routeParams){ // setting an injectable instance `resolvedVal`
/* use $routeParams values as parameters? */
return myServ.backdoor(); // calling your service
}
}}
);
}]);
Then it's enough to just inject your resolve into the controller:
app.controller('myCtrl', function($scope, $http, $window, resolvedVal){ // note: resolvedVal injection
$scope.my_data = resolvedVal;
});
'use strict';
angular.module('sampleApplicationApp').config(function($stateProvider)
{
$stateProvider.state('abcmanagement', {
parent : 'parentmanagement',
url : '/em',
views : {
'content#' : {
templateUrl : 'scripts/app/abc.html',
controller : 'abcController'
}
}
}).state('newmodel', {
parent : 'abcmanagement',
url : '/new',
views : {
'content#' : {
templateUrl : 'scripts/app/xyz.html',
controller : 'xyzController'
}
}
})
});
angular.module('sampleApplicationApp')
.controller('abcController', function ($scope, $state, $modal) {
$scope.models = {};
// logic to load models
});
angular.module('sampleApplicationApp')
.controller('xyzController', function ($scope, $state, $modal) {
// I want to access models from above controller
});
Is there a possibility i can have access to models defined in abcController from xyzController ?
two options:
if the controllers inherit from the same parent controller, you can store the data in the parent $scope (or $rootScope, but that's bad practice);
if the controllers do not inherit from the same parent controller, use a factory to share data between controllers:
`
angular.module('sampleApplicationApp')
.factory('abcModel', function () {
var factory = {};
var model = {};
factory.setModel = function(key, value) {
model[key] = value;
}
factory.getModel = function(key) {
return model[key];
};
return factory;
});
angular.module('sampleApplicationApp')
.controller('abcController', function ($scope, $state, $modal, abcModel) {
abcModel.setModel('abc', "hello world");
});
angular.module('sampleApplicationApp')
.controller('xyzController', function ($scope, $state, $modal, abcModel) {
$scope.value = abcModel.getModel('abc');
});
You have, potentially, as many as three options:
1) If xyzController resides within abcController within your HTML then you can reference $parent.property ('property' being the name of the $scope property in the parent controller you want access to).
2) You could use $rootScope by setting any properties you want to access in multiple controllers like so, $rootScope.property. I would recommend avoiding this as it could pollute the global scope.
3) You could use an Angular service with methods for getting and setting the variables in question. Then you could simply inject this service as a dependency in each controller where you need access to these variables. Recommended approach
The best practice is that you should create an Angular service which holds the variable.
You can work around it by using the $rootScope. Don't forget to inject it in both controllers ;)
There are many ways to achieve what you are trying to do.You can create a factory or a service,you can use $rootScope(not recommended),you can use angular's broadcast, emit method to achieve this.Refer to this example http://stackoverflow.com/questions/21919962/share-data-between-angularjs-controllers
I use routeProvider in Angular JS:
.when('/profile/personal', {
templateUrl: 'personal.html',
controller: 'EditProfileController'
})
How I can pass param to controller EditProfileController and here call Ajax method that returns data. This data must be display in template of route in personal.html.
Example:
.controller('EditProfileController', ['$scope', '$http', function ($scope, $http) {
// If was click on `/profile/personal` from route, must get patam `personal` and call method GetAjax(param);
$scope.GetAjax = function (param){
//here return data put it in template HTML from route
}
}]);
My links are located in page by path:
http://wd.tk/profile
When I click to link route I get URL:
http://wd.tk/profile#/profile/personal/1
Id do:
.controller('EditProfileController', ['$scope', '$http', function ($scope, $http, $routeParams) {
console.log($routeParams);
}]);
I get error:
TypeError: Cannot read property 'idProfile' of undefined
First, in your url configuration, you must put the parameter of url:
when('/profile/personal/:idProfile', {
templateUrl: 'personal.html',
controller: 'EditProfileController'
})
Now, in your EditProfileController, you should get the parameter and call to ajax request:
Inject the $routeParams object and get the parameter with
$routeParams.idProfile:
.controller('EditProfileController',
function ($scope, $http, $routeParams) {
var idProfile = $routeParams.idProfile;
$http.get("service url").then(setData, setError);
function setData(data) {
$scope.data = data;
}
function setError() {
alert("error on get data profile");
}
}]);
In your html, you will show your data profile in the correct format.
But I recommend that all the ajax calls should groups in angular services.
PD:
Check It out angular ui router:
What is the difference between angular-route and angular-ui-router?
hope this helps.
You you need to change your $routeProvider, that should have /profile/:type instead of /profile/personal that means you are going to provide value for :type which can be accessible by injectin $routeParams service inside controller.
.when('/profile/:type', {
templateUrl: 'personal.html',
controller: 'EditProfileController'
})
Controller
.controller('EditProfileController', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
$scope.profileType = $routeParams.type;
$scope.GetAjax = function (){
//here you have profile type in $scope.profileType
//you can pass it to ajax by simply accessing scope variable.
$http.get('/getprofiledata?type='+ $scope.profileType)
.success(function(data){
$scope.profileData = data;
})
.error(function(error){
console.log('error occured')
})
}
$scope.GetAjax(); //calling it on controller init
}]);
Update
YOu had missed one of dependency $routeParams in array annotation.
.controller('EditProfileController', ['$scope', '$http', '$routeParams',function ($scope, $http, $routeParams) {
console.log($routeParams);
}]);
I am developing a permission system for my app using a factory that looks like this:
angular.module('ecosystemServices', [])
.factory('Guard', function($http, $rootScope) {
var permissions = [];
return {
ready: function() {
if (permissions.length == 0) {
$http.get('/api/users/own-permissions')
.success(function(data){
permissions = data.user_permissions;
$rootScope.$broadcast('permissionsReady', 1);
});
} else {
$rootScope.$broadcast('permissionsReady', 1);
}
return true;
}
}
})
I have to wait until the permissions are loaded to start making queries, so I'm performing a broadcast to the controller, that looks something like this:
appControllers.controller('AgencyPanelCtrl', ['$rootScope', '$scope', '$location', '$routeParams', '$http','Guard',
function ($rootScope, $scope, $location, $routeParams, $http, Guard) {
$scope.loading = true;
Guard.ready();
$scope.has_permission = function(permission) {
return Guard.can(permission);
}
$rootScope.$on('permissionsReady', function(event, ready) {
$scope.initialize();
});
$scope.initialize = function() {
console.log("Initialized");
}
}]);
It's working, but if I change the controller and do the same (change the view and change the controller), the broadcast arrives to the old controller.
Does anyone knows why? Or how to fix it?
You are defining your event listener on the $rootScope. As the name would suggest, there is only one $rootScope, and it's at the root of the document.
As such, when your view changes and the old controller is no longer relevant, the $rootScope still has the listener, which still holds a reference to the old controller's $scope through a closure, and hence everything still goes to the old controller.
Instead, you should define the listener on the $scope of the controller:
$scope.$on('permissionsReady', function(event, ready) {
$scope.initialize();
});
This should fix your problem.
I have the following code under my AngularJS .run which works perfectly on my local development machine but won't work when uploaded to my client server...after few tests it is obvious that by the time the controller is loaded the event is not triggered yet so most of the functions in the controller depending on this event do not work. Can someone please tell me what I am doing wrong here and how to fix it? Thanks
myApp.run(['AuthDataSvc', '$rootScope', function (AuthDataSvc, $rootScope) {
AuthDataSvc.getAuth().then(function(Token){
$rootScope.$broadcast('Token', Token);
}, function(status){
console.log(status);
});
}]);
You are always going to have a race condition. I have a couple alternatives you can do:
1) Use a service. I am not really a fan of this option because it leads to Spaghetti code. And most time you don't want the controller to run until you have logged on. I prefer option 2.
myApp.run(['AuthDataSvc', '$rootScope', function (AuthDataSvc, $rootScope) {
AuthDataSvc.getAuth(); /* no op we will use the service to determine logged in */
}]);
/* inside a controller */
if(AuthDataSvc.isLoggedIn()){
//do something.
}
2) Use a route.resolve. Resolves are defined on the route and the Controller will only load once it the promise has been set to resolved. I showed you an example for ui-router and ng-route you need to pick your poison. If you dont use ui-router you should consider it.
/* app.config ... route config.. */
var waitForLogon = {
UserToken: ["AuthDataSvc", function (AuthDataSvc) {
return AuthDataSvc.logon();
}]
};
//this is for ng-route
$routeProvider
.when('/Book/:bookId', {
templateUrl: '--',
controller: 'MyCtrl',
resolve: waitForLogon
})
//this is for ui-router
$stateProvider
.state('me', {
templateUrl: '--',
controller: 'MeCtrl',
resolve: waitForLogon
})
/* controller */
angular.module('yourapp')
.controller('MyCtrl', ["UserToken", ... , function(UserToken){
//User Token will always be here when your Ctrl loads.
});
/* service code -- */
angular.module('yourapp')
.service('AuthDataSvc', ["LogonModel", "$q", function(LogonModel, $q) {
this._q = null;
var that = this;
this._doAuth = function(){
this.getAuth().then(function(Token){ that._q.resolve(Token) }, function(error){that._q.reject(error);}
};
this.logon = function () {
if(!this._q){
this._q = $q.defer();
this._doAuth();// <-current auth do here, and resolve this._q when done
}
return this._q.promise;
};
});