I'm trying to ensure that upon loading the frame state, that my $rootScope has all the necessary properties defined from previous states.
The ionic.utils module is properly injected into my angular app. This module comes from my services.js file.
angular.module('ionic.utils', [])
.factory('dataService', ['$rootScope','$q','$timeout', function($rootScope, $q, $timeout) {
return {
get: function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve($rootScope);
}, 2000);
return deferred.promise;
}
}
}]);
Inside my controllers.js file, this is the corresponding controller for my frame state:
.controller('FrameCtrl', ['$scope','$state','$rootScope','dataService',
function($scope, $state, $rootScope, dataService) {
// get active address and delivery time.
dataService.get().success(function() {
console.log("derp");
});
}])
However, this controller returns the following console error upon state transition:
ionic.bundle.js:17696 TypeError: Cannot read property 'get' of undefined
at new <anonymous> (controllers.js:201)
at invoke (ionic.bundle.js:11591)
at Object.instantiate (ionic.bundle.js:11602)
at $get (ionic.bundle.js:14906)
at updateView (ionic.bundle.js:42986)
at IonicModule.directive.directive.compile.eventHook (ionic.bundle.js:42933)
at Scope.$get.Scope.$broadcast (ionic.bundle.js:20605)
at $state.transitionTo.$state.transition.resolved.then.$state.transition (ionic.bundle.js:34122)
at deferred.promise.then.wrappedCallback (ionic.bundle.js:19197)
at ionic.bundle.js:19283
I'm having trouble finding the error in the service I've written. Some help would be greatly appreciated!
EDIT
After adding the dependency injections into my controller, now the error has changed. Here it is:
TypeError: object is not a function
at new <anonymous> (controllers.js:202)
at invoke (ionic.bundle.js:11591)
at Object.instantiate (ionic.bundle.js:11602)
at $get (ionic.bundle.js:14906)
at updateView (ionic.bundle.js:42986)
at IonicModule.directive.directive.compile.eventHook (ionic.bundle.js:42933)
at Scope.$get.Scope.$broadcast (ionic.bundle.js:20605)
at $state.transitionTo.$state.transition.resolved.then.$state.transition (ionic.bundle.js:34122)
at deferred.promise.then.wrappedCallback (ionic.bundle.js:19197)
at ionic.bundle.js:19283
Your dependency array in controller is missing numerous dependencies passed to arguments
.controller('FrameCtrl', [ 'Rootscope', function($scope, $state,
$rootScope, Rootscope) {
Should be
.controller('FrameCtrl', ['$scope','$state', '$rootScope', 'Rootscope', function($scope, $state,
$rootScope, Rootscope) {
Sure seems confusing to me to name a service Rootscope!
Normally with promises we just use .then, which takes the success function as the first parameter and the error function as the second.
success and error are functions on a promise that AngularJS adds
for us when using $http or $resource. They're not standard, you
won't find them on other promises.
Code
dataService.get().then(function() {
console.log("derp");
});
Return was missing from deferred.resolve()
angular.module('ionic.utils', []).factory('dataService', ['$rootScope', '$q', '$timeout', function($rootScope, $q, $timeout) {
return {
get: function() {
var deferred = $q.defer();
$timeout(function() {
return deferred.resolve($rootScope);
}, 2000);
return deferred.promise;
}
}
}]);
Hopefully this will help you. Thanks.
Related
I have a partial in which data is coming from multiple controllers, not the situation is those functions which are called in the controller,they are hitting the server for more than fifty times, and they keep hitting as long as they dont get the response from server. I dont know how to tackle this situation please guide me.
mainControllers.controller('AddProductController', ['$scope', '$http', '$routeParams', '$cookies', '$rootScope', 'Upload', '$timeout', '$uibModal', '$log', '$document', '$window', 'variantsService', 'toaster', '$route', '$rootScope', 'Lightbox', function ($scope, $http, $routeParams, $cookies, $rootScope, Upload, $timeout, $uibModal, $log, $document, $window, variantsService, toaster, $route, $rootScope, Lightbox) {
/*Currency dynamic*/
$scope.currency = function () {
$http.get('currencies',
{headers:
{'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': $rootScope.keyword_auth_token, 'Accept-Language': $cookies.get('type')}
})
.success(function (data) {
$scope.user_curr = data[0].code;
})
.error(function (data) {
console.log(data);
});
};
/*Currency dynamic ends here*/
$scope.currency();
}]);
Is there any way, any way, so that I can limit this thing?
It definitely is a bad idea to have multiple controllers for a single partial. You should consider using angular factories for maintaining data in such cases. But to provide you a short solution, you should remove the line $scope.currency(); from your controller (because it would make an api call as soon as your controller is initialized) and consider using ng-init built-in directive. So, basically in your partial where you are using ng-controller="AddProductController", you can add ng-init="currency()" (If you want to make an api call).
I always put the calls in a service, and then you can take full control. Something like this:
app.service("currencyService", function($q, $http) {
var _currencyPromise = null,
_currencies = null;
this.getCurrencies = function() {
var deferred = $q.defer();
// Check if the currencies are resolved before
// If so, immediately return these
if (_currencies) {
deferred.resolve(_currencies);
}
// Else check if the promise is already running
// If so, use that promise
else if (_currencyPromise) {
_currencyPromise.then(function(response) {
deferred.resolve(response.data);
});
}
// Else make the http call and assign to the promise
// So that the promise can be used instead of a new http call
else {
_currencyPromise = $http.get("..");
_currencyPromise.then(function(response) {
// Assign data to the currencies, so that it can be used
// by next calls immediately
_currencies = response.data;
deferred.resolve(_currencies);
}, function(error) {
// something went wrong
_currencyPromise = null;
deferred.reject();
});
}
return deferred.promise;
}
});
Then in your controllers you can always use this service, while the http call will only be made once:
app.controller("myCtrl", ["$scope", "currencyService", function($scope, currencyService) {
currencyService.getCurrencies().then(function(currencies) {
$scope.user_curr = currencies[0].code;
});
}]);
See this jsfiddle for reference. In the console you can see that the API is only called once.
I came up with a quite simple solution. For example I have a view like this
<div ng-controller="HomeController">
<div class="active tab-pane" ng-controller="AddProductController" ng-init="subcategories_id();currency();">
<p>{{user_curr}}</p>
</div><!--ends here->
<p>first controller {{abc}}</p>
</div>
I am using the nginitwhich works fine.
I have seen a couple of questions like this before but they are usually clearly missing injections, and hopefully that isn't the case with my problem.
As part of my app I am making I am trying to make a get request to the server to return a list of modules.
Controller
app.controller('ModulesCtrl', ['$scope','modFact','quizIndexFactory', '$http', function($scope, $http, quizIndexFactory, modFact){
$scope.moduleSet;
$scope.status;
getModules();
function getModules(){
modFact.getList()
.then(function (response) {
$scope.moduleSet = response.data;
}, function (error) {
$scope.status = 'unable to load modules in controller: ' + error.message;
});
}
Factory
app.factory('modFact', ['$http', function($http){
var modFact = {};
modFact.getList = function() {
console.log("success");
return $http.get('http://localhost:3000/module');
};
return modFact;
}]);
Yet I get the error pointing to the function call in the controller:
Error: modFact.getList is not a function
Any ideas? I am following the structure provided by this blog post:
http://weblogs.asp.net/dwahlin/using-an-angularjs-factory-to-interact-with-a-restful-service
It seems that the order of arguments being injected into the controller does not match the order that you supply the arguments. In your controller, the entity that is named modFact is actually angular's $http service (which doesn't have a getList method).
(Taking a little liberty with indentation and newlines to demonstrate the problem):
[ '$scope','modFact','quizIndexFactory', '$http',
function($scope, $http, quizIndexFactory, modFact) {
...
}]
should be:
[ '$scope', '$http', 'quizIndexFactory', 'modFact',
function($scope, $http, quizIndexFactory, modFact) {
...
}]
I've made a handful of Angular applications in the past, but have never really made use of modules. I'm creating an Ionic app right now (which uses Angular) and for some reason I cannot get my services to inject into the controllers.
controllers.js
angular.module('myapp.controllers', [])
.controller('StreamCtrl', ['$scope', 'StreamService',
function($scope, StreamService) {
$scope.playlists = [1,2,3,4];
}]);
services.js
angular.module('myapp.services', [])
.factory('StreamService', ['$scope', function($scope) {
var self = {
'fetching' : false,
'streamItems' : []
};
return self;
]);
app.js
angular.module('myapp', ['ionic',
'myapp.services',
'myapp.controllers',
'ngCordova',
'LocalStorageModule'])
// And lots of other code that isn't needed for this question.
So when I try and load the StreamCtrl I end up getting the following error:
Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope <-StreamService
http://errors.angularjs.org/1.3.6/$injector/unpr?p0=<ion-nav-view name="menuContent" class="view-container" nav-view-transition="ios">copeProvider%20%3C-%20%24scope%20%3C-%20StreamService
at REGEX_STRING_REGEXP (http://localhost:8100/lib/ionic/js/ionic.bundle.js:7888:12)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:11806:19
at Object.getService [as get] (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11953:39)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:11811:45
at getService (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11953:39)
at Object.invoke (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11985:13)
at Object.enforcedReturnValue [as $get] (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11847:37)
at Object.invoke (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11994:17)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:11812:37
at getService (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11953:39)
See this working fiddle ,
You are treating service as if it was a controller, never inject a $scope into service, its not there
var myApp = angular.module('myApp',['myapp.services','myapp.controllers']);
angular.module('myapp.controllers', [])
.controller('StreamCtrl', ['$scope', 'StreamService',
function($scope, StreamService) {
$scope.playlists = [1,2,3,4];
}]);
angular.module('myapp.services', []).factory('StreamService', function() {
var self = {
'fetching' : false,
'streamItems' : []
};
return self;}
);
Your error clearly says there is problem inside StreamService factory.
You could never inject $scope inside factory. Removing $scope dependency will solve your issue.
Factory basically used to expose singleton methods, common and sharable data. Usually we write any service call or method which can be accessible by any module who inject it using its dependancy.
Factory
angular.module('myapp.services', [])
.factory('StreamService', [function() {
var self = {
'fetching': false,
'streamItems': []
};
return self;
}]);
Working fiddle.
Hope this could help you. Thanks.
I'm attempting to handle http errors within AngularJS (using ui-router), but am losing the context of my run function in the following code.
bugtracker.run(['$rootScope', '$state', function($rootScope, $state) {
//at this point $state and $rootScope are defined
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {
//at this point $state and $rootScope are undefined
});
}]);
The code that causes $stateChangeError to trigger is as follows.
//main.js
bugtracker.config(['$stateProvider', '$httpProvider', '$compileProvider', function($stateProvider, $httpProvider, $compileProvider) {
//...
$stateProvider.state('projects.show', {
url: '/{projectId:[0-9]{1,8}}',
templateUrl: '/assets/projects/show.html',
controller: 'ProjectShowCtrl',
resolve: bugtracker.controller('ProjectShowCtrl').resolve
});
//...
}]);
//ProjectShowCtrl.js
projectShowCtrl.resolve = {
project: function(Project, $q, $stateParams, $state) {
var deferred = $q.defer();
Project.findById($stateParams.projectId, function(successData) {
deferred.resolve(successData);
}, function(errorData) {
deferred.reject(errorData); // you could optionally pass error data here
});
return deferred.promise;
},
delay: function($q, $timeout) {
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
};
I would like $state to be defined within the anonymous function called by the $on function so that I could redirect the user to a 401, 403, etc. page, but I'm unsure why it is not.
In other examples I have seen (https://github.com/angular-ui/ui-router/issues/898) it is implied that $state is defined within the context of the anonymous function.
If anyone could explain why $state is not defined or what I can change to make it defined I would greatly appreciate it!
There's no way these would be undefined, unless they were already undefined in the run block. However I've seen cases where the debugging tool thinks some variables are undefined when they actually aren't. That happened to me in FireBug with an old FF version.
I have a service in Angular which uses my API to get user information and provides it to my controllers. It's set up like this:
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ngResource', 'infinite-scroll', 'ui.bootstrap', 'ngCookies', 'seo'])
.service('userInfo', function($http, $cookies){
$http.get('/api/users/' + $cookies.id).
success(function(data) {
var userInfo = data.user[0];
return userInfo;
});
}). // other stuff comes after this
In my controllers, I include it like:
function userProfile($scope, $cookies, userInfo, $http, $resource, $routeParams, $rootScope){
$scope.user = userInfo;
console.log('user info is')
console.log(userInfo);
This is returning no data, while if I put the same service function in the controller itself it returns just fine. What am I missing here? Never used DI/Services in Angular before so might be a simple mistake somewhere.
I need to ensure that the service returns data before the controller loads. How can this be accomplished
You can make the factory to return a promise like this:
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ngResource', 'infinite-scroll', 'ui.bootstrap', 'ngCookies', 'seo'])
.service('userInfo', function ($http, $cookies) {
var promise = $http.get('/api/users/' + $cookies.id).
success(function (data) {
var userInfo = data.user[0];
return userInfo;
});
return promise;
}) // other stuff comes after this
And in your controller, do
function userProfile($scope, $cookies, userInfo, $http, $resource, $routeParams, $rootScope){
userInfo.then(function(data){
$scope.user = data;
});
}
This can guarantee that whenever you use the service, it always gives you the data synchronously, you don't have to necessarily load any data before loading the controller.
Your userInfo service has to return the promise returned by $http. That promise will then be injected into your controller, and the view will be updated as soon as the promise successfully resolves.
If you don't want the view to be rendered at all before userInfo resolves, you should set a resolve property on your route, and inject your service there:
$routeProvider.when('/profile', {
templateUrl: 'profile',
controller: userProfile,
resolve: {
userInfoData: function ($q, userInfo) {
return userInfo;
}
}
});
Then just inject userInfoData into your controller in place of the userInfo service.
You can assign the resource object to your variable like that
return $http.get(url)
I've faced the same problem in which I had to load data into a service using $resource and get that data into controllers $scope.
I didn't wanted to directly return the promise and then use a resolver in the controller (as #zsong wrote) but to do all the magic into the service once and use the ability to assign a promise directly to a $scope as #Joseph Silber point out, so here is what I did :
return function($scope){promise.then(function(data){$scope.user = data})};
And used it in the controller like this :
userInfo($scope);
Not much of an improvement but it allowed me a clearer syntax in my controllers, hope it'll help even three years later !