angular services declaration - angularjs

I am working on a simple angular SPA. I got the services working, and then wanted to extract them to a separate file. I've done something wrong with syntax and dependencies, and I'm wondering if anyone can help me spot it. I know I am confusing some things, and there might be a couple of additional bugs. I'm open to hearing some ideas about where I'm going wrong here. Please advise.
current angular error
Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope <- FetchProduct
http://errors.angularjs.org/1.3.14/$injector/unpr?p0=<article class="demo ng-scope" ng-view="product-list">copeProvider%20%3C-%20%24scope%20%3C-%20FetchProduct
Error: $injector:unpr Unknown Provider Unknown provider: Description
This error results from the $injector being unable to resolve a
required dependency. To fix this, make sure the dependency is defined
and spelled correctly.
markup
<!doctype html>
<html ng-app="demoApp">
<head>
<title>Kat Chilton | Escalada | Angular Skills Demo App</title>
<link rel="stylesheet" href="demo.css" type="text/css">
<link href='http://fonts.googleapis.com/css?family=Oswald:400,300,700' rel='stylesheet' type='text/css'>
</head>
<body ng-controller="ProductListCtrl">
<article class="demo" ng-view="product-list">
</article>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-route.js"></script>
<script src="controllers.js"></script>
<script src="app.js"></script>
<script src="services.js"></script>
</body>
</html>
app.js
'use strict';
var demoApp = angular.module('demoApp', [
'ngRoute',
'DemoControllers',
'DemoServices'
]);
demoApp.config(['$routeProvider',
function($routeProvider){
$routeProvider.when('/products/', {
templateUrl: 'product-list.html',
controller: 'ProductListCtrl'
})
.when('/products/:product_id', {
templateUrl: 'product-detail.html',
controller: 'ProductDetailCtrl'
})
.otherwise({
redirectTo: '/products/'
});
}]);
controllers.js
var DemoControllers = angular.module('DemoControllers', []);
DemoControllers.controller('ProductListCtrl', ['$scope', '$http', 'FetchList',
function ($scope, $http, FetchList) {
$scope.products = FetchList;
}]);
DemoControllers.controller('ProductDetailCtrl', ['$scope', '$http', '$routeParams', 'FetchProduct',
function ($scope, $http, $routeParams, FetchProduct) {
$scope.selection = FetchProduct;
}]);
services.js:
var DemoServices = angular.module('DemoServices', []);
DemoServices.factory('FetchList', ['$http', function ($http) {
var list;
var FetchList = function ($http) {
$http.get('https://s3-eu-west-1.amazonaws.com/developer-application-test/cart/list')
.success(function (data, status, headers, config) {
// console.log('data :: ', data, 'status :: ', status, 'headers :: ', headers, 'config :: ', config);
list = data.products;
});
};
return {products: new FetchList($http)};
}]);
DemoServices.factory('FetchProduct', ['$http', '$scope', function ($http, $scope) {
var product;
var FetchProduct = function ($http, $scope) {
$http.get('https://s3-eu-west-1.amazonaws.com/developer-application-test/cart/' + $scope.product_id + '/detail')
.success(function (data, status, headers, config) {
console.log('data :: ', data, 'status :: ', status, 'headers :: ', headers, 'config :: ', config);
product = data;
});
};
return {product: new FetchProduct($http, $scope)};
}]);

var demoApp = angular.module('demoApp', [
'ngRoute',
'DemoControllers'
])
.service('DemoServices');
This is incorrect. The service() method is used to add a new service to the module. It takes a service name as argument, and a constructor function for the service. What 'DemoServices' is here is the name of a module. And you want to add this module as a dependency of demoApp. So you just need to add it to the dependencies array, already containing ngRoute and DemoControllers:
var demoApp = angular.module('demoApp', [
'ngRoute',
'DemoControllers',
'DemoServices'
]);
EDIT:
OK, now that I have a clear error message, the error is more obvious. Your service FetchProduct depends on $scope. But $scope is not a service, and thus can't be injected in a service. Controllers have a $scope, and angular creates one every time the controller is instantiated, but services are singletons, and don't have any scope: they're not associated to any DOM element.
Your service should look like this:
DemoServices.factory('productFetcher', ['$http', function($http) {
var getProduct = function(productId) {
return $http.get('https://s3-eu-west-1.amazonaws.com/developer-application-test/cart/' + productId + '/detail').then(function(response) {
return response.data;
});
});
return {
getProduct: getProduct;
};
}]);
and it should be used like this, in a controller, to get the product 42:
productFetcher.getProduct(42).then(function(product) {
$scope.product = product;
});

