Here's my Spring controller (resource class) method:
#Controller
#RequestMapping("/rest/cart")
public class CartResources {
#Autowired
CartService cartService;
#RequestMapping("/{cartId}")
public #ResponseBody
Cart getCartById (#PathVariable(value = "cartId") int cartId)
{
Cart cart = cartService.getCartById(cartId);
CartItem item = cart.getCartItems().get(0);
Product product = item.getProduct();
System.out.println(product.getProductName());
return cart;
}
}
Here's my angular js class:
var cartApp = angular.module ("cartApp", []);
cartApp.controller("cartCtrl", function ($scope, $http){
$scope.refreshCart = function (cartId) {
$http.get('/eGrocery/rest/cart/'+$scope.cartId).success(function (data) {
$scope.cart=data;
//CODE BELOW IS FOR TESTING PURPOSES
var product = $scope.cart.cartItems[0].product;
var item = $scope.cart.cartItems[0];
if(item == null)
alert("item is null");
else
alert("total price is" + item.totalPrice);
if(product == null)
alert("product is null");
else
alert("product name is" + product.productName);
});
};
$scope.initCartId = function (cartId) {
$scope.cartId = cartId;
$scope.refreshCart(cartId);
};
Here's the HTML file:
<section class="container" ng-app="cartApp">
<div ng-controller = "cartCtrl" ng-init="initCartId('${cartId}')">
<table class="table table-hover">
<tr>
<th>Product</th>
<th>Unit Price</th>
<th>Quantity</th>
<th>Price</th>
</tr>
<tr ng-repeat = "item in cart.cartItems">
<td>{{item.product.productName}}</td>
<td>{{item.product.productPrice}}</td>
<td>{{item.quantity}}</td>
<td>{{item.totalPrice}}</td>
</tr>
</table>
</div>
Brief explanation of the code:
The Spring controller is supposed to pass a Cart object to AngularJS class. The cart object contains cartItem object, which contains a product object.
The problem:
In the AngularJS file, when I try to retrieve any attribute of the Product object, I get null. In fact, the entire product object is null. However, the cartItem object is not null. For instance, I can retrieve the value of cartItem.totalPrice.
The strange thing here is that in the Spring controller class, I explicitly printed out the values of the Product object and they were not null. So, I don't know why AngularJS gets a null Product. Please help.
Related
I'm trying to make a web app in Java that connects to a database and shows a table with users.
I have problem with this piece of code in HTML but I believe that this is only the result of earlier coding.
So the code in curly brackets ( {{user.name}} and other) gets underlined and says "Unresolved variable"
I have no idea where is the problem so I'm pasting my angular methods and Java code where I made a list with users that should be displayed in localhost.
This is the code from github that I tried to rewrite but instead of hotels I'm displaying Users.
https://github.com/dangeabunea/RomanianCoderExamples/blob/master/BookingDemo/src/main/resources/templates/index.html
HTML code:
<!-- Display users in a table -->
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Surname</th>
<th>Login</th>
<th>Is Deleted?</th>
<th style="width: 90px"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in vm.users">
<td>{{user.name}}</td>
<td>{{user.surname}}</td>
<td>{{user.login}}</td>
<td>{{user.isDeleted}}</td>
<td>
<button class="btn btn-danger" ng-click="vm.deleteUser(user.id)">Delete</button>
</td>
</tr>
</tbody>
</table>
JavaScript (angular):
angular
.module('app')
.controller('UserController', UserController);
UserController.$inject = ['$http'];
function UsersController($http) {
var vm = this;
vm.users = [];
vm.getAll = getAll;
vm.deleteUser = deleteUser;
init();
function init(){
getAll();
}
function getAll(){
var url = "/users/all";
var usersPromise = $http.get(url);
usersPromise.then(function(response){
vm.users = response.data;
});
}
function deleteUser(id){
var url = "/users/delete/" + id;
$http.post(url).then(function(response){
vm.users = response.data;
});
}
}
Java:
#Component
public class DatabaseSeeder implements CommandLineRunner {
private UserRepository userRepository;
#Autowired
public DatabaseSeeder(UserRepository userRepository){
this.userRepository = userRepository;
}
#Override
public void run(String... strings) throws Exception {
List <Users> users = new ArrayList<>();
users.add(new Users("John", "Kowalski", "john332", false));
users.add(new Users( "Debby", "Ryan", "debbs84", false));
users.add(new Users( "Michael", "Smith", "grizzly98", false));
userRepository.saveAll(users);
I have implemented a REST service with Java and all HTTP methods work correctly when I test it with Postman. Now I decided to learn more about AngularJS and added it for consuming the REST service. The GET request works fine and all products are displayed on an html page. But for some reason Delete and Put methods do not work at all. And I'm having trouble to figure out what causes such behaviour.
I have noticed that the problem arises with methods that involve product id. The entity Product.java has an id field named prod_id.
app.js
angular.module("AppProducts", [])
.constant("baseUrl", "http://localhost:8080/webstore/product")
.controller("ProductsCtrl", function ($scope, $http, baseUrl) {
$scope.currentView = "table";
//Works correctly
$scope.showAll = function () {
$http.get(baseUrl).success(function (data) {
$scope.products = data;
});
}
//if product exists, copy it, otherwise new empty
$scope.editOrCreate = function (product) {
$scope.currentProduct = product ? angular.copy(product) : {};
$scope.currentView = "edit";
}
$scope.create = function (product) {
$http.post(baseUrl, product).success(function (product) {
$scope.products.push(product);
$scope.currentView = "table";
});
}
$scope.update = function (product) {
$http({
url: baseUrl + product.prod_id,
method: "PUT",
data: product
}).success(function (modifiedItem) {
for (var i = 0; i < $scope.products.length; i++) {
if ($scope.products[i].prod_id == modifiedItem.prod_id) {
$scope.products[i] = modifiedItem;
break;
}
}
$scope.currentView = "table";
});
}
$scope.delete = function (product) {
// HTTP DELETE
$http({
method: "DELETE",
url: baseUrl + product.prod_id
}).success(function () {
$scope.products.splice($scope.products.indexOf(product), 1);
});
}
// Save changes
$scope.saveEdit = function (product) {
if (angular.isDefined(product.prod_id)) {
$scope.update(product);
} else {
$scope.create(product);
}
}
$scope.cancelEdit = function () {
$scope.currentProduct = {};
$scope.currentView = "table";
}
$scope.sortType = 'brand'; // set the default sort type
$scope.sortReverse = false; // set the default sort order
$scope.searchProduct = ''; // set the default search/filter term
$scope.showAll();
});
'table' view
<table id="myTable" class="table table-hover">
<thead>
<tr>
<th>Brand</th>
<th>Product Name</th>
<th>Description</th>
<th>Price</th>
<th width="100"></th>
<th width="100"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in products | orderBy:sortType:sortReverse">
<td>{{product.brand}}</td>
<td>{{product.productName}}</td>
<td>{{product.description}}</td>
<td>{{product.price}}</td>
<td><button class="btn btn-success" ng-click="editOrCreate(product)">Edit</button></td>
<td><button class="btn btn-danger" ng-click="delete(product)">Delete</button></td>
</tr>
</tbody>
</table>
RestController 'delete' method
#RequestMapping(value = "/product/{id}", method = RequestMethod.DELETE)
public ResponseEntity<?> deleteProduct(#PathVariable("id") int id) {
Product product = productService.getProductById(id);
if (product == null) {
return new ResponseEntity(new CustomError("Unable to delete. Product with id " + id + " not found."),
HttpStatus.NOT_FOUND);
}
productService.deleteProduct(id);
return new ResponseEntity<Product>(HttpStatus.NO_CONTENT);
}
This may be the problem. When you are appending the url like this
baseUrl + product.prod_id // let product.prod_id = 1
you would get resulting string as http://localhost:8080/webstore/product1 which is not defined in your backend. Try changing the assignment to something like this:
baseUrl + "/" + product.prod_id
Or you cold just add an / at end of baseurl. Like this:
.constant("baseUrl", "http://localhost:8080/webstore/product/")
I am working on a Web Application using Laravel as backend API and AngularJS for frontend. I have successfully fetched the data from Laravel API and displayed it via AngularJS ng-repeat. Now i want a delete button for each record which is displayed in the table. When a user click that delete button it should delete the clicked record.
I did the following try which is working perfectly.But the problem occurs when i click delete button it deletes record from database but it is not refreshing the records list , instead of refreshing it just shows the headers titles of table and nothing else. When i manually refresh it from browser then it displays back the records list. I want to load the list automatically after the record is deleted.
Console Error : Console Error: DELETE
http://localhost/ngresulty/public/api/result/50?id=50 500 (Internal
Server Error)
Before Delete ( List ):
After delete Scene:
MainCtrl.js
$scope.deleteResult = function(id) {
$scope.loading = true;
Result.destroy(id)
.success(function(data) {
// if successful, we'll need to refresh the comment list
Result.get()
.success(function(data) {
$scope.students = data;
$scope.loading = false;
});
});
};
MyAppService.js
angular.module('myAppService', [])
.factory('Result', function($http) {
return {
get : function() {
return $http.get('api/result');
},
show : function(id) {
return $http.get('api/result/' + id);
},
save : function(resultData) {
return $http({
method: 'POST',
url: 'api/result',
headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
data: $.param(resultData)
});
},
destroy : function(id) {
return $http.delete('api/result/' + id,{params: {id}});
}
}
});
App.js
var myApp = angular.module('myApp', ['mainCtrl', 'myAppService']);
Results View :
<table class="table table-striped">
<thead>
<tr>
<th>Roll No</th>
<th>Student Name</th>
<th>Father Name</th>
<th>Obtained Marks</th>
<th>Total Marks</th>
<th>Percentage</th>
<th>Delete</th>
</tr>
</thead>
<tbody ng-hide="loading" ng-repeat="student in students | filter:searchText">
<tr>
<td>#{{ student.rollno }}</td>
<td>#{{ student.name }}</td>
<td>#{{ student.fname }}</td>
<td>#{{ student.obtainedmarks }}</td>
<td>#{{ student.totalmarks }}</td>
<td>#{{ student.percentage }}</td>
<td>
Delete</p>
</td>
</tr>
</tbody>
</table>
What I tried but not working :
$scope.deleteResult = function(id) {
$scope.loading = true;
Result.destroy(id)
.success(function(data) {
// do something with data if you want to
$scope.students.splice(id, 1);
});
};
Solution :
Whenever you get 500 internal error the issue will be from server side. The issue was with server side all i did was change my destroy service to
destroy : function(id) {
return $http.delete('api/result/' + id);
}
and in laravel controller i was returning a bool value true but i changed that to ID
return \Response::json($studentid);
because i was in need of that ID for success return and then it worked like a charm.
The problem is Array splice method takes the index of array as first argument and you are providing it Student Id which is not a array index. You have to find the index of student id in the array then pass it into the splice method
$scope.findWithAttr= function(array, attr, value) {
for(var i = 0; i < array.length; i += 1) {
if(array[i][attr] === value) {
return i;
}
} }
Now you can call this function is destroy success block.
$scope.deleteResult = function(idToDelete) {
$scope.loading = true;
$http.delete('api/result/' + id,{params: {id}}); }
.then(function(data) {
var index=$scope.findWithAttr($scope.students,id,idToDelete);
$scope.students.splice(index, 1);
});
};
You are splicing the data incorrectly.
Do like this to splice the data in destroy success block.
var del_index = $scope.students.findIndex(function(d){return d.id == id});
if(del_index>0)//if index of the id to be removed found
$scope.students.splice(del_index, 1);
There is a javascript library called lodash
This library provides the remove function where you can remove an element from the data.
Sometimes slice does not work. SO try this hopefully it would work.
$scope.deleteResult = function(id) {
$scope.loading = true;
Result.destroy(id)
.success(function(data) {
// do something with data if you want to
_.remove($scope.students,function(student){
return id==studednt.id;
}
});
};
I'm really new to Angular and i'm trying to create a list of user transactions that presents the time of the action and the user's name. In my audit API I have an action ID and the User FK which associates with my User API and i'm displaying it as follows:
HTML
<table>
<thead>
<tr>
<th>
Date/Time
</th>
<th>
User
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="audit in audit.data>
<td>{{audit.audit_date_time}}</td>
<td>**{{audit.audit_user_fk}}**</td> **<--I need the name not the ID here**
</tr>
</tbody>
</table>
My Apis are as follows:
AUDIT
[
{
"audit_id": "1",
"audit_date_time": "2016-01-28 12:46:20",
"audit_user_fk": "97"
}
]
USER
[
{
"user_id": "97",
"user_full_name": "Mr.User",
}
]
Controller, which is working fine GETting the data from each API:
app.controller('auditControl', ['$scope','auditService', 'userService', function ($scope, auditService, userService) {
var auditLogs = auditService.query(function () {
$scope.audit.data = auditLogs;
});
var user = userService.query(function () {
$scope.auditUser = user;
});
}]);
So my main issue i'm having is getting the user name in the table instead of the foreign key value. I've stripped out a lot of this just so we can focus on the main problem. Getting the user name from the user API, based on the FK in the Audit API and repeated based on the items in the Audit API.
Any help greatly appreciated and apologies for the noob question!
Create a custom filter.
app.filter("lookupUser", function() {
function lookup (idNum, userList) {
var userName = "UNKNOWN";
angular.forEach(userList, function(user) {
if ( user.user_id == idNum ) {
userName = user.user_full_name;
};
});
return userName;
};
return lookup;
});
Then in your template:
<tr ng-repeat="audit in audit.data>
<td>{{audit.audit_date_time}}</td>
<td>{{audit.audit_user_fk | lookupUser : auditUser }}</td>
</tr>
You could do something like this:
Controller:
app.controller('auditControl', ['$scope','auditService', 'userService', function ($scope, auditService, userService) {
var auditLogs = auditService.query(function () {
$scope.audit.data = auditLogs;
});
var user = userService.query(function () {
$scope.auditUser = user;
});
$scope.getUserName = function (id) {
var result = $scope.users.filter(function( user ) {
return user.user_id == id;
});
if (angular.isDefined(result) && result.length > 0) {
return result[0].user_full_name;
} else {
return "--";
}
}
}]);
HTML
<table>
<thead>
<tr>
<th>
Date/Time
</th>
<th>
User
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="audit in audit.data">
<td>{{audit.audit_date_time}}</td>
<td>**{{getUserName(audit.audit_user_fk)}}**</td> **<--I need the name not the ID here**
</tr>
</tbody>
</table>
I don't know where the users array are, so I called $scope.users.
On my view I have possibility to filter displayed data using Ajax.BeginForm that returns partail view and refreshes only a table with data. I also have a possibility to sort by column when clicking a column header using Ajax.ActionLink. The problem is that when I use Ajax.ActionLink I have to refresh whole page and I loose what was selected in filters (they are custom multiselect combo controls) so whole data is sorted and displayed.
I tried using ViewBag to send Json data to set back the filters but I failed. I would rather only refresh table even on sort. I am kind of new to MVC.
How to do it in a nice way? Thanks for the help!
View:
#using (Ajax.BeginForm(new AjaxOptions() {HttpMethod = "get", InsertionMode = InsertionMode.Replace, UpdateTargetId = "exposureRecords"}))
{
<div class="form-group">
<select id="brands-select" name="brands" multiple="multiple">
#{
var brands = Model.Brands;
foreach (var item in brands)
{
<option value="#item">#item</option>
}
}
</select>
</div>
(...similar for 3 other filters...)
<table class="table">
<tr>
<th>
#Html.ActionLink("Marka", "Index", new { sortOrder = ViewBag.BrandSortParam })
</th>
<th>
#Html.ActionLink("Dyscyplina", "Index", new { sortOrder = ViewBag.DisciplineSortParm })
</th>
<th>
#Html.ActionLink("MiesiÄ…c", "Index", new { sortOrder = ViewBag.MonthSortParm })
</th>
<th>
#Html.ActionLink("Liczba ekspozycji", "Index", new { sortOrder = ViewBag.QuantitySortParm })
</th>
<th>
#Html.ActionLink("Ekwiwalent reklamowy", "Index", new { sortOrder = ViewBag.ValueSortParm })
</th>
</tr>
</table>
}
#Html.Partial("_Table",Model)
then in controller I have
public ActionResult Index(IEnumerable<string> brands, IEnumerable<string> disciplines,
IEnumerable<string> months,string sortOrder)
{
ViewBag.BrandSortParam = String.IsNullOrEmpty(sortOrder) ? "brand_desc" : "";
ViewBag.DisciplineSortParm = sortOrder == "discipline" ? "discipline_desc" : "discipline";
ViewBag.MonthSortParm = sortOrder == "month" ? "month_desc" : "month";
ViewBag.QuantitySortParm = sortOrder == "quantity" ? "quantity_desc" : "quantity";
ViewBag.ValueSortParm = sortOrder == "value" ? "value_desc" : "value";
model.ExposureRecords = FilterExposure(brands, disciplines, months);
model.ExposureRecords = Sort(sortOrder, model.ExposureRecords);
if (Request.IsAjaxRequest())
return PartialView("_Table", model);
return View(model);
}
My suggestion would be to use a client-side library. Sorting can be done in the controller, but in my experience, it is usually painful. I recently did what you're looking to accomplish in a project using sorttable.js, although there are several options to choose from (see Porschiey's comment above).
To use sortable, add the "sortable" class to your table. Also, be sure to run the "makesortable" js using the OnComplete property in your ajax.beginform ajaxoptions, that way the table will sort after an ajax call. Like this:
#using (Ajax.BeginForm(new AjaxOptions() {HttpMethod = "get", InsertionMode = InsertionMode.Replace, UpdateTargetId = "exposureRecords", OnComplete="makesortable"}))
{
...
}
function makesortable() {
sorttable.makeSortable(document.getElementById('exposureRecords'));
};