I have this HTML:
<div class='container-fluid' ng-controller="TypeaheadCtrl">
<p></p>
<b>Selected User</b>
Enter a name: <input type="text" ng-model="selected" typeahead="user as (user.first + ' ' + user.last) for user in users | filter:$viewValue" />
</div>
this controller:
app.controller('TypeaheadCtrl', ['$scope', 'getUser',function($scope, getUser) {
$scope.selected = "";
getUser.success(function(data) {
$scope.users = data;
});
}]);
and this service:
app.factory('getUser', ['$http', function($http) {
return $http.get('https://myUrl?param=Foo')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
How can I pass an argument to the service to make the value of param in URL dynamic?
The easiest way with minimal change is to change your factory so that it returns a function
app.factory('getUser', ['$http', function($http) {
var httpReq = function(param){
return $http.get('https://myUrl?' + param + '=Foo')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}
return httpReq;
}]);
Now you can pass a value into your factory
app.controller('TypeaheadCtrl', ['$scope', 'getUser',function($scope, getUser) {
$scope.selected = "";
getUser('paramValue').success(function(data) {
$scope.users = data;
});
}]);
A factory creates an object and returns it as the publically available operations. So, you can create and return an object that wraps the HTTP call:
app.factory('getUser', ['$http', function($http) {
function myInternal(arg1) {
return $http.get('https://myUrl?param=' + arg1)
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}
return {
makeMyCall: function(arg1) {
return myInternal(arg1);
}
};
}]);
Then from the controller you can invoke the getUser.makeMyCall function passing in the argument.
BTW, if you are not adding anything to the promise chain that there is no need to handle the success and error function in the factory:
function myInternal(arg1) {
return $http.get('https://myUrl?param=' + arg1);
}
return {
makeMyCall: function(arg1) {
return myInternal(arg1);
}
};
app.controller('TypeaheadCtrl', ['$scope', 'getUser',function($scope, getUser) {
$scope.selected = "";
getUser('Foo').success(function(data) {
$scope.users = data;
});
}]);
app.factory('getUser', ['$http', function($http) {
return function(myParam) {
return $http.get('https://myUrl', {param:{param:myParam}});
};
}]);
Related
The URL I use to retreive a JSON for my app has a dynamic parameter (:id ). I'm not too sure how I can work with this, so that it passes the ID the user has chosen. Just need a bit of guidance.
app.factory('bookcategories', ['$http', function($http) {
return $http.get('http://52.41.65.211:8028/api/v1/categories/:id/books.json')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
Controller
app.controller('BookCategoryController', ['$scope', 'categories', '$routeParams', function($scope, categories, $routeParams) {
categories.success(function(data) {
$scope.detail = data.categories[$routeParams.bookId];
$scope.currentCategoryIndex = parseInt($routeParams.categoryId);
$scope.myCategoriesDetails = $scope.category;
});
}]);
app.js
...
.when('/categories/:categoryId', {
controller: 'BookCategoryController',
templateUrl: 'views/booksincategory.html'
})
...
HTML
<h3 class="title">{{book.title}}</h3>
You could achieve this with a little service like the following code example. A factory is a wrong choice here.
app.service('bookCategories', ['$http', function($http) {
this.get = function (id) {
return $http.get('http://52.41.65.211:8028/api/v1/categories/'+ id + '/books.json')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
};
}]);
And than use it like:
app.controller('MyCtrl', function(bookCategories) {
bookCategories.get(1).then(function (result) {
console.log(result);
});
});
I want to fetch particular category by id. I have populated dummyjson data using $http method.I am unable to do this. I have pass id from my services to controller but it returns null. Here i my code
service.js:
(function() {
angular.module('myApp')
.factory('registerService', function ($http) {
var category=[];
return {
getAll:function(){
return $http.get('json/dummyJson.json').then(function(response){
category=response.data;
return category;
});
},
getUser:function(category_id)
{
for(var i=0;i<category.length;i++){
console.log(category.length);
if(category[i].id === parseInt(category_id)){
return category[i];
}
}
return null;
}
}
});
})();
controller.js:
(function() {
angular.module('myApp').controller('registrationCtrl1', function ($scope, $stateParams, registerService) {
console.log('inside registerCtrl2');
$scope.categoryName=registerService.getUser($stateParams.category_id);
console.log($stateParams.category_id);
console.log($scope.categoryName);
});
})();
You are assuming that category will have value within getUser, but that won't happen. The only place where category is populated is getAll, but since you are not calling getAll, category is not populated. Chnage your method as below and it will work:
getUser: function(category_id) {
return $http.get('json/dummyJson.json').then(function(response){
category=response.data;
for(var i=0;i<category.length;i++) {
console.log(category.length);
if(category[i].id === parseInt(category_id)){
return category[i];
}
}
return null;
});
}
Since your method returns a promise now you need to handle the promise in a callback in your controller:
angular.module('myApp').controller('registrationCtrl1', function ($scope, $stateParams, registerService) {
console.log('inside registerCtrl2');
registerService.getUser($stateParams.category_id)
.then(function (response) {
$scope.categoryName= response;
console.log($stateParams.category_id);
console.log($scope.categoryName);
});
});
I have this in the controller
angular.module('myApp')
.controller('TaskController', function ($scope, TaskFactory) {
$scope.addTodo = function () {
$scope.todos.push({text : $scope.formTodoText});
$scope.formTodoText = '';
};
});
and this in the factory
angular.module('myApp')
.factory('TaskFactory', function ($q, $http) {
var sendTasks = function(params) {
var defer = $q.defer();
console.log(1, params);
$http.post('http://localhost:3000/task/save', params)
.success(function(data) {
console.log(2);
console.log('data', data);
})
.error(function(err) {
defer.reject(err);
});
return defer.promise;
}
return {
sendTask: function(taskData) {
console.log('taskData', taskData);
return sendTasks('/task/save', {
taskData : taskData
})
}
}
});
all I need is to know, how to send the data from the controller to the factory in order to do the POST to the specified route ?
You just need to call the function/method inside factory with the required params.
angular.module('myApp')
.controller('TaskController', function ($scope, TaskFactory) {
$scope.addTodo = function () {
$scope.todos.push({text : $scope.formTodoText});
TaskFactory.sendTask({data : $scope.formTodoText})
$scope.formTodoText = '';
};
});
You can follow Dan Wahlin blog post.
Controller:
angular.module('customersApp')
.controller('customersController', ['$scope', 'dataFactory', function ($scope, dataFactory) {
$scope.status;
dataFactory.updateCustomer(cust)
.success(function () {
$scope.status = 'Updated Customer! Refreshing customer list.';
})
.error(function (error) {
$scope.status = 'Unable to update customer: ' + error.message;
});
}
Factory:
angular.module('customersApp')
.factory('dataFactory', ['$http', function($http) {
var urlBase = '/api/customers';
dataFactory.updateCustomer = function (cust) {
return $http.put(urlBase + '/' + cust.ID, cust)
};
}
Hope that solve your problem.
You can call the function directly on the TaskFactory that you pass into the controller as a dependency.
I've cleaned up your code a bit and created a plunk for you here:
And here's the code:
Controller
(function(angular) {
// Initialise our app
angular.module('myApp', [])
.controller('TaskController', function($scope, TaskFactory) {
// Initialise our variables
$scope.todos = [];
$scope.formTodoText = '';
$scope.addTodo = function() {
// Add an object to our array with a 'text' property
$scope.todos.push({
text: $scope.formTodoText
});
// Clear the input
$scope.formTodoText = '';
// Call function to send all tasks to our endpoint
$scope.sendTodos = function(){
TaskFactory.sendTasks($scope.todos);
}
};
});
})(angular);
Factory
(function(angular) {
angular.module('myApp')
.factory('TaskFactory', function($q, $http) {
var sendTasks = function(params) {
var defer = $q.defer();
$http.post('http://localhost:3000/task/save', params)
.success(function(data) {
console.log('data: ' + data);
})
.error(function(err) {
defer.reject(err);
});
return defer.promise;
}
return {
sendTasks: sendTasks
}
});
})(angular);
I am using AngularJS to set up a table and filter its data by a search or category keywords. I
AngularJS
categorieFilter = angular.module("categorieFilter", [])
categorieFilter.controller("catFilter", ["$scope", "store", function($scope, store){
$scope.search = "";
$scope.products = [];
$scope.categories = [];
$scope.categories = store.getCategories();
$scope.products = store.getProducts();
$scope.filterProductsByCats = function(category){
$scope.search = category;
};
}])
categorieFilter.factory('store', function($http){
return {
getCategories: $http.get('api/categories').success(function (data) {
return data;
}),
getProducts : $http.get('api/products').success(function (data) {
return data;
}
};
});
The $http.get on its own is working, when I surf directly to my api I get the required data. Also when I do a alert(data) ifter the $hhtp.get in categories, I get the data I need... So this should be working but it doesn't. I get an error:
TypeError: store.getCategories is not a function
And I got no clue where this is coming from. Anybody a solution to this problem?
When using a factory you should do new function to return a constructor:
function myFactoryFunction() {
return function() {
var a = 2;
this.a2 = function() {
return a*2;
};
};
}
---------------------------------------------------------------------------------
// Injected in your controller
var myShinyNewObject = new myInjectedFactory();
$scope.four = myShinyNewObject.a2();
From this detailed post angular.service vs angular.factory
In your case
var storeFactory = new store();
storeFactory.getProducts();
Updated version, with TS code:
categorieFilter = angular.module("categorieFilter", [])
/**
Store factory
*/
categorieFilter.controller("catFilter", ["$scope", "store", function($scope, store){
$scope.search = "";
$scope.products = [];
$scope.categories = [];
store.getCategories().then(function(data){
$scope.categories = data;
})
store.getProducts().then(function(data){
$scope.products = data;
})
$scope.filterProductsByCats = function(category){
$scope.search = category;
};
}])
/**
Store factory
*/
categorieFilter.factory('store', function($http, $q){
function _getCategory (){
var deferred = $q.defer();
$http.get('api/categories').success(function (data) {
deferred.resolve(data);
})
return deferred.promise;
}
function _getProducts (){
var deferred = $q.defer();
$http.get('api/products').success(function (data) {
deferred.resolve(data);
}
return deferred.promise;
}
return {
getCategories: _getCategory,
getProducts : _getProducts
};
});
I usually create services using $resource. You could try this:
categorieFilter = angular.module("categorieFilter", []);
categorieFilter.factory('categoryStore', [
'$resource',
function($resource) {
return $resource('/api/categories/', {}, {
getCategories: { method: 'GET', params: {} },
});
}
]);
categorieFilter.factory('productsStore', [
'$resource',
function ($resource) {
return $resource('/api/products/', {}, {
getProducts: { method: 'GET', params: {} },
});
}
]);
categorieFilter.controller("catFilter", [
"$scope", "categoryStore", "productsStore", function ($scope, categoryStore, productsStore) {
$scope.search = "";
$scope.products = [];
$scope.categories = [];
$scope.categories = categoryStore.getCategories();
$scope.products = productsStore.getProducts();
$scope.filterProductsByCats = function(category) {
$scope.search = category;
};
}
]);
I usually write http factories passing a callback function parameter (I usually work with Node and I'm used to do this for long working functions). Taking your code it will looks something like this:
categorieFilter = angular.module("categorieFilter", [])
categorieFilter.controller("catFilter", ["$scope", "store", function($scope, store){
$scope.search = "";
$scope.products = [];
$scope.categories = [];
store.getCategories(function(err, data){
if(!err)
$scope.categories = data;
});
store.getProducts(function(err, data){
if(!err)
$scope.products = data;
});
$scope.filterProductsByCats = function(category){
$scope.search = category;
};
}])
categorieFilter.factory('store', function($http){
return {
getCategories: function(next){
$http.get('api/categories')
.success(function (data) {
next(null, data);
})
.error(function(headers, status){
next(status, null);
});
},
getProducts : function(next){
$http.get('api/products')
.success(function (data) {
next(null, data);
})
.error(function(headers, status){
next(status, null);
});
}
};
});
As you can see now factory takes a callback that will be called with error and data parameters, so error handling can be delegate or not to the controller. This is pretty useful for complex situations.
Here's a plunker that works using $q and defer explicitly with some random JSON.
var app = angular.module('categorieFilter', []);
app.factory('store', function($http, $q){
return {
getCategories: function() {
var deferred = $q.defer();
$http.get('https://api.myjson.com/bins/2gamd')
.success(deferred.resolve)
.error(deferred.resolve);
return deferred.promise;
}
}
})
.controller('catFilter', function($scope, store){
store.getCategories().then(function(data) {
$scope.categories = data.stories;// change data.stories to whatever your data is
});
});
I have an EmailAccountsController and I need to inject 'Hosting' and 'EmailAccount' services into it. Here is my code:
hostingsModule.controller('EmailAccountsCtrl', ['$scope', 'Hosting', 'EmailAccount', function ($scope, Hosting, EmailAccount) {
var hostingId = 1
$scope.hosting = Hosting.find(hostingId);
$scope.emailAccounts = EmailAccount.all(hostingId)
}]);
The error message is TypeError: Cannot call method 'all' of undefined
When I inject only one service into the same controller, everything works. Is there a way how to inject multiple services into one controller?
EDIT: I've tried to put all the relevant code into one file. It' looks like this:
hostingsModule.factory('Hosting', ['$http', function($http) {
var Hosting = function(data) {
angular.extend(this, data);
};
Hosting.all = function() {
return $http.get('<%= api_url %>/hostings.json').then(function(response) {
return response.data;
});
};
Hosting.find = function(id) {
return $http.get('<%= api_url %>/hostings/' + id + '.json').then(function(response) {
return response.data;
});
}
return Hosting;
}]);
hostingsModule.factory('EmailAccount', ['$http', function($http) {
var EmailAccount = function(data) {
angular.extend(this, data);
};
EmailAccount.all = function(hostingId) {
return $http.get('<%= api_url %>/hostings/' + hostingId + '/email-accounts.json').then(function(response) {
return response.data;
});
};
EmailAccount.find = function(id) {
return $http.get('<%= api_url %>/hostings/' + id + '.json').then(function(response) {
return response.data;
});
};
}]);
hostingsModule.controller('EmailAccountsCtrl', ['$scope', 'Hosting', 'EmailAccount', function($scope, Hosting, EmailAccount) {
var hostingId = 1;
$scope.hosting = Hosting.find(hostingId);
$scope.emailAccounts = EmailAccount.all(hostingId)
console.log($scope.hosting);
console.log($scope.emailAccounts);
}]);
Scope issue. You need to return EmailAccount since it is initialized inside the closure.
You need to add return EmailAccount; like what you did for Hosting.
Or try this code:
hostingsModule.factory('EmailAccount', ['$http', function ($http) {
var service = {
all: function (hostingId) {
return $http.get('<%= api_url %>/hostings/' + hostingId + '/email-accounts.json').then(function (response) {
return response.data;
});
},
find: function (id) {
return $http.get('<%= api_url %>/hostings/' + id + '.json').then(function (response) {
return response.data;
});
}
}
return service;
}]);