I'm listing users with:
/api/users/
I'd like to list users who are admins by calling:
/api/users/admins
As trivial as it may seem, I can't find a way to do this.
I do not know which programming language you are using, but I'm going to give you an example using PHP Laravel, and AngularJS.
API
Route::get('/api/users', function ()
{
$users = App\User::all();
return $users;
});
Route::get('/api/users/admin', function ()
{
$users = App\User::where('admin', true)->get();
return $users;
});
FRONT
angular.module('app', [])
.service('api', ['$http', function ($http) {
function getUsers() {
return $http.get('/api/users');
}
function getAdminUsers() {
return $http.get('/api/users/admin');
}
this.getUsers = getUsers;
this.getAdminUsers = getAdminUsers;
}])
.controller('UserCtrl', ['$scope', 'api', function ($scope, api) {
$scope.users = [];
$scope.adminUsers = [];
api.getUsers()
.then(function success(response) {
$scope.users = response.data;
}, function error(response) {
});
api.getAdminUsers()
.then(function success(response) {
$scope.adminUsers = response.data;
}, function error(response) {
});
}]);
Sorry about the lack of details in my question. I was actually asking the question about the angular-restmod module.
Here's what I did in the end:
module.factory('CustomMethods', ['restmod', 'RMUtils', function CustomMethodsMixin(restmod, RMUtils) {
return restmod.mixin(function() {
this.define('Model.$customCollection', function(_url, params) {
var original = this;
return this.$collection(params, {
$urlFor: function() {
return RMUtils.joinUrl(original.$url(), _url);
}
});
});
return this;
});
}]);
And expose all my api to it:
restmodProvider.rebase('CustomMethods')
Related
I have an AngularJs application working with components and several modules. I created a plunker example to present my problem here.
I have my NavbarComponent where I declared my Controller where I inject my service called NavbarService.
In the NavbarService, I inject a factory resource to make my Rest call, once this call is made I'm trying to made some treatment on the response before returning it back to the controller, in this example I just apply a simple filter on it, but it doesn't work. If I omit my treatment and return only the categories, the code works and you can visualize a list of two.
I can make my treatment in the controller but this is a bad practice 'cause I believe it should be done in the Service, secondly since it's an asynchronous response I must do something like this to make it work, which is really really ugly:
navbarService.getCategories().$promise.then(function (response) {
console.log("controller", response[0].category);
vm.categories = categoryFilter(response[0].category);
}, function (error) {
console.log("an error occured");
});
Can someone please guide me through this, I'm out of solutions. Thank you
Another simple way is to pass a callback function to service from you component like this
'use strict';
angular.module('navbar').component('appNavbar', {
templateUrl: "navbar.template.html",
controller: [ 'navbarService', function appNavbarController(navbarService) {
var vm = this;
navbarService.getCategories(function(data){
// this will be called when service will get the response and filter function has filtered the response
vm.categories = data;
});
}]
});
Now service should be like this
'use strict';
angular.module('navbar').service('navbarService', ['categoryResourceService', 'categoryFilter', function(categoryResourceService, categoryFilter) {
var vm = this;
vm.getCategories = function(callback) {
categoryResourceService.query(function(response) {
console.log("[NavbarService] response:", response);
callback(categoryFilter(response));
}, function(error) {
console.log("[NavbarService] error:", error);
});
//return vm.categories;
}
}]);
Filter will be like this
'use strict';
angular.module('navbar').filter('category', function() {
return function(categories) {
var categoryIds = ['World'];
var result = [];
angular.forEach(categoryIds, function (categoryId) {
angular.forEach(categories, function (category) {
if (category.name == categoryId) {
console.log("Match");
result.push(category);
}
});
});
return result;
};
});
Your filter should be like this and it should be called in transformResponse in $resource query instead of service, i hope this will help you
'use strict';
angular.module('navbar').filter('category', function() {
return function(categories) {
var categoryIds = ['World'];
var result = [];
angular.forEach(categoryIds, function (categoryId) {
angular.forEach(categories, function (category) {
if (category.name == categoryId) {
console.log("Match");
result.push(category);
}
});
});
return result;
};
});
Your categoryResource.service should be like this
angular.module('shared').factory('categoryResourceService',
['$resource','categoryFilter', function($resource, categoryFilter) {
var provider = "categories.json";
var params = {
id: '#id'
};
return $resource(provider, params, {
query: {
isArray: true,
method: 'GET',
params: {},
transformResponse: function(categories) {
var results = categoryFilter(angular.fromJson(categories));
console.log("[categoryResourceService] filtered response:", results);
return results;
}
}
});
}]);
navbar.service should be like this simply
'use strict';
angular.module('navbar')
.service('navbarService', [ 'categoryResourceService', function (categoryResourceService) {
var vm = this;
vm.getCategories = function(){
vm.categories = categoryResourceService.query(function(response){
console.log("[NavbarService] response:", response);
}, function(error){
console.log("[NavbarService] error:", error);
});
return vm.categories;
}
}]);
And components like this
'use strict';
angular.module('navbar').component('appNavbar', {
templateUrl: "navbar.template.html",
controller: [ 'navbarService', function appNavbarController(navbarService) {
var vm = this;
vm.categories = navbarService.getCategories();
}]
});
I have code:
angular.module('admin', [])
.provider('users', function () {
this.users = 'default';
this.$get = function () {
var that = this;
return {
getUsers: function () {
return that.users;
}
}
};
})
.run(function (users, $http) {
users.users = $http('url'); // and others
})
.controller('test', function ($scope, users) {
$scope.users = users.getUsers();
});
I would like to intitalize data in .run() method (I can't use .config() method because it doesn't let to pass any services like $http). I found .run() method, but this code doesn't work... Data aren't saved in provider. Official documentation says:
"Execute this function after injector creation. Useful for application initialization."
I think it's best way to initialize data.
You may want to use an Angular Factory/Service for this kind of need. That is what I do. And pass that into the application. That service will be your singleton or source of truth about the dat.
angular.module('myData.services', [])
.factory('myData', ['$rootScope', '$http' , function($rootScope,$http) {
var factory = {
myData : {}
};
$http('/api/call', function(apiData) {
factory.myData = apiData;
});
return factory;
}]);
You could then use this in your controllers:
angular.module('myApp.controllers', [])
.controller('myCtrl', ['myData', '$scope', function(myData, $scope){
$scope.users = myData;
}]);
Check out the documentation on services: https://docs.angularjs.org/guide/services
Second attempt
angular.module('admin', [])
.factory('users', function ($http) {
var users = {};
var data = [];
$http.get('database.php')
.then(function (response) {
data = response.data;
});
users.getData = function () {
return data;
};
return users;
})
.controller('test', function ($scope, users) {
console.log(users.getData());
});
I would like to have data private. Empty Array returned, reponse comes with all data.
Provider configuration can be doable inside config block only, you can't do that inside run block
Though I don't find a reason to load users object while configuring app. I'd say that you should use either service/factory for this.
Code
angular.module('admin', [])
.service('users', function($http, $q) {
var users = [];
//make an get call to fetch users
function getUsers() {
return $http.get('database.php')
.then(function(response) {
data = response.data;
});
}
//will make a call if users aren't there
this.getData = function() {
// Handled below two conditions
// 1. If users aren't fetched the do an Ajax
// 2. If last ajax doesn't return a data then DO it again..
if (users.length > 0)
return $q.resolve(data); //do return data using dummy promise
return getUsers();
};
return users;
})
.controller('test', function($scope, users) {
users.getData().then(function(data){
console.log(data);
});
});
I want to have a button that refresh a page (request to http to load data) :
http://plnkr.co/edit/Ol6iEoLp037ZHu0P40Wr?p=preview
refresh button with Factory - - not working
$scope.doRefresh = function() {
Content.content.success(function(data){
$scope.data = data.artists;
console.log($scope.data);
$scope.$broadcast('scroll.refreshComplete');
});
Now when you delete some data and want to have theme back you should hit refresh button but it's not working .
working demo
http://plnkr.co/edit/WHSEPxyQDi3YNkEP8irL?p=preview
$scope.doRefresh = function() {
$http.get("data.json")
.success(function(data) {
$scope.data = data.artists;
console.log($scope.data);
$scope.$broadcast('scroll.refreshComplete');
})
}
now it's working with $http
I want to do it with factory , but i can't handle this , Any advice ?
Update *****
Factory
app.factory('Content', function ($http) {
return {
content: $http.get('data.json')
}
})
You've got to tell your service to retrieve the data every time the content is requested.
app.factory('Content', function ($http, $q) {
return {
getContent: function() {
var deferred = $q.defer();
$http.get('data.json').succes(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
}
})
Then in your controller you can do:
$scope.doRefresh = function() {
Content.getContent().then(function(data) {
$scope.data = data.artists;
console.log($scope.data);
$scope.$broadcast('scroll.refreshComplete');
});
You can also just cache the data in your factory and return it without doing a request:
app.factory('Content', function($http, $q, $timeout) {
var originalData;
return {
getContent: function() {
var deferred = $q.defer();
if (!originalData) {
$http.get('data.json').succes(function(data) {
originalData = data;
deferred.resolve(data);
});
} else {
/// gonna use timeout to simulate async behaviour -- kinda hacky but it makes for a pretty interface
$timeout(function() {
defered.resolve(originalData);
}, 0);
}
return deferred.promise;
}
}
})
Careful though, changes done to the returned object will affect the originalData object.
app.factory('Content', function ($http) {
function getContent(onSuccess) {
$http.get('data.json').success(function (data) {
if (onSuccess) {
onSuccess(data)
}
}
}
return {
content: getContent
}
})
in your controller:
$scope.doRefresh = function () {
Content.content(function (data) {
$scope.data = data.artists;
console.log($scope.data);
$scope.$broadcast('scroll.refreshComplete');
});
};
[plunkr][1]http://plnkr.co/edit/Jk1Rp3nEgUQTmDOs3xBl?p=preview
My current code is structured as below.
angular.module("app",[])
.service("dataService",function($http){
this.get = function (url) {
return $http.get(url);
};
})
.service("mainService",function(dataService){
this.getData = function(pattern){
return dataService.get(pattern+"/abc");
}
})
.controller("mainController",function($scope,mainService){
$scope.refreshData = function(pattern){
loadData(pattern);
}
function loadData(pattern){
mainService.getData(pattern)
.success(function(data){
console.log(data);
})
.error(function(error){
console.log(error);
})
}
})
I have been trying to make sense of how to test it by reading blogs but each blog has either a different approach or the blog is 2-3 years old. I would like to know how do I test the controller?
Should I test each function? If yes, then how should I test the private function? Is using the private function a good idea or should I just add the private function code to the scoped function?
Also is there any better way to do write this function?
Most important part where we are going to create stub:
beforeEach(function() {
var $httpResponse = {
success: function() {
return $httpResponse;
},
error: function() {
return $httpResponse;
}
};
var _stubMainService_ = {
getData: jasmine.createSpy('getData').and.returnValue($httpResponse)
};
angular.module('app')
.value('mainService', _stubMainService_);
});
and test that uses it:
it('rereshes data', function() {
var pattern = 'abcde';
scope.refreshData(pattern);
expect(mainService.getData).toHaveBeenCalledWith(pattern);
});
angular.module("app", [])
.service("dataService", function($http) {
this.get = function(url) {
return $http.get(url);
};
})
.service("mainService", function(dataService) {
this.getData = function(pattern) {
return dataService.get(pattern + "/abc");
}
})
.controller("mainController", function($scope, mainService) {
$scope.refreshData = function(pattern) {
loadData(pattern);
}
function loadData(pattern) {
mainService.getData(pattern)
.success(function(data) {
console.log(data);
}).error(function(error) {
console.log(error);
})
}
})
describe('mainController()', function() {
var scope, controller, mainService, $q;
beforeEach(module('app'));
beforeEach(function() {
var $httpResponse = {
success: function() {
return $httpResponse;
},
error: function() {
return $httpResponse;
}
};
var _stubMainService_ = {
getData: jasmine.createSpy('getData').and.returnValue($httpResponse)
};
angular.module('app')
.value('mainService', _stubMainService_);
});
beforeEach(inject(function($controller, $rootScope, _mainService_) {
scope = $rootScope.$new();
controller = $controller('mainController', {
$scope: scope
});
mainService = _mainService_;
}));
it('rereshes data', function() {
var pattern = 'abcde';
scope.refreshData(pattern);
expect(mainService.getData).toHaveBeenCalledWith(pattern);
});
})
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>
I am trying to use Angular with SignalR in my demo application. I am trying to use $q service to use promises. Don't know whats wrong in my code but its not working.
SERVICE
var boardConsole = $.connection.builtinboard;
var chat = angular.module('chat', []);
chat.factory('board', ['$q', '$timeout', function ($q, $timeout) {
var board = {};
board.startBoard = function (callback) {
$.connection.hub.start(function () {
if (angular.isFunction(callback)) {
callback();
}
});
};
board.loadAllMessages = function () {
var deferred = $q.defer();
boardConsole.server.loadAllMessages().done(function (messages) {
deferred.resolve(messages);
}).fail(function () {
deferred.reject(function () {
//SHOW NOTHING FOUND
});
});
return deferred.promise;
};
return board;
} ]);
CONTROLLER
chat.controller('chatController', ['$scope', 'board', function ($scope, board) {
$scope.Messages = [];
board.startBoard(function () {
board.loadAllMessages().then(function (messages) {
alert('1');
$scope.Messages = messages;
});
});
} ]);
its not working
Just wrap it in a $timeout. This will perform a safe $apply if necessary.
$timeout(function(){
deferred.resolve(messages);
});