I am trying to put my service file in another js file but getting error
Unknown provider: $scopeProvider <- $scope <- getData
I have created 3 files which are :
app.js
app=angular.module('myApp', []); console.log("app.js loaded.");
service.js
app.service('getData',['$scope','$http',function($scope,$http){
this.getDataFrom = function(){
$http.get("http://www.w3schools.com/angular/customers.php")
.success(function(response) {$scope.names = response.records;});
}; }]); console.log("script loaded.");
index.html
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js"></script><script src="app.js"></script><script src="service.js"></script>
<script>app.controller('customersCtrl',['$scope','getData', function($scope, getData) {
alert(getData.getDataFrom());}]);</script>
Basically i am trying to put this code in different files.
You can't inject scope into services. It doesn't work like that, since they aren't associated with a scope.
Try rewriting your code as follows:
Remove the $scope reference in the service and the injection, and return the result of the $http.get, which is a promise
app.service('getData',['$http',function($http){
this.getDataFrom = function(){
return $http.get("http://www.w3schools.com/angular/customers.php")
}; }]); console.log("script loaded.");
Then, change your controller to use the service, and when the data is fetched, to update its scope:
<script>app.controller('customersCtrl',['$scope','getData','commentDataService', function($scope, getData,commentDataService) {
commentDataService.getComments().then(function(data) {
$scope.data = data;
console.log('the data is here!', data);
});
alert(commentDataService.getComments());
alert(getData.getDataFrom());}]);</script>
You cannot have a $scope injected in the service. So your service should look like below:
app.service('getData',['$http',function($http){
var names = null;
this.getDataFrom = function(){
$http.get("http://www.w3schools.com/angular/customers.php")
.success(function(response) {names = response.data.records; return names;});
}; }]);
I got it worked and to fetch data by help of this info "$scope is not associated with a scope"
finally obtained data with this code :
service.js
app.service('getData',['$http',function($http){
this.getDataFrom = function(){
return $http.get("http://www.w3schools.com/angular/customers.php")
.then(function(response) {
return response.data.records;
});
};}]);
index.html
app.controller('customersCtrl', ['$scope', 'getData', function($scope, getData) {
getData.getDataFrom().then(function(response){
alert(JSON.stringify(response));
$scope.names=response;
});
}]);
Related
This is more of a writing clean code/ optimizing existing code.
I am writing my Angular Services to fetch data from backend like this
angular.module('myApp').service('Auth', ['$http', '$q', 'Config', function($http, $q, Config) {
this.getUser = function() {
return $http.get(Config.apiurl + '/auth/user')
.then(function(response) {
return response.data;
}, function(error) {
return $q.reject(error.data);
});
};
}]);
Now in this, I am calling getUser function n number of times from the Database.
Now the question is, is it okay to call this service to get n times redundant data or I should it be saved somewhere say rootscope to be accessed later? Or storing in root scope would be bad practice and I should consider some other option or nothing at all?
Would like to get some views on Angular Community here.
Here is a sample example on how to use factory for sharing data across the application.
Lets create a factory which can be used in entire application across all controllers to store data and access them.
Advantages with factory is you can create objects in it and intialise them any where in the controllers or we can set the defult values by intialising them in the factory itself.
Factory
app.factory('SharedData',['$http','$rootScope',function($http,$rootScope){
var SharedData = {}; // create factory object...
SharedData.appName ='My App';
return SharedData;
}]);
Service
app.service('Auth', ['$http', '$q', 'SharedData', function($http, $q,SharedData) {
this.getUser = function() {
return $http.get('user.json')
.then(function(response) {
this.user = response.data;
SharedData.userData = this.user; // inject in the service and create a object in factory ob ject to store user data..
return response.data;
}, function(error) {
return $q.reject(error.data);
});
};
}]);
Controller
var app = angular.module("app", []);
app.controller("testController", ["$scope",'SharedData','Auth',
function($scope,SharedData,Auth) {
$scope.user ={};
// do a service call via service and check the shared data which is factory object ...
var user = Auth.getUser().then(function(res){
console.log(SharedData);
$scope.user = SharedData.userData;// assigning to scope.
});
}]);
In HTML
<body ng-app='app'>
<div class="media-list" ng-controller="testController">
<pre> {{user | json}}</pre>
</div>
</body>
Instead of rootScope just use a local variable of user in your service that can be accessed from anywhere in your code and so you doesn't have to call the api every time.
angular.module('metaiotAdmin').service('Auth', ['$http', '$q', 'Config', function($http, $q, Config) {
this.getUser = function() {
if(this.user){
return this.user;
}
else{
return $http.get(Config.apiurl + '/auth/user')
.then(function(response) {
this.user = response.data;
return response.data;
}, function(error) {
return $q.reject(error.data);
});
}
};
}]);
Hope it helps.
You don't have to, $http already caches your request for you, if the same request is applied in case you set the cache config option to true.
$http.get('/hello', { cache: true})
.then(onResponse)
or you can either set it for every request, by using either an interceptor or override the http instance in the $httpProvider, to apply the effect for every http request.
app.module('app.module')
factory('MyHttpInterceptor', function() {
return {
request : function(config) {
config.cache = true;
return config;
},
// rest of implementation of the interceptor
}
});
app.module('app.module')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('MyHttpInterceptor');
// ... rest of the configuration
}]);
Or :
app.module('app.module')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.cache = true;
// ...
}]);
see :
Angular doc for caching
I have an application where the frontend is build on AngularJS and backend is on laravel 5.1.
The user authentication is done by account controller via an API call:
myApp.controller('LoginCtrl', function($scope,$auth,$location){
$scope.authenticate = function(provider){
$auth.authenticate(provider)
.then(function() {
toastr.success('You have successfully signed in with ' + provider);
$location.path('/');
})
.catch(function(response) {
toastr.error(response.data.message);
});
};
});
angular.module('MyApp')
.factory('Account', function($http){
return {
getProfile: function(){
return $http.get('/api/me');
}
}
});
Once authenticated, the function getProfile is called to populate user data into the view by controller:
myApp.controller('UserApiCtrl', function($scope,$auth,Account){
$scope.user = {};
$scope.getProfile = function(){
Account.getProfile()
.then(function(response){
$scope.user = response.data;
})
.catch(function(response){
})
};
$scope.getProfile();
})
For the page to able render user data across all the different controller, should I assign user data with just $scope or assign it to $rootScope in app.js where user data will be available globally.
You could use $cookies ("Provides read/write access to browser's cookies.")
myApp.controller('UserApiCtrl', function($scope,$auth,Account,Auth,$cookies){
$scope.user = {};
$scope.getProfile = function(){
Account.getProfile()
.then(function(response){
$cookies.putObject('user', response.data);
})
.catch(function(response){
if(response.status === 401)
$cookies.remove('user');
})
};
$scope.getProfile();
})
Example service:
myApp.factory('Auth', ['$rootScope', '$cookies', function($rootScope, $cookies) {
$rootScope.user = $cookies.getObject('user') || {
id: '',
token: ''
};
...
I've used a controller on my body tag to provide access to more global stuff and then controllers in my individual views to do things that are more specific to the view.
<body ng-controller = "appController as app">
<div ui-view></div>
</body>
This just seems cleaner than using $rootScope to me.
I am new to angulerJS. i have defined a factory to get data from API but when i try to put the factory in a controller i got error.
That is the factory code.
(Function () {
var CategoriesFactory = function($http) {
var factory = {};
factory.getCategorys = function(account_id){
return $http.get('http://localhost:18678/api/Transaction?account_id=2');
};
factory.getTransaction = function(acc_id){
return $http.get('http://localhost:18678/api/Transaction?acc_id=2');
};
factory.getTransactionInCategory = function(category_id, from_date, to_date){
return.$http.get('http://localhost:18678/api/transaction?category='+category_id+'&account=2&from=2015-01- 01&to=2015-12-30');
};
return factory;
};
angular.module('AccApp').factory('CategoriesFactory', CategoriesFactory);
}());
here is the controller.
app.controller('CategoriesController',
function ($scope, $routeParams, $http, CategoriesFactory) {
})
and here is the error.
Unknown provider: CategoriesFactoryProvider <- CategoriesFactory
I guess you must have forgot to inject AccApp into your mai module where you have defined your app.
angular.module("app", ['AccApp']);
Please do something like this.
Hope this helps!
Why are you trying to write angular code in a wierd way ?
The goal of angular is the simplicity
var app = angular.module('AccApp',[]);
app.factory('CategoriesFactory',function($http){// you can cut and paste this factory into a seperate file if you wish
return{
getCategorys:function(account_id){
return $http.get('http://localhost:18678/api/Transaction?account_id=2');
},
getTransaction:function(acc_id){
return $http.get('http://localhost:18678/api/Transaction?acc_id=2');
},
getTransactionInCategory : function(category_id, from_date, to_date){
return.$http.get('http://localhost:18678/api/transaction?category='+category_id+'&account=2&from=2015-01- 01&to=2015-12-30');
};
}
});
Now you can Inject this factory into your controller simply:
app.controller('CategoriesController',function ($scope, $routeParams, $http, CategoriesFactory){
console.log(CategoriesFactory.getCategorys(getCategorys));
});
I've created $http and REST API interface in AnguarJS service as a function that gets injected into different controllers like this:
// Global service to share between states
.service("appSharedService", ['$http', function($http) {
// Method: Returns list of all cities.
this.restCitiesGet = function() {
return $http.get('http://example/nkhorasaniec7/api/v0/city');
};
// Method:
this.citiesGet = function() {
this.restCitiesGet().success(function (data) {
console.log(data);
return data;
})
};
}])
console.log(data); returns the right json output when I call citiesGet() .
// Main controller that prints list of cities.
.controller('CityList', ['$scope', function($scope, appSharedService) {
$scope.cities = appSharedService.citiesGet();
console.log($scope.cities);
}]);
This is my controller injecting my service. console.log($scope.cities); here returns undefined.
$scope.cities value doesn't get changed after route calls this controller.
Is there something wrong with my setup?
Something interesting is that after I change route and come back to this controller again, this time $scope.cities have my REST data and everything's fine.
I think there's something wrong with timing or asynchronous functionality problem here that I'm not aware of.
EDIT:
I could have had $http in my controller and this works all well:
.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
$http.get('http://localhost/nkhorasaniec7/api/v0/city').success(function (data) {
$scope.cities = data;
});
}]);
But I want to implement helper functions for this.
I would say that the common approach would be to return the promise directly to the controller, much like you have mentioned above by directly using the http request.
// Global service to share between states
.service("appSharedService", ['$http', function($http) {
// Method: Returning the promise
this.citiesGet = function() {
return $http.get('http://example/nkhorasaniec7/api/v0/city');
};
}])
Controller:
.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
appSharedService.citiesGet().success(function (data) {
$scope.cities = data;
});
}]);
I think you are right about the timing issue. From what I understand, you are getting a promise, that at the moment you do console.log($scope.cities) is not yet resolved.
If you use $scope.cities inside your page, you should see the results as soon as they are loaded. Another option would be to use the promise then function if you really want to log.
$scope.cities = appSharedService.citiesGet().then(function(data) {
console.log(data);
return data;
};
Answering my own question:
I'm trying to make this happen in my a controller defined in my view using ng-controller, not a controller linked to a router (otherwise you could use resolve property like this Delaying AngularJS route change until model loaded to prevent flicker).
And I want to use REST using $http as a factory/service helper function for a cleaner code.
// Global service to share between states
.service("appSharedService", ['$http', '$q', function($http, $q) {
this.citiesGet = function() {
var deferred = $q.defer();
$http({method: 'GET', url: 'http://localhost/nkhorasaniec7/api/v0/city'}).success(function(data) {
deferred.resolve(data);
}).error(function(data, status) {
deferred.reject(data);
});
return deferred.promise;
};
}])
I used angular $q promise here.
// Our main controller that prints list of cities.
.controller('CityList', ['$scope', 'appSharedService', function($scope, appSharedService) {
var promise = appSharedService.citiesGet();
promise.then(
function(data){$scope.cities = data;}
,function(reason){alert('Failed: ' + reason);}
);
}])
And used then function to use that promise.
And now it always updates $scope.cities in any situation that template loads (not just in ng-view)
You can use $q service
.service("appSharedService", ['$http', '$q', function($http, $q) {
// Method: Returns list of all cities.
this.restCitiesGet = function() {
var deffered = $q.defer();
$http.get('http://example/nkhorasaniec7/api/v0/city').then(
//success
function(response){
deffered.resolve(response.data);},
//error
deffered.reject();
);
return deffered
};
and after that you can use promise in you controller
.controller('CityList', ['$scope', function($scope, appSharedService) {
$scope.cities = []
appSharedService.citiesGet().then(
//success
function(result){
angular.copy(result, $scope.cities)
console.log($scope.cities);
},
//error
function(){
console.log("load error");
});
}]);
I am currently working myself through tutorials and books teaching AngularJS.
I want to write a simple app, that loads some user data from a json file and displays it.
Now this is the relevant part of a JavaScript file, which does what I want:
Here is my Code :
angular.module('myModule', [])
.controller('myCtrl', function($scope, $http) {
$http.get('../mockdata/users_js.json').success(function(data, status, headers, config) {
$scope.users = data;
});
});
Now if I try to create a separate module for importing my data, I fail:
angular.module('myModule', [])
.controller('myCtrl', function($scope, Users) {
$scope.users = Users.query();
})
.factory('Users', function($http) {
var users = {};
users.query = function() {
// In real apps, we'd pull this data from the server...
$http.get('../mockdata/users_js.json').success(function(data, status, headers, config) {
this.data = data;
});
return this.data;
};
return users;
});
What am I doing wrong ?
And How can i fix this ?
In users.query() you kick off an asynchronous HTTP request, and then before it has a chance to finish return this.data which is undefined.
You could take a look at $resource, it returns a promise that you can assign to a $scope variable immediately. It will apply the right value when the request completes.
.factory('Users', function($resource) {
var users = {};
users.query = function() {
return $resource('../mockdata/users_js.json').get();
};
return users;
});
If you want to know how to do this with $http:
angular.module('myModule', [])
.controller('myCtrl', function($scope, Users) {
Users.then(function(data){
$scope.users = data;
});
})
.factory('Users', function($http) {
var Users = {};
Users = $http.get('../mockdata/users_js.json').then(function (response) {
return response.data;
});
return Users;
});
Here's a live Plnkr.