Related

Executing any one function in controller executes the entire controller function

I am a newbie to Angular. I am using a controller and I am initially loading the page using the init function. I have an element on html that activates the incrementPage function. When I activate the function, the init function executes again and I get the same result instead of the next page. How do I solve this issue?
myApp.controller('MusicController', ['$scope', '$resource', function($scope, $resource){
var vm = $scope;
init();
function init(){
vm.pgno = 1;
music = $resource('http://104.197.128.152:8000/v1/tracks/', {"page": vm.pgno}).get({"page": vm.pgno});
vm.tracks = music;
}
vm.incrementPage = function(){
vm.pgno = vm.pgno + 1;
console.log(vm.pgno);
music = $resource('http://104.197.128.152:8000/v1/tracks/', {"page": vm.pgno}).get({"page": vm.pgno});
vm.tracks = music;
console.log(vm.pgno);
};
}]);
Also, I am using ngRoute and two different controllers.
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: "views/listMusic.html",
controller:'MusicController',
})
.when('/genres', {
templateUrl: "views/genres.html",
controller:'MusicGenreController',
})
}]);
myApp.controller('MusicGenreController', ['$scope', 'tracklister', function($scope, tracklister) {
var vm = $scope;
var gpgno = 1;
var incrementGPage = function(){
gpgno += 1;
gen = tracklister.genreList.get({'page': gpgno});
vm.genres = gen;
}
(function(){
gen = tracklister.genreList.get({'page': gpgno});
vm.genres = gen;
})();
}]);
When I click the Genres instead of taking me to the genres view it is getting me back to the same listMusic view inside the first MusicController controller. What to do here?
<!DOCTYPE html>
<html ng-app='ListTracksApp'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-route.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-resource.js"></script>
<script src="appl.js"></script>
<meta charset="utf-8">
<link rel="stylesheet" href="styles.css">
<title>Music</title>
</head>
<body>
<h1>Music Tracks</h1>
Genres
<div ng-view>
</div>
</body>
</html>
In your controller, change it to this:
myApp.controller('MusicController', ['$scope', '$resource', function($scope, $resource) {
var vm = $scope;
function $onInit() {
// the rest of your code
That'll get called once, when the controller initializes. Also I think your link is incorrect, as georgeawg pointed out but I'm not too familiar with ngRoute, I've used uiRouter for years, it should be #!/genres
One other thing although this isn't related to your question, in your init() function you have a call to your db, which I suspect is going to be async, you should probably use resolve in the ngRoute and inject it into the controller so it's initially resolved:
resolve: {
data: function ($resource) {
var url = 'http://104.197.128.152:8000/v1/tracks/';
return $resource(url, {"page": 1}).get({"page": 1}).$promise;
}
}
Then your controller can use 'data' as the result of the call:
myApp.controller('MusicController', ['$scope', '$resource', 'data', function($scope, $resource, data)

Error: [$injector:unpr] http://errors.angularjs.org/1.5.0/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope%20%3C-%20

I'm a new in Angularjs and developing a simple Calculator application with backend support.
Since I separate controller to controller+service - there is an error like:
Error: [$injector:unpr] http://errors.angularjs.org/1.5.0/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope%20%3C-%20calcService
So can anyone shed light where I'm wrong ?
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="bootstrap-3.0.3-dist/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="css/style.css" />
<script type="text/javascript" src="js/jquery-1.12.2.min.js"></script>
<script src="angular/angular.min.js"></script>
<script type="text/javascript" src="angular/angular-ui-router.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
<script type="text/javascript" src="js/services/calcService.js"></script>
<script type="text/javascript" src="js/controllers/calcCtrl.js"></script>
<script type="text/javascript" src="js/controllers/resultsCtrl.js"></script>
</head>
<body>
<div class="container" ng-app="app">
<header ng-include="'templates/nav.html'"></header>
<div ui-view></div>
<footer ng-include="'templates/footer.html'"></footer>
</div>
</body>
</html>
app.js
angular
.module('app', [
'ui.router'
])
.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('calc', {
url: '/',
templateUrl: '../templates/calc.html',
controller: 'calcCtrl'
})
.state('results', {
url: '/results',
templateUrl: '../templates/results.html',
controller: 'resultsCtrl'
})
}]);
calcCtrl.js:
angular
.module('app')
//.controller('calcCtrl', ['$scope', '$http', function($scope, $http) {
.controller('calcCtrl', ['$scope', 'calcService', function($scope, calcService) {
$scope.title = "Calculator";
$scope.items = ['calc','results'];
$scope.selectedValue = 'calc';
}]);
calcService.js:
//angular.module('app', []);
angular.module('app')
.factory('calcService', ['$scope', '$http', function($scope, $http) {
$scope.calculate = function() {
// use $.param jQuery function to serialize data from JSON
var data = $.param({
left: $scope.left,
right: $scope.right,
operation: $scope.operation
});
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
}
$http.post('/calc/calculate', data, config)
.success(function (data, status) {
$scope.responseData = "Result is : " + data;
})
.error(function (data, status) {
$scope.responseData = "Data: " + data +
"<hr />status: " + status;
});
};
} ]);
Files structure: https://gyazo.com/5d571f2a92757a4c20239cb67d8b0d5c
Here is what I'm currently have with errors in firebug: https://gyazo.com/4e367b3644b0f106938f272e2980f074
If I uncomment 1st line in calcService.js - here is a result (totally hidden UI): https://gyazo.com/fb6714f5d131ab31ae0ca17509b19968
You can't inject $scope into a factory - how would it know what scope to inject? If you need to use scope data then you pass it from your controller as parameters on the factory methods. Also, your service should return the promise which you then handle in your controller.
Factory:
angular.module('app')
.factory('calcService', ['$http', function($http) {
var service = {};
service.calculate = function(left, right, operation) {
// use $.param jQuery function to serialize data from JSON
var data = $.param({
left: left,
right: right,
operation: operation
});
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
}
return $http.post('/calc/calculate', data, config);
};
return service;
}]);
In your controller:
angular.module('app')
.controller('calcCtrl', ['$scope', 'calcService', function($scope, calcService) {
$scope.title = "Calculator";
$scope.items = ['calc','results'];
$scope.selectedValue = 'calc';
$scope.calculate = function(){
calcService.calculate($scope.left, $scope.right, $scope.operation).then(
function(response) {
$scope.responseData = "Data: " + response.data;
},
function(error) {
// examine the error properties and do whatever
}
);
};
}]);

ngRoute resolve injector issue

I'm getting an error saying,
[$injector:unpr] http://errors.angularjs.org/1.4.1/$injector/unpr?p0=qProvider%20%3C-%20q%20%3C-%20searchResult
When I use the following config and controller. I'm trying to resolve and http request on a specific route.
.when('/fsr/:first', {
templateUrl: 'views/fsr.html',
controller: 'fsrCtrl',
resolve: {
searchResult: ['$http', 'q', function($http, $q) {
var def = $q.defer();
var samples;
$http.get('/api/fsr').success(function(data, status){
samples = data;
def.resolve(data);
})
return {
getSamples: function() {
return def.promise;
}
}
}]
}
})
.controller('fsrCtrl', ['$scope', 'searchResult', function($scope, searchResult){
searchResult.getSamples().then(function(data){
console.log(data);
})
}])
Why I'm getting this?
Here are the solution, change q to $q.
searchResult: ['$http', '$q', function($http, $q) {
...
}
var app = angular.module('webbapp', ['ngRoute']);
app.config(['$routeProvider', function ($routeProvider) {
console.log('woot');
$routeProvider
.when('/fsr', {
templateUrl: 'fsr.html',
controller: 'fsrCtrl',
resolve: {
searchResult: ['$http', '$q', function($http, $q) {
var def = $q.defer();
var samples;
$http.get('/api/fsr').success(function(data, status){
samples = data;
def.resolve(data);
})
return {
getSamples: function() {
return def.promise;
}
}
}]
}
})
}])
.controller('fsrCtrl', ['$scope', 'searchResult', function($scope, searchResult){
searchResult.getSamples().then(function(data){
console.log(data);
})
}])
angular.bootstrap(document, ['webbapp']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Hello Plunker!</h1>
Load Fsr view
<div ng-view=""></div>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-route.min.js"></script>
<script src="app.js"></script>
</body>
</html>

AngularJS: TypeError: Cannot read property 'get' of undefined

I am trying to use a service inside my angular controller, however I am getting the error in the TypeError: Cannot read property 'get' of undefined.
This is how my app.js script look like:
angular
.module('ToDoApp', ['ngAnimate', 'todoService'])
.controller('ToDoController', ['$scope', function($scope, $http, Todo) {
Todo.get()
.success(function(data) {
$scope.tasks = data;
});
// ...
}]);
It doesn't know about the get propery. This is how Todo looks like:
angular.module('todoService', [])
.factory('Todo', function($http) {
return {
get: function() {
return $http.get('/todos');
},
// ...
}
});
And I'm loading the scripts in this order:
<script src="{{ asset('/scripts/services/todoService.js') }}"></script>
<script src="{{ asset('/scripts/app.js') }}"></script>
The error sounds to me like the controller isn't getting the service object correctly, like this dependency is missing. But I already loaded the dependency with the module.
What am I missing?
Deleted my previous comment, figured out what you had wrong. You're using the array notation to fix minification, but you're only listing $scope, you need to list the others as well, meaning you need to add the $http and the ToDo:
angular
.module('ToDoApp', ['ngAnimate', 'todoService'])
.controller('ToDoController', ['$scope', '$http', 'ToDo', function($scope, $http, Todo) {
Todo.get()
.success(function(data) {
$scope.tasks = data;
});
// ...
}]);

Simple Angular $routeProvider resolve test. What is wrong with this code?

I have created a simple Angular JS $routeProvider resolve test application. It gives the following error:
Error: Unknown provider: dataProvider <- data
I would appreciate it if someone could identify where I have gone wrong.
index.html
<!DOCTYPE html>
<html ng-app="ResolveTest">
<head>
<title>Resolve Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"> </script>
<script src="ResolveTest.js"></script>
</head>
<body ng-controller="ResolveCtrl">
<div ng-view></div>
</body>
</html>
ResolveTest.js
var rt = angular.module("ResolveTest",[]);
rt.config(["$routeProvider",function($routeProvider)
{
$routeProvider.when("/",{
templateUrl: "rt.html",
controller: "ResolveCtrl",
resolve: {
data: ["$q","$timeout",function($q,$timeout)
{
var deferred = $q.defer();
$timeout(function()
{
deferred.resolve("my data value");
},2000);
return deferred.promise;
}]
}
});
}]);
rt.controller("ResolveCtrl",["$scope","data",function($scope,data)
{
console.log("data : " + data);
$scope.data = data;
}]);
rt.html
<span>{{data}}</span>
The problem is that you have ng-controller="ResolveCtrl" on your body tag in index.html when also in your $routeProvider you specify the same controller for rt.html. Take out the controller definition from your body tag and just let the $routeProvider take care of it. It works great after that.
According to the angularjs documentation for $routeprovider the resolve object is a map from key (dependency name) to factory function or name of an existing service. Try this instead:
var myFactory = function($q, $timeout) { ... };
myFactory.$inject = ['$q', '$timeout'];
$routeProvider.when("/",{
templateUrl: "rt.html",
controller: "ResolveCtrl",
resolve: {
data: myFactory
}
});
By adding data to the definition of the controller your telling angular that you expect to inject a service or factory here yet you don't have a data service or factory thus the error. To use the data variable you have all you need from the $scope.data line. So to fix this you need to remove the data injection from your controller call.
var rt = angular.module("ResolveTest",[]);
rt.config(["$routeProvider",function($routeProvider)
{
$routeProvider.when("/",{
templateUrl: "rt.html",
controller: "ResolveCtrl",
resolve: {
data: ["$q","$timeout",function($q,$timeout)
{
var deferred = $q.defer();
$timeout(function()
{
deferred.resolve("my data value");
},2000);
return deferred.promise;
}]
}
});
}]);
rt.controller("ResolveCtrl",["$scope", function($scope)
{
$scope.data = "";
}]);
If you want to have a data provider add a factory something like
rt.factory('data', ['$http', function($http){
return {
// Functions to get data here
}
}]);
Then in your controller call the appropriate function from this factory.
Also as the others have pointed out you don't need the controller both in your route and in an ng-controller (this will nest your controller in your controller if you inspect the scopes).
If you must use resolve you still need a factory as resolve will just point to the proper factory which needs to be declared separately.

Resources