Why my factory below keep throwing an error when the $scope, $route, $http are present?
app.factory("factoryContacts",function($scope,$route,$http){
return {
getContacts: function(){
return $http({
method: 'GET',
url:'php/listContacts.php'
}).then(function(response) {
$scope.contacts = response.data;
});
}
};
});
can't I pass $scope, $route, $http into a factory?
I tested with this basic one and it gives me the same error,
app.provider('helloWorld', function($scope) { // note $scope is present
// In the provider function, you cannot inject any
// service or factory. This can only be done at the
// "$get" method.
this.name = 'Default';
this.$get = function() {
var name = this.name;
return {
sayHello: function() {
return "Hello, " + name + "! From Provider!!"
}
}
};
this.setName = function(name) {
this.name = name;
};
});
What should I do?
the error,
Error: [$injector:unpr] http://errors.angularjs.org/1.2.6/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope%20%3C-%20factoryContacts ... <ng-view class="ng-scope">
can't I pass $scope, $route, $http into a factory?
why not $scope
You can't inject $scope into service/factory, its singleton and has local scope. But you can use $rootScope
To pass $route and $http use injection and write like:
app.factory("factoryContacts",['$route','$http', function($route,$http){
return {
getContacts: function(){
return $http({
method: 'GET',
url:'php/listContacts.php'
}).then(function(response) {
//....
});
}
};
}]);
Related
Looking at this Plunker from an answer on SO
Plunker example
Learning angular and in the controller there is a param cityName, I am not sure how that works.
What I am trying to do is that I have a myController.js file
var app = angular.module("sampleApp");
app.controller('TypeaheadCtrl',['$scope','search', function ($scope, search) {
$scope.displayed=[];
search.getResult(searchQuery)
.then(function (data) {
$scope.displayed = (data.records);
});
}]);
myService.js
angular.module('sampleApp').factory('search', ['$q', '$http', function ($q, $http) {
var sdo = {
getResult: function (searchQuery) {
var promise = $http({
method: 'GET',
url: 'http://somewhere.com'
params: {
q: "a"
}
});
promise.success(function (data, status, headers, conf) {
return data;
});
return promise;
}
}
return sdo;
}]);
I want to be able to call the service after the third character is typed in the typeahead box and pass the characters to the service
You should use typeahead-min-length="3" option on typeahead input element.
HTML
<input type="text" ng-model="result"
typeahead="suggestion for suggestion in getSuggestion($viewValue)"
typeahead-min-length="3"/>
Then have function inside controller which will again return a promise.
$scope.getSuggestion = function (searchQuery){
return search.getResult(searchQuery)
.then(function (data) {
return data.records;
});
};
Since you have used .success the data will get return getResult function.
Use .then to chain promise so that you can return a data from the success callback.
Service
angular.module('sampleApp').factory('search', ['$q', '$http', function($q, $http) {
var sdo = {
getResult: function(searchQuery) {
var promise = $http({
method: 'GET',
url: 'http://somewhere.com'
params: {
q: searchQuery //<-- pass parameter here
}
});
promise.then(function(response) {
//you could format data here and returned formatted result
//or you could also do some sort of validation or filtering on data
return response.data;
});
return promise;
}
}
return sdo;
}]);
change your service like this
app.factory('search', ['$q', '$http', function($q, $http) {
var sdo = {};
sdo.getResult = function(query) {
var deferred = $q.defer();
var url = "http://someurlpath/api/" + query;
$http.get(url)
.success(function(data) {
deferred.resolve(data.data);
}).error(function(msg, code) {
deferred.reject(msg);
});
return deferred.promise;
};
return sdo;
}]);
Hello I have this service :
angular.module('angularProtoApp')
.factory('ModelService',['$q', '$http', function ($q, $http) {
var folder = 'assets/';
var extension = 'Model.json';
return {
getModelFromJson : function (pageCode) {
return $http({
method : 'GET',
url : folder + pageCode + extension,
headers: {'Content-Type': 'application/json'}
}).then(
function (response) {
return response.data;
}
);
}
};
}]);
And I have this controller :
angular.module('angularProtoApp')
.controller('MainCtrl', ['$scope', '$location', 'ModelService', function ($scope, $location, ModelService) {
$scope.model = '';
ModelService.getModelFromJson('Ffco').then(
function (data) {
$scope.model = data;
if ($scope.model.isSeleniumTestRunning) {
$scope.slnPageCodeClass = 'sln' + $scope.model.pageCode;
}
$location.path('/' + $scope.model.pageCode);
},
function (error){
console.log(error);
}
);
}]);
But I don't know how to correctly test the controller.
I began to do something like this, but I don't think this is enough.
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('angularProtoApp'));
var MainCtrl,
scope,
ModelServiceMock;
beforeEach(inject(function ($controller, $rootScope, _ModelService_) {
scope = $rootScope.$new();
ModelServiceMock = _ModelService_;
spyOn(ModelServiceMock, 'getModelFromJson').and.callThrough();
$controller('MainCtrl', {
$scope: scope,
ModelService : ModelServiceMock
});
}));
it('should call getModelFromJson method on ModelService', function () {
scope.$digest();
expect(ModelServiceMock.getModelFromJson).toHaveBeenCalled();
});
});
I'm not sure I test the service correctly, I did not succeed in testing the scope variables of the controller.
Does somebody know how to test it properly ?
Thanks.
I am trying to create a service to get json and pass it to me homeCtrl I can get the data but when a pass it to my homeCtrl it always returns undefined. Im stuck.
My Service:
var myService = angular.module("xo").factory("myService", ['$http', function($http){
return{
getResponders: (function(response){
$http.get('myUrl').then(function(response){
console.log("coming from servicejs", response.data);
});
})()
};
return myService;
}
]);
My Home Controller:
var homeCtrl = angular.module("xo").controller("homeCtrl", ["$rootScope", "$scope", "$http", "myService",
function ($rootScope, $scope, $http, myService) {
$scope.goData = function(){
$scope.gotData = myService.getResponders;
};
console.log("my service is running", $scope.goData, myService);
}]);
You should return promise from getResponders function, & when it gets resolved it should return response.data from that function.
Factory
var myService = angular.module("xo").factory("myService", ['$http', function($http) {
return {
getResponders: function() {
return $http.get('myUrl')
.then(function(response) {
console.log("coming from servicejs", response.data);
//return data when promise resolved
//that would help you to continue promise chain.
return response.data;
});
}
};
}]);
Also inside your controller you should call the factory function and use .then function to get call it when the getResponders service function resolves the $http.get call and assign the data to $scope.gotData
Code
$scope.goData = function(){
myService.getResponders.then(function(data){
$scope.gotData = data;
});
};
This is an example how I did for my project, it work fine for me
var biblionum = angular.module('biblioApp', []);//your app
biblionum.service('CategorieService', function($http) {
this.getAll = function() {
return $http({
method: 'GET',
url: 'ouvrage?action=getcategorie',
// pass in data as strings
headers: {'Content-Type': 'application/x-www-form-urlencoded'} // set the headers so angular passing info as form data (not request payload)
})
.then(function(data) {
return data;
})
}
});
biblionum.controller('libraryController', function($scope,CategorieService) {
var cat = CategorieService.getAll();
cat.then(function(data) {
$scope.categories = data.data;//don't forget "this" in the service
})
});
I have this simple factory that fetches a data file and saves it to service.data:
angular.module("tiki").factory("editTiki", ["$http", function($http){
var service = {}
service.data = {}
service.getTikis = function(){
$http.get("data/tikis.json").success(function(tikis){
console.log(tikis)
service.data = tikis
})
}
return service
}])
Then, in the controller i assign it to the $scope. This is first empty ofcourse but when the $http resolves it should update my factory and in turn update the service.data object with the returned data.
angular.module('tiki').controller("tiki.controller.settings.edit", ["$scope", "editTiki", function($scope, editTiki){
//should return the tikis
$scope.preview = editTiki.data
editTiki.getTikis()
$scope.showEditTikiObject = function(){
console.log($scope.preview)
}
}])
However, i have this function to test the contents of the data and it returns an empty object. Why is that?
You are reassigning service.data = tikis after assigning it to $scope.preview.
You should do probably something with the promise.
angular.module("tiki").factory("editTiki", ["$http", function($http){
var service = {};
service.data = {};
service.getTikis = function(){
return $http.get("data/tikis.json").success(function(tikis){
console.log(tikis)
service.data = tikis;
return service.data;
})
};
return service;
}]);
angular.module('tiki').controller("tiki.controller.settings.edit", ["$scope", "editTiki", function($scope, editTiki){
editTiki.getTikis()
.then(function () {
$scope.preview = editTiki.data;
});
$scope.showEditTikiObject = function(){
console.log($scope.preview);
};
}])
I ended up with the following. So here I am not injecting the scope object into the factory, but setting the $scope in the controller itself using the concept of promise returned by $http service. Hope this helps.
(function () {
getDataFactory = function ($http)
{
return {
callWebApi: function (reqData)
{
var dataTemp = {
Page: 1, Take: 10,
PropName: 'Id', SortOrder: 'Asc'
};
return $http({
method: 'GET',
url: '/api/PatientCategoryApi/PatCat',
params: dataTemp, // Parameters to pass to external service
headers: { 'Content-Type': 'application/Json' }
})
}
}
}
patientCategoryController = function ($scope, getDataFactory) {
alert('Hare');
var promise = getDataFactory.callWebApi('someDataToPass');
promise.then(
function successCallback(response) {
alert(JSON.stringify(response.data));
// Set this response data to scope to use it in UI
$scope.gridOptions.data = response.data.Collection;
}, function errorCallback(response) {
alert('Some problem while fetching data!!');
});
}
patientCategoryController.$inject = ['$scope', 'getDataFactory'];
getDataFactory.$inject = ['$http'];
angular.module('demoApp', []);
angular.module('demoApp').controller('patientCategoryController', patientCategoryController);
angular.module('demoApp').factory('getDataFactory', getDataFactory);
}());
In my angular module I wrote a generic http handler for all my ajax requests.'
I was expecting that I could use the service across controllers, but my problem is the promise seems to be global.
Once ControllerOne uses the mapi_loader service, when I load AnotherController (by ng-click="go('/$route_to_load_another_controller')"), AnotherController is loaded a promise that has already returned from ControllerOne even though the URL they fetch are totally different.
So I guess my question is how do I write a service I could use across controllers? Do I really need to write a separate service for each controller where their only difference in code is the URL passed for $http.jsonp?
angular.module('myAppControllers',[])
.service('mapi_loader', ['$http', function($http) {
var promise;
var myService = {
fetch: function(url) {
if ( !promise ) {
promise = $http.jsonp(url)
.then(function (response) {
return response.data.nodes;
});
}
return promise;
}
};
return myService;
}])
.controller('ControllerOne', ['$scope', 'mapi_loader', function ($scope, mapi_loader) {
mapi_loader
.fetch("http://host.com/mapi_data_for_controller_one?callback=JSON_CALLBACK")
.then(function(data) {
$scope.useme = data;
});
}])
.controller('AnotherController', ['$scope', 'mapi_loader', function ($scope, mapi_loader) {
mapi_loader
.fetch("http://host.com/mapi_data_for_another_controller?callback=JSON_CALLBACK")
.then(function(data) {
$scope.useme = data;
});
}])
;
try something like this
angular.module('myAppControllers',[])
.service('mapi_loader', function($http) {
var alreadyLoading = {};
return {
fetch: function(url) {
if ( url in alreadyLoading ) {
return alreadyLoading[url];
}
return alreadyLoading[url] = $http.jsonp(url)
.then(function (response) {
delete alreadyLoading[url];
return response.data.nodes;
});
}
};
})
.controller('ControllerOne', function ($scope, mapi_loader) {
...
})
.controller('AnotherController', function ($scope, mapi_loader) {
...
});