I am having fits trying to get my factory/service function to work from my controller. I have seen many threads on this, and have tried various solutions, to no avail, so it leads me to believe I'm missing something simple. Here's the code (error message provided below):
'use strict';
var smacApp = angular.module('smacApp', ['ngRoute']);
smacApp.config(function($routeProvider) {
$routeProvider
.when("/login", {
templateUrl: "templates/login.html",
controller: "LoginController"
})
});
smacApp.factory('AuthenticationService', function() {
var users = ["Bob", "Joe"];
return {
all: function() {
return users;
},
first: function() {
return users[0];
}
};
});
smacApp.controller('LoginController', function($scope, AuthenticationService) {
$scope.users = AuthenticationService.all();
console.log($scope.users);
});
smacApp.run.$inject = ['$rootScope', '$routeParams'];
smacApp.run(function($rootScope, $routeParams) {
});
The error message I am receiving is:
angular.js:9778TypeError: AuthenticationService.all is not a function
at new <anonymous> (http://localhost/smac3/app.js:61:39)
at d (http://localhost/smac3/lib/angular/js/angular.min.js:34:265)
at Object.instantiate (http://localhost/smac3/lib/angular/js/angular.min.js:34:394)
at http://localhost/smac3/lib/angular/js/angular.min.js:66:112
at link (http://localhost/smac3/lib/angular/js/angular- route.js:913:26)
at J (http://localhost/smac3/lib/angular/js/angular.min.js:53:345)
at f (http://localhost/smac3/lib/angular/js/angular.min.js:46:399)
at http://localhost/smac3/lib/angular/js/angular.min.js:46:67
at http://localhost/smac3/lib/angular/js/angular.min.js:47:303
at u (http://localhost/smac3/lib/angular/js/angular.min.js:51:28) <div ng-view="" id="container" class="ng-scope">
Any help is greatly appreciated!
Maybe the syntax for your factory is correct, but I've always written them more like this:
smacApp.factory('AuthenticationService', function() {
var factory = this
factory.users = ["Bob", "Joe"];
factory.all = function() {
return factory.users;
};
factory.first = function() {
return factory.users[0]
}
return factory;
}
or
smacApp.factory('AuthenticationService', function() {
var factory = this
factory = {
users: ["Bob", "Joe"],
all: function() { return factory.users },
first: function() { return factory.users[0] }
}
return factory;
}
Related
I am calling a function in a factory and trying to inject in the controller. But I am getting an error saying, unknown provider. Please let me know where I am going wrong.
app.factory('pdfdwn', function($scope) {
return{
download:function(){
html2canvas(document.getElementById('export'), {
onrendered: function (canvas) {
var data = canvas.toDataURL();
var docDefinition = {
content: [{
image: data,
width: 500,
}]
};
pdfMake.createPdf(docDefinition).download("Table.pdf");
}
});
return download();
}
}
});
controller:
app.controller('myctrl', function($scope,pdfdwn){
$scope.pdf = function() {
var pdd = pdfdwn.download();
};
});
1.remove $scope from factory method because you cannot inject inside.
2.Remove the return download(); from the factory, because u are already returning the download.
Inside the controller:
app.controller('myctrl', function($scope,pdfdwn){
$scope.pdf = function() {
pdfdwn.download();
};
});
I am writing a Factory/Service for the first time and trying to get an image from a factory into controller but getting undefined when in the factory function for some reason.
Here is the fiddle
https://jsfiddle.net/vijay_vadlamani/2qL2Lh5r/1/
Html:-
JS:-
angular.module('myApp').factory('imageFactory', function() {
return function contentImage($scope) {
$scope.getImage = function(content) {
return getContentImage(content);
};
};
});
angular.module(myApp).controller('getImageCtrl', ['$scope', 'imageFactory', function($scope, imageFactory) {
$scope.getListImage = function(content) {
return imageFactory.getImage(content);
};
}]);
Try to declare service like this:
var app = angular.module('myApp',[]);
app.factory('imageFactory', function()
{
var service =
{
getImage: function(content)
{
return getContentImage(content);
}
};
return service
});
and use it like this:
app.controller('getImageCtrl', ['$scope','imageFactory',function($scope, imageFactory)
{
$scope.getListImage = function(content)
{
return imageFactory.getImage(content);
};
}]);
Here's demo
i have 2 controllers who are not in the same scope or have a parent child relation.
So i want to call from controlleB a function in ControllerA. In my case its a listContoller with an addItem function and i want to call this function from a addItemController somewhere else on the page after clicking submit. i know this should work with a service, but i dont know how.
app.controller("listCtrl", ["$scope", "listSvc", function ($scope, listSvc){
$scope.list.data = listSvc.load("category");
$scope.addItem = function(newitem) {
$scope.list.data.unshift(newitem);
...
}
}]);
app.controller("addItemCrtl", ["$scope", "listSvc", function ($scope, listSvc){
$scope.addItem = function() {
listSvc.addItem($scope.newItem);
}
}]);
app.service('listSvc', function() {
return{
load: function(section){
...
},
addItem: function(item){
addItem(item); <<-- call function in listController
}
}
});
UPDATE
k is this better? i put the list.data inside my service and i watch from my controller if the list change and put it on the scope from my controller that ng-repeat can do his work... is this appraoch better? or have someone better tips for me how i should do this...
app.service('listSvc', ['$http', function($http) {
var list = {};
return {
list:{
get: function () {
return list.data;
},
set: function (data) {
list.data = data;
}
},
addItem: function(item){
var response = $http.post("/api/album/"+$scope.list.section, item);
response.success(function(){
list.data.unshift(item);
console.log("yeah success added item");
}).error(function(){
console.log("buuuh something went wrong");
});
return response;
},
load: function(section){
var response = $http.get("/api/album/"+section);
response.success(function(data){
list.set(data);
list.section = section;
console.log("yeah success loaded list");
}).error(function(){
console.log("buuuh something went wrong");
});
return response;
}
};
}]);
and in my controllers i do this
app.controller("listCrtl", ["$scope", "listSvc", function ($scope, listSvc){
listSvc.load("category");
...
$scope.$watch('listSvc.list.get()', function(data) {
$scope.list.data = data;
});
...
}]);
app.controller("addItemCrtl", ["$scope", "listSvc", function ($scope, listSvc){
...
$scope.addItem = function() {
listSvc.addItem($scope.newItem);
}
...
}]);
gregor ;)
I just solved this myself! Perhaps this may help:
The function inside of my Controller:
var timeoutMsg = function() {
vm.$parent.notification = false;
};
The function inside my Service (I had to pass in $timeout as well as the name of the function from my Controller, now it works):
// original broken code:
// this.modalSend = function(vm) {
// fixed:
this.modalSend = function(vm, $timeout, timeoutMsg) {
vm.$parent.sendTransaction = function() {
// Show notification
vm.$parent.message = 'Transaction sent!';
vm.$parent.notification = true;
$timeout(timeoutMsg, 4000);
// original broken code:
// $timeout(timeoutMsg(), 4000);
};
}
var vm = $scope
How would i change the following code form $http.get to a $resource
//The created resource (not using it for now)
hq.factory('LogsOfUser', function ($resource) {
return $resource('/HQ/Graph/GetLoggedinTimes?userName=:userName', {
userName: '#userName'
})
});
//The Controller
var ModalViewLogActionsCtrl = function ($scope, $http, $log, LogsOfUser, $modal) {
$scope.openLogs = function (userName) {
$http.get("/HQ/Graph/GetLoggedinTimes?userName=" + userName).success(function (data) {
var modalInstance = $modal.open({
templateUrl: 'LogView.html',
controller: 'ModalLogViewInstance',
resolve: {
items: function () {
//$scope.items = data;
$log.log(data);
$scope.items = data;
return $scope.items; //return data;
},
userName: function () {
return userName;
}
}
});
}).error(function () {
alert("eror :(");
});;
};
};
You've already done most of the work. All you need now is to call the service inside the controller :
LogsOfUser.query({
userName: userName
}, function success(data) {
//your code
}, function err() {
alert("Error")
});
Use query to get an array of data, and get to get a single document.
Here is a example how to call a resource from a controller:
app.controller('MainCtrl', function($scope, $resource) {
var userName = 'Bob';
var LoggedinTimes = $resource('/HQ/Graph/GetLoggedinTimes');
var data = LoggedinTimes.get({userName : userName}, function () {
console.log(data);
});
});
First, you would want to move data-related logic behind a Service, so your controller doesn't know about server-specifics. More importantly, your Service becomes reusable as all services in AngularJS are global singletons. your controller stays small, as it should be.
Next, your controller would call getLoggedIntimes() and work with the outcome as if the data is there. The result of a $resource.get() or similar functions return an empty object or array which fills itself when the REST call returns with data.
In your service you would do the actual $resource.get().
something along the lines of the following pseudo code:
//The Controller
var ModalViewLogActionsCtrl = function ($scope, MyService, $log, LogsOfUser, $modal) {
$scope.openLogs = function (userName) {
var items = MyService.getLoggedInTimes(userName);
var modalInstance = $modal.open({
templateUrl: 'LogView.html',
controller: 'ModalLogViewInstance',
resolve: {
items: function () {
$scope.items = items;
return $scope.items;
},
userName: function () {
return userName;
}
}
});
};
};
app.service('MyService', function ($resource) {
var loggedInResource = $resource('/HQ/Graph/GetLoggedinTimes/:userName');
return {
getLoggedInTimes: functio(username) {
return loggedInResource.get({
username: username
});
}
};
});
I'm trying to learn angular by extending a sample app to use firebase. I want to modify the service object being used to call firebase instead of my webserver. I tried to inject $scope into my service object and am now getting an error. What am I doing wrong?
var app = angular.module("myApp", ['ngRoute', 'firebase']);
app.config(function($routeProvider) {
$routeProvider.when('/', {
templateUrl: "templates/home.html",
controller: "HomeController"
})
.when('/settings', {
templateUrl: 'templates/settings.html',
controller: 'SettingsController'
})
.otherwise({ redirectTo: '/' });
});
//services must return objects
app.service('mailService', ['$scope', '$http', '$firebase', function($scope, $http, $firebase) {
var mailRef = new Firebase("https://ng-book-email-client.firebaseio.com/mail");
//var getMail = function() {
// return $http({
// method: 'GET',
// url: '/api/mail'
// });
//};
$scope.email = $firebase(mailRef);
var sendEmail = function(mail) {
//var d = $q.defer();
//$http({
// method: 'POST',
// data: 'mail',
// url: '/api/send'
//}).success(function(data, status, headers) {
// d.resolve(data);
//}).error(function(data, status, headers) {
// d.reject(data);
//});
//return d.promise;
return $scope.email.$add(mail);
};
return {
//getMail: getMail,
sendEmail: sendEmail
};
}]);
app.controller('HomeController', function($scope) {
$scope.selectedMail;
$scope.setSelectedMail = function(mail) {
$scope.selectedMail = mail;
};
$scope.isSelected = function(mail) {
if($scope.selectedMail) {
return $scope.selectedMail === mail;
}
};
});
// directive that builds the email listing
app.directive('emailListing', function() {
var url = "http://www.gravatar.com/avatar/";
return {
restrict: 'EA', // E- element A- attribute C- class M- comment
replace: false, // whether angular should replace the element or append
scope: { // may be true/false or hash. if a hash we create an 'isolate' scope
email: '=', // accept an object as parameter
action: '&', // accept a function as a parameter
isSelected: '&',
shouldUseGravatar: '#', // accept a string as a parameter
gravatarSize: '#'
},
transclude: false,
templateUrl: '/templates/emailListing.html',
controller: ['$scope', '$element', '$attrs', '$transclude',
function($scope, $element, $attrs, $transclude) {
$scope.handleClick = function() {
$scope.action({selectedMail: $scope.email});
};
}
],
// if you had a compile section here, link: wont run
link: function(scope, iElement, iAttrs, controller) {
var size = iAttrs.gravatarSize || 80;
scope.$watch('gravatarImage', function() {
var hash = md5(scope.email.from[0]);
scope.gravatarImage = url + hash + '?s=' + size;
});
iElement.bind('click', function() {
iElement.parent().children().removeClass('selected');
iElement.addClass('selected');
});
}
};
});
app.controller('MailListingController', ['$scope', 'mailService', function($scope, mailService) {
$scope.email = [];
$scope.nYearsAgo = 10;
//mailService.getMail()
//.success(function(data, status, headers) {
// $scope.email = data.all;
//})
//.error(function(data, status, headers) {
//});
$scope.searchPastNYears = function(email) {
var emailSentAtDate = new Date(email.sent_at),
nYearsAgoDate = new Date();
nYearsAgoDate.setFullYear(nYearsAgoDate.getFullYear() - $scope.nYearsAgo);
return emailSentAtDate > nYearsAgoDate;
};
}]);
app.controller('ContentController', ['$scope', 'mailService', '$rootScope', function($scope, mailService, $rootScope) {
$scope.showingReply = false;
$scope.reply = {};
$scope.toggleReplyForm = function() {
$scope.reply = {}; //reset variable
$scope.showingReply = !$scope.showingReply;
console.log($scope.selectedMail.from);
$scope.reply.to = $scope.selectedMail.from.join(", ");
$scope.reply.body = "\n\n -----------------\n\n" + $scope.selectedMail.body;
};
$scope.sendReply = function() {
$scope.showingReply = false;
$rootScope.loading = true;
mailService.sendEmail($scope.reply)
.then(function(status) {
$rootScope.loading = false;
}, function(err) {
$rootScope.loading = false;
});
}
$scope.$watch('selectedMail', function(evt) {
$scope.showingReply = false;
$scope.reply = {};
});
}]);
app.controller('SettingsController', function($scope) {
$scope.settings = {
name: 'harry',
email: "me#me.com"
};
$scope.updateSettings = function() {
console.log("updateSettings clicked")
};
});
error
Error: [$injector:unpr] http://errors.angularjs.org/1.2.14/$injector/unpr?p0=<div ng-view="" class="ng-scope">copeProvider%20%3C-%20%24scope%20%3C-%20mailService
at Error (native)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:6:450
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:32:125
at Object.c [as get] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:30:200)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:32:193
at c (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:30:200)
at d (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:30:417)
at Object.instantiate (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:31:80)
at Object.<anonymous> (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:31:343)
at Object.d [as invoke] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:30:452) angular.js:9509
The answer is that the $scope shouldn't be injected into services or factories. They're supposed to be reusable and sharable. The right way to achieve the effect is to create a $firebase object inside the service and return a function that can take any variable and scope and $bind them to the firebase object.
Inspiration comes from http://plnkr.co/edit/Uf2fB0?p=info
var app = angular.module("myApp", ['ngRoute', 'firebase']);
//services must return objects
app.service('mailService', ['$http', '$firebase', function($http, $firebase) {
var emailRef = new Firebase("https://ng-book-email-client.firebaseio.com/all");
var emails = $firebase(emailRef);
// uses firebase to bind $scope.email to the firebase mail object
var setEmails = function(scope, localScopeVarName) {
return emails.$bind(scope, localScopeVarName);
};
var sendEmail = function(mail) {
return $scope.email.$add(mail);
};
return {
setEmails: setEmails,
sendEmail: sendEmail
};
}]);
app.controller('MailListingController', ['$scope', 'mailService', function($scope, mailService) {
mailService.setEmails($scope, 'emails');
$scope.nYearsAgo = 10;
$scope.searchPastNYears = function(email) {
var emailSentAtDate = new Date(email.sent_at),
nYearsAgoDate = new Date();
nYearsAgoDate.setFullYear(nYearsAgoDate.getFullYear() - $scope.nYearsAgo);
return emailSentAtDate > nYearsAgoDate;
};
}]);
I think you should not inject $scope to a service, Service can be a common one for implementation /support for several controllers and service shouldn't know about a $scope (controller). But controllers users services to make their work done by passing parameters to a service method.
mailService.sendEmail($scope.reply)
Not sure why you need $scope inside a service here,
$scope.email = $firebase(mailRef);
are you expecting something like this,
this.email = $firebase(mailRef);