I am trying to consume my spring rest service using angularjs client following this link
Create,update and read parts are working. When I try to delete, its showing this error.
Error: [$resource:badcfg] Error in resource configuration for action
get. Expected response to contain an object but got an array
(Request: GET http://localhost:8080/SpringRestExample/employee)
Why i am getting GET request in DELETE method?
employee_service.js
'use strict';
App.factory('Employee', ['$resource', function ($resource) {
return $resource(
'http://localhost:8080/SpringRestExample/employee/:id',
{id: '#employeeId'},
{
update: {
method: 'PUT'
}
}
);
}]);
employee_controller.js
'use strict';
App.controller('EmployeeController', ['$scope', 'Employee', function($scope, Employee) {
var self = this;
self.employee= new Employee();
self.employees=[];
self.fetchAllEmployees = function(){
self.employees = Employee.query();
};
self.createEmployee = function(){
self.employee.$save(function(){
self.fetchAllEmployees();
});
};
self.updateEmployee = function(){
self.employee.$update(function(){
self.fetchAllEmployees();
});
};
self.deleteEmployee = function(identity){
var employee = Employee.get({employeeId:identity}, function() {
employee.$delete(function(){
console.log('Deleting employee with id ', identity);
self.fetchAllEmployees();
});
});
};
self.fetchAllEmployees();
self.submit = function() {
if(self.employee.employeeId==null){
console.log('Saving New Employee', self.employee);
self.createEmployee();
}else{
console.log('Updating employee with id ', self.employee.employeeId);
self.updateEmployee();
console.log('Employee updated with id ', self.employee.employeeId);
}
self.reset();
};
self.edit = function(employeeId){
console.log('id to be edited', employeeId);
for(var i = 0; i < self.employees.length; i++){
if(self.employees[i].employeeId === employeeId) {
self.employee = angular.copy(self.employees[i]);
break;
}
}
};
self.remove = function(employeeId){
console.log('id to be deleted', employeeId);
if(self.employee.employeeId === employeeId) {//If it is the one shown on screen, reset screen
self.reset();
}
self.deleteEmployee(employeeId);
};
self.reset = function(){
self.employee= new Employee();
$scope.myForm.$setPristine(); //reset Form
};
}]);
Your issue could be when you call Employee.get({employeeId:identity}, ...) prior to deleting the employee. This will load the employee before deletion and it will do a GET request on 'http://localhost:8080/SpringRestExample/employee/:id'.
For this query to work properly, you need to provide id, which you haven't done, so it might just be leaving out that part of the URL. You provided employeeId, which is only used for mapping the id parameter to the Employee objects. Try replacing the query above with {id: identity}.
Related
I have a unit test fails to correctly read the JSON in the second request
this is my Config factory
(function() {
'use strict';
angular.module('commercial.factories').factory('config', config);
function config($http) {
var service = {
GetConfig: getConfig
};
return service;
function getConfig(identifier) {
var _config = {};
// Check for url match in mapping json file
var urlMap = $http.get('./app/core/urlMap.json').then(function(response) {
for (var i = 0; i < response.data.length; i++) {
if (identifier.toString().toLowerCase().indexOf(response.data[i].url.toLowerCase()) > -1 || response.data[i].clientId === identifier) {
return response.data[i].contentFolder;
}
}
});
// Retrieve the config for the related client found in the url map (above)
return urlMap.then(function(response) {
var contentFolder = response;
return $http.get('./content/' + response + '/config.json')
.then(function(response) {
if (Object.keys(_config).length === 0) {
_config = response.data;
_config.contentFolder = contentFolder;
}
return _config;
});
});
}
}
})();
and my test...
describe('Config Factory', function() {
var configFactory;
beforeEach(inject(function(_config_) {
configFactory = _config_;
}));
describe('GetConfig()', function() {
it('should get the urlMap from the urlMap.json', function() {
var identifier = '_default';
var mockData = [{ url: identifier, contentFolder: '_default' }];
$httpBackend.expectGET('./content/' + identifier + '/config.json');
$httpBackend.expectGET('./app/core/urlMap.json').respond(mockData);
var promise = configFactory.GetConfig(identifier);
$httpBackend.flush(0);
promise.then(function(result) {
expect(result).toEqual(mockData);
})
});
});
});
and the config.json it trys to read...
{
"clientId":34
}
when i run my test i get an error back from Karama saying ...
uncaught SyntaxError: Unexpected token :
on line 2 of my JSON.
Im suspicious that it may have something to do with having two expectGET's in the same test but i cant be sure?
You might need to call json.stringify(mockData) for the mockData, when responding from the get request. The json parser probably has problems with the single quotes in your mockData array.
I also spotted a missing . in your expectation:
expect(result) toEqual(mockData);
should be:
expect(result).toEqual(mockData);
OK, so this was a bit of a silly mistake on my part.
I noticed that i failed to add a respond to the config.json call. See code below.
it('should get the urlMap from the urlMap.json', function() {
var identifier = '_default';
var mockData = [{ url: identifier, contentFolder: '_default' }];
var mockConfig = { clientId: 34 };
$httpBackend.expectGET('./app/core/urlMap.json').respond(mockData);
$httpBackend.expectGET('./content/' + identifier + '/config.json').respond(mockConfig);
var promise = configFactory.GetConfig(identifier);
$httpBackend.flush();
promise.then(function(result) {
expect(result).toEqual(mockData);
})
});
I'm attempting to learn the MEAN stack and learning to use the $http service.
I currently have a global check in place that is suppose to update my Sprints model, which looks like:
var SprintSchema = new Schema({
tasks: [{
type: String,
ref: 'Task'
}],
name: {
type: String
},
start: {
type: Date
},
end: {
type: Date
},
active: Boolean
});
The following controller should update the Sprint model when requested, and when I console.log the variable in my success function, it looks like what I would expect it to pass but it doesn't actually end up updating my model. Below is my code and an example of the console.log.
'use strict';
angular.module('inBucktApp')
.service('VariableService', function () {
// AngularJS will instantiate a singleton by calling "new" on this function
var ticketId = 'noTicketYet';
var ticketAssigneeName = 'noTicketNameYet';
return {
getPropertyId: function () {
return ticketId;
},
getPropertyName: function () {
return ticketAssigneeName;
}
,
setProperty: function(value, valueName) {
ticketId = value;
ticketAssigneeName = valueName;
}
};
})
.run(['$rootScope', '$http', 'socket', 'VariableService', function($rootScope, $http, socket, VariableService) {
$rootScope.sprintStart;
$http.get('/api/sprints').success(function(sprints) {
$rootScope.sprints = sprints.pop();
$rootScope.sprintStart = new Date($rootScope.sprints.start);
$rootScope.sprintEnd = new Date($rootScope.sprints.end);
socket.syncUpdates('sprints', $rootScope.sprints);
$http.get('/api/tasks').success(function(task) {
$rootScope.task = task;
$rootScope.taskPop = _.flatten($rootScope.task);
$rootScope.taskPopAgain = $rootScope.task.pop();
socket.syncUpdates('task', $rootScope.task);
$rootScope.updateTicket = function(){
//Goes through the entire array and check each element based on critera.
var taskIdsToAdd = [];
for(var i = 0; i < $rootScope.taskPop.length; i++){
var taskFind = $rootScope.taskPop[i];
//Logic if ticket is not in the sprint
if ((new Date(taskFind.start) >= $rootScope.sprintStart) && (new Date(taskFind.start) <= $rootScope.sprintEnd)){
taskFind.sprint = true;
taskIdsToAdd.push(taskFind._id);
$rootScope.sprints.tasks.push(taskFind._id);
$http.put("/api/tasks/"+taskFind._id,taskFind).success(function(task){
console.log('Logic 1 Ran!');
console.log($rootScope.sprintStart);
// socket.syncUpdates('taskPopAgain', taskFindPopAgain);
});
$http.put("/api/sprints/"+$rootScope.sprints._id,$rootScope.sprints).success(function(sprints){
console.log('Logic 2 Ran!');
console.log($rootScope.sprintStart);
console.log(sprints)
});
console.log($rootScope.sprints);
} else{
console.log('this doesnt work first');
};
//Logic if ticket is not in the sprint
if (new Date(taskFind.start) < $rootScope.sprintStart || new Date(taskFind.start) > $rootScope.sprintEnd){
taskFind.sprint = false;
$http.put("/api/tasks/"+taskFind._id,taskFind).success(function(task){
console.log(task);
});
}else{
console.log('this doesnt work');
};
}
};
$rootScope.updateTicket();
});
});
}]);
Console.Log of console.log(sprints)
Anyone have any idea what I'm doing incorrect here?
Thanks for the help guys.
I am creating a simple AngularJS SPA using an API to load data into Mongoose.
My app just adds, displays and edits a list of members. It works when I just store the members in an array in my factory service but now I want to change it to hook up to Mongoose via an API.
Factory
app.factory('SimpleFactory', ['$http', function($http){
var factory = {};
var members = $http.get('/api/members')
factory.getMembers = function ()
{
return members = $http.get('/api/members');
}
factory.getMember = function (index) {
if (index >=0 && index < members.length ) {
return members[index] = $http.get('/api/members/' + member_id )
}
return undefined
}
factory.addMember = function(member) {
return $http.post('/api/members',member)
}
factory.updateMember = function(index,member) {
$http.put('/api/members/' + member_id, member)
}
return factory;
}])
Controller
app.controller('MembersController', ['$scope','SimpleFactory',
function ($scope,SimpleFactory) {
SimpleFactory.getMembers()
.success(function(members) {
$scope.members = members;
});
$scope.addMember = function()
{
var member = {
name: $scope.newMember.name,
address: $scope.newMember.address,
age : $scope.newMember.age,
level : $scope.newMember.level,
swimmer : $scope.newMember.swimmer,
email : $scope.newMember.email,
regdate : $scope.newMember.regdate,
}
SimpleFactory.addMember(member)
.success(function(added_member)
{
$scope.members.push(added_member);
$scope.newMember = { }
} );
}
}])
But I am not sure how to change my controller for updating a member, it is coded as follows to pick up the members from an array in my factory setting, how do I code it to pick up members from Mongoose via API:
app.controller('MemberDetailController', ['$scope', '$location', '$routeParams', 'SimpleFactory',
function($scope, $location, $routeParams, SimpleFactory) {
$scope.member = {
index: $routeParams.member_index,
detail: SimpleFactory.getMember($routeParams.member_index)
}
$scope.updateMember = function() {
SimpleFactory.updateMember($scope.member.index,
$scope.member.detail)
$location.path('/members')
}
}
])
Can anyone help, its not a complicated app but I'm only learning and I am stuck here!
Thanks
You $scope.member object should set after getMember promise success.
Code
SimpleFactory.getMember($routeParams.member_index).then(function(data){
$scope.member = {
index : $routeParams.member_index,
detail : data.user
};
});
Apart from that you need to make sure getMember method should always return a promise while index is 0
factory.getMember = function (index) {
var deferred = $q.defer();
if (index >=0 && index < members.length ) {
return members[index] = $http.get('/api/members/' + member_id )
}
deferred.resolve;
}
Update
For calling update method you need to do change service first which would return a promise
factory.updateMember = function(index,member) {
return $http.put('/api/members/' + member_id, member)
}
Then call factory.updateMember resolve that promise and then do $location.path
$scope.updateMember = function() {
SimpleFactory.updateMember($scope.member.index, $scope.member.detail)
.then(function(data) {
$location.path('/members')
});
};
I'm newbie to js and this is my first question in stackoverflow as well. So any comment or act of downgrading is understandable.
This is the angular-js-flowchart project on github.
This is another stackoverflow topic that teachs how to use factory as a data getter involving $http.
My need is to generate data for the chart by using an Angular factory that returns a $http function. The $http talks to a php service that retrieve data from database. I have tested the service using jsonlint and its working fine. The directory of service is checked, relatively to the html file.
I copied the "factory" code from another stackoverflow question and applied to app.js in the angularjs-flowchart Github project.
The problem is that the Chrome console keeps throwing an error that I can not understand. Data is not retrieved. The error on console is "TypeError: Cannot read property 'getData' of undefined"
This is the modified-by-me app.js:
//
// Define the 'app' module.
//
angular.module('app', ['flowChart', ])
//
// Simple service to create a prompt.
//
.factory('prompt', function () {
/* Uncomment the following to test that the prompt service is working as expected.
return function () {
return "Test!";
}
*/
// Return the browsers prompt function.
return prompt;
})
//
// Application controller.
//
.controller('AppCtrl', ['$scope', 'prompt', function AppCtrl ($scope, prompt, dataFactory) {
//
// Code for the delete key.
//
var deleteKeyCode = 46;
//
// Code for control key.
//
var ctrlKeyCode = 65;
//
// Set to true when the ctrl key is down.
//
var ctrlDown = false;
//
// Code for A key.
//
var aKeyCode = 17;
//
// Code for esc key.
//
var escKeyCode = 27;
//
// Selects the next node id.
//
var nextNodeID = 10;
//
// Event handler for key-down on the flowchart.
//
$scope.keyDown = function (evt) {
if (evt.keyCode === ctrlKeyCode) {
ctrlDown = true;
evt.stopPropagation();
evt.preventDefault();
}
};
//
// Event handler for key-up on the flowchart.
//
$scope.keyUp = function (evt) {
if (evt.keyCode === deleteKeyCode) {
//
// Delete key.
//
$scope.chartViewModel.deleteSelected();
}
if (evt.keyCode == aKeyCode && ctrlDown) {
//
// Ctrl + A
//
$scope.chartViewModel.selectAll();
}
if (evt.keyCode == escKeyCode) {
// Escape.
$scope.chartViewModel.deselectAll();
}
if (evt.keyCode === ctrlKeyCode) {
ctrlDown = false;
evt.stopPropagation();
evt.preventDefault();
}
};
//
// Add a new node to the chart.
//
$scope.addNewNode = function () {
var nodeName = prompt("Enter a task name:", "New Task");
if (!nodeName) {
return;
}
//
// Template for a new node.
//
var newNodeDataModel = {
name: nodeName,
id: nextNodeID++,
x: 0,
y: 0,
inputConnectors: [
{
name: "Pre"
}
],
outputConnectors: [
{
name: "Sub"
}
],
};
$scope.chartViewModel.addNode(newNodeDataModel);
};
//
// Add an input connector to selected nodes.
//
$scope.addNewInputConnector = function () {
var connectorName = prompt("Enter a connector name:", "New connector");
if (!connectorName) {
return;
}
var selectedNodes = $scope.chartViewModel.getSelectedNodes();
for (var i = 0; i < selectedNodes.length; ++i) {
var node = selectedNodes[i];
node.addInputConnector({
name: connectorName,
});
}
};
//
// Add an output connector to selected nodes.
//
$scope.addNewOutputConnector = function () {
var connectorName = prompt("Enter a connector name:", "New connector");
if (!connectorName) {
return;
}
var selectedNodes = $scope.chartViewModel.getSelectedNodes();
for (var i = 0; i < selectedNodes.length; ++i) {
var node = selectedNodes[i];
node.addOutputConnector({
name: connectorName,
});
}
};
//
// Delete selected nodes and connections.
//
$scope.deleteSelected = function () {
$scope.chartViewModel.deleteSelected();
};
//
// Setup the data-model for the chart.
//
var chartDataModel = {};
var handleSuccess = function(data, status){
chartDataModel = data;
console.log(chartDataModel);
};
dataFactory.getData().success(handleSuccess);
//
// Create the view-model for the chart and attach to the scope.
//
$scope.chartViewModel = new flowchart.ChartViewModel(chartDataModel);
}])
.factory('dataFactory', function($http){
return {
getData : function(){
return $http.post("chart-data-retrieve.php");
}
};
});
Basically, what i added but doesn't work is
// Setup the data-model for the chart.
//
var chartDataModel = {};
var handleSuccess = function(data, status){
chartDataModel = data;
console.log(chartDataModel);
};
dataFactory.getData().success(handleSuccess);
and
.factory('dataFactory', function($http){
return {
getData : function(){
return $http.post("chart-data-retrieve.php");
}
};
});
Please help, thanks.
I tried to set the chartViewModel of the $scope directly inside the service call, so the variable chartDataModel becomes redundant. And it works.
// Create the view-model for the chart and attach to the scope.
//
myService.then(function(data) {
$scope.chartViewModel = new flowchart.ChartViewModel(data);
});
I tried to return a promise, not a $http from the factory. It works now. The controller can now use the service to retrieve data. However I still could not set the controller's variable to the data retrieved.
The following is the code:
.factory('myService', function($http, $q) {
//this runs the first time the service is injected
//this creates the service
var deferred = $q.defer();
$http.get('chart-data-retrieve.php').then(function(resp) {
deferred.resolve(resp.data);
});
return deferred.promise;
})
And the code inside controller:
var chartDataModel = {};
//get data from myService factory
myService.then(function(data) {
alert(data);
chartDataModel = data;
});
Currently, the alert() show me the data already. However, the variable chartDataModel is still unset.
First project working with AngularJS and I am a bit stuck using the select list to either set the default value to the first option for a new, or if its an edit select the value.
I have a form with two select lists. Note, I am thinking i'm wrong in my ng-options tag.
invite.tpl.html
<select ng-model="selectedUser" ng-options="user.id as user.user_name for user in users"></select>
<select ng-model="selectedEvent" ng-options="event.id as event.name for event in events"></select>
A controller that gets/posts JSON.
invite.js
.controller('InviteCtrl', function InviteController( $scope, InviteRes, $state, $stateParams ) {
$scope.inviteId = parseInt($stateParams.inviteId, 10);
$scope.users = InviteRes.Users.query();
$scope.events = InviteRes.Events.query();
//EDIT (HAVE ID) - SET SELECTS TO THE USER/EVENT
if ($scope.inviteId) {
$scope.invite = InviteRes.Invites.get({id: $scope.inviteId});
$scope.selectedUser = $scope.invite.user_id;
$scope.selectedEvent = $scope.invite.event_id;
}
//NEW (NO ID) - SET DEFAULT OPTIONS TO FIRST USER/EVENT
else {
$scope.selectedUser = $scope.users[0];
$scope.selectedEvent = $scope.events[0];
$scope.invite = new InviteRes.Invites();
}
Function to save.
$scope.submit = function() {
$scope.invite.user_id = $scope.selectedUser;
$scope.invite.event_id = $scope.selectedEvent;
//IF ID - UPDATE ELSE NEW
if ($scope.inviteId) {
$scope.invite.$update(function(response) {
$state.transitionTo('invites');
}, function(error) {
$scope.error = error.data;
});
}
else {
$scope.invite.$save(function(response) {
$state.transitionTo('invites');
}, function(error) {
$scope.error = error.data;
});
}
};
And a getting those resources
.factory( 'InviteRes', function ( $resource ) {
return {
Invites: $resource("../invites/:id.json", {id:'#id'}, {'update': {method:'PUT'}, 'remove': {method: 'DELETE', headers: {'Content-Type': 'application/json'}}}),
Users: $resource('../users.json'),
Events: $resource('../events.json'),
};
})
I looked around and found some articles explaining how to do this, but everything I've tried has either given me issues with either setting the values, or saving the form.
The resource API doesn't return immediately - see the docs for the following statement:
It is important to realize that invoking a $resource object method
immediately returns an empty reference
Could it simply be that you're trying to assign the value before it's available?
Could you change your code to read something like:
if ($scope.inviteId) {
$scope.invite = InviteRes.Invites.get({id: $scope.inviteId}, function() {
$scope.selectedUser = $scope.invite.user_id;
$scope.selectedEvent = $scope.invite.event_id;
});
}
In terms of the select directive, I tend to use objects rather than values, e.g.
<select ng-model="selectedUser" ng-options="user.user_name for user in users"></select>
// in controller:
$scope.selectedUser = $scope.users[1];