I am learning to use JHipster and can't figure out how to use create a custom query.
In my project I have Orders table with DeliveryDay and Week fields and want to show only orders for current day of the week. DeliveryDay and Week is int with values (1-7 and 0-2)
So in OrdersRepository.java I added custom query like this:
public interface OrdersRepository extends JpaRepository<Orders,Long> {
Page<Orders> findByDeliveryDayAndWeek(int weekday, int week, pageable);
in OrdersResource.java i added this one:
#RequestMapping(value = "/today",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<List<Orders>> getOrdersForToday(Pageable pageable)
throws URISyntaxException {
log.debug("REST request to get a page of Orderss");
Page<Orders> page = ordersRepository.findByDeliveryDayAndWeek(1, 0, pageable);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/today");
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
I also added today.html (copied orders.html) and today.js
'use strict';
angular.module('fruitcrmApp')
.config(function ($stateProvider) {
$stateProvider
.state('today', {
parent: 'entity',
url: '/today',
data: {
authorities: ['ROLE_USER'],
pageTitle: 'fruitcrmApp.orders.home.title'
},
views: {
'content#': {
templateUrl: 'scripts/app/custom/today.html',
controller: 'OrdersController'
}
},
resolve: {
translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) {
$translatePartialLoader.addPart('orders');
$translatePartialLoader.addPart('global');
return $translate.refresh();
}]
}
})
});
and add today.js in the index.html
My orders.controller.js looks like this (generated by JHipster)
'use strict';
angular.module('fruitcrmApp')
.controller('OrdersController', function ($scope, $state, Orders, OrdersSearch, ParseLinks) {
$scope.orderss = [];
$scope.predicate = 'id';
$scope.reverse = true;
$scope.page = 1;
$scope.loadAll = function() {
Orders.query({page: $scope.page - 1, size: 20, sort: [$scope.predicate + ',' + ($scope.reverse ? 'asc' : 'desc'), 'id']}, function(result, headers) {
$scope.links = ParseLinks.parse(headers('link'));
$scope.totalItems = headers('X-Total-Count');
$scope.orderss = result;
});
};
$scope.loadPage = function(page) {
$scope.page = page;
$scope.loadAll();
};
$scope.loadAll();
$scope.search = function () {
OrdersSearch.query({query: $scope.searchQuery}, function(result) {
$scope.orderss = result;
}, function(response) {
if(response.status === 404) {
$scope.loadAll();
}
});
};
$scope.refresh = function () {
$scope.loadAll();
$scope.clear();
};
$scope.clear = function () {
$scope.orders = {
details: null,
orderDate: null,
firstDelivery: null,
isActive: false,
id: null
};
};
});
Now I can access http://localhost:3000/#/today but it shows all data from Orders what I did wrong? How to use my own method from OrdersRepository.java?
I tried to search for examples but didn't found any relevant. What are the needed steps I missed? Link for some tutorial where it is covered will be great if answer will be to long.
You need to create a new angular service for your today API endpoint. Something like this, called orders-today.service.js:
'use strict';
angular.module('fruitcrmApp')
.factory('OrdersToday', function ($resource) {
return $resource('api/orders/today', {}, {
'query': { method: 'GET', isArray: true}
});
});
Then in your orders.controller.js file, you need to inject your new OrdersToday service:
.controller('OrdersController', function ($scope, $state, Orders, OrdersSearch, OrdersToday, ParseLinks) {
When you want to get the list of today's orders, you need to use OrdersToday.query just like you used Orders.query in the example you pasted.
You will probably want to create a OrdersTodayController with references to OrdersToday, and use that in today.js instead of OrdersController.
Related
i have a simple dropdown which i made with the help of select. The dropdown works fine in normal flow, but when i update my page or sometimes refresh my page the selected value in dropdown becomes empty because of the late response from the backend.
Html
<div class="col-lg-12 col-md-12" ba-panel ba-panel-title="Registration" ba-panel-class="" ng-init="driver.phoneNumberPrefixFunc();">
<div class="col-lg-12 col-md-12" ba-panel ba-panel-title="Registration" ba-panel-class="" ng-init="driver.phoneNumberPrefixFunc();driver.getVehicleTypes();driver.getUnArchBankListing()">
<form class="form-vertical" name="driver.registrationForm" ng-submit="driver.register(driver.registrationInformation);">
<select class="form-control" id="phonePrefix" name="phonePrefix" ng-model="driver.registrationInformation.phoneNumberPrefix"
required>
<option value="" selected>Select Code</option>
<option ng-repeat="item in driver.registrationInformation.phonePrefix" value="{{item.code}}">{{item.code}}</option>
</select>
</form>
</div>
Controller
function editDriverDetails() {
phoneNumberPrefixFunc();
var params = {
id: $stateParams.driverId
};
return driverServices.getDriverDetails(params).then(function (res) {
if (res.success == "1") {
driverData = res.data.driver;
driver.registrationInformation.phoneNumberPrefix = driverData.phoneNumberPrefix;
usSpinnerService.stop('spinner-1');
} else {
usSpinnerService.stop('spinner-1');
toastr.error(res.message, 'Driver');
}
});
};
editDriverDetails function gets called when I am editing my form. As you can see I am calling phoneNumberPrefixFunc() in the beginning as I need the list of phonenumber prefix. below is the function code.
function phoneNumberPrefixFunc(data) {
usSpinnerService.spin('spinner-1');
return driverServices.phoneNumberPrefix(data).then(function (response) {
if (response.success == '1') {
usSpinnerService.stop('spinner-1');
driver.registrationInformation.phonePrefix = response.data.countryCode;
} else {
usSpinnerService.stop('spinner-1');
toastr.error(response.message);
}
});
};
function phoneNumberPrefixFuncwill bring the list of objects in array for dropdown and driver.registrationInformation.phoneNumberPrefix is the preselected value which i get in editDriverDetails function. Now sometimes the response of phoneNumberPrefixFunc or editDriverDetails is late and thats why my drop down does not get populated. How can i fix this ?
I worked it out like this.
Routes.js
(function () {
'use strict';
angular.module('Driver', []).config(routeConfig);
/** #ngInject */
function routeConfig ($stateProvider, $urlRouterProvider) {
function authentication (GlobalServices, $q, localStorageService, $state) {
var d = $q.defer();
var checkUser = localStorageService.get('user');
if (checkUser !== null) {
d.resolve(checkUser);
} else {
GlobalServices.currentUser().then(function (data) {
if (data.success === 0) {
$state.go('login');
} else {
localStorageService.set('user', data.data.account);
d.resolve(data.user);
}
});
}
return d.promise;
}
function phoneNumberPrefix ($q,driverServices) {
var d = $q.defer();
driverServices.phoneNumberPrefix().then(function (data) {
d.resolve(data.data.countryCode);
});
return d.promise;
}
function getVehicleTypes ($q,driverServices) {
var d = $q.defer();
driverServices.vehicleType().then(function (data) {
d.resolve(data.data.vehicleTypes);
});
return d.promise;
}
function getUnArchBankListing ($q,bankServices) {
var d = $q.defer();
bankServices.getUnArchiveBankListing({type : 'unarchive'}).then(function (data) {
d.resolve(data.data.banks);
});
return d.promise;
}
$stateProvider
.state('drivers', {
url: '/drivers',
template: '<ui-view autoscroll="true" autoscroll-body-top></ui-view>',
abstract: true,
// controller: 'DriverMainController',
title: 'Drivers',
sidebarMeta: {
icon: 'fa fa-motorcycle',
order: 3,
},
resolve: {
$user: authentication,
phoneData : function () {},
vehcileTypesData: function () {},
banksData: function () {}
},
})
.state('driverView', {
url: '/driver/:driverId',
templateUrl: '../app/pages/driver/driverView.html',
title: 'Profile',
controller: 'driverCtrl',
controllerAs: 'profile',
resolve: {
$user: authentication,
phoneData : function () {},
vehcileTypesData: function () {},
banksData: function () {}
},
})
.state('driverEdit', {
url: '/driver-edit/:driverId',
params: {
driverDetails: null,
driverId : null
},
templateUrl: '../app/pages/driver/registration/registration.html',
title: 'Driver Profile',
controller: 'driverCtrl',
controllerAs: 'driver',
resolve: {
$user: authentication,
phoneData : function ($q, driverServices) {
var d = $q.defer();
return phoneNumberPrefix($q, driverServices);
},
vehcileTypesData: function ($q, driverServices) {
var d = $q.defer();
return getVehicleTypes($q, driverServices);
},
banksData: function ($q, bankServices) {
var d = $q.defer();
return getUnArchBankListing($q, bankServices);
}
}
});
$urlRouterProvider.when('/drivers', '/drivers/registration');
}
})();
Instead of using ng-init="driver.phoneNumberPrefixFunc();" i made sure that the page only open when the required data is loaded. Then i can access the data in controller like this .
controller.js
(function () {
angular.module('Driver').controller('driverCtrl', driverCtrl);
driverCtrl.$inject = ['$scope', '$state','phoneData','vehcileTypesData','banksData'];
function driverCtrl($scope, $state,phoneData,vehcileTypesData,banksData) {
if(phoneData){
driver.phonePrefix = phoneData;
}
if(banksData){
driver.bankListing = banksData;
}
if(vehcileTypesData){
driver.vehicleTypes = vehcileTypesData;
}
}
})();
I built a factory to get Data from the Database and pass to all controllers in my application like this:
(function () {
angular.module('appContacts')
.factory('dataService', ['$http', dataService]);
function dataService($http) {
return {
getCurrentOrganization: getCurrentOrganization,
};
function getCurrentOrganization(id) {
return $http({
method: 'GET',
url: '/api/organization/' + id + '/contacts'
})
}
}
})();
And I have a view like this:
<div ng-app="myapp">
<div ng-controller="contactController">
<a ui-sref="organization({Id: organization.id})" ng-click="vm.setCurrentOrganization(organization)"> {{organization.organizationName }}</a>
</div>
</div>
That link redirect from a view the view contactsView.html to a detail view organizationDetail.html managed by a second controller:
....
.state("home", {
url: "/",
templateUrl: "views/contactsView.html",
controller: "contactsController",
controllerAs: "vm"
})
.state("organization", {
url: "/organization/:Id",
templateUrl: "views/organizationDetail.html",
params: { Id: null },
controller: "organizationsController",
controllerAs: "vm"
})
...
My problem is that I get the data, I see in the console, but when the new URL comes into place, the Data is gone and the view is shown empty.
How could I use the data produced in the factory in the second Controller?
EDIT:
Here are the Controllers:
//organizationsController.js
(function () {
"use strict";
angular.module('appContacts')
.controller('organizationsController', function organizationsController(dataService) {
var vm = this;
vm.setCurrentOrganization = function (organization) {
vm.theOrganization = organization;
vm.visible = true;
dataService.getCurrentOrganization(vm.theOrganization.id).then(function (result) {
vm.organizationData = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});
}
});
})();
And the contactsController:
//contactsController.js
(function () {
"use strict";
angular.module('appContacts')
.controller('contactsController', function contactsController(dataService) {
var vm = this;
vm.visible = false;
activate();
function activate() {
dataService.getAllContacts().then(function (result) {
vm.allcontacts = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});
dataService.getAllOrganizations().then(function (result) {
vm.organizations = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});
}
});
})();
The problem is that I click the llink in the view A (contactsView.html/ContactsViewController) and I should end in the VIEW B (OrganizationDetails.html/organizationController), using the Data fetch in the service.
You are doing it wrong here
<div ng-app="myapp">
<div ng-controller="contactController">
<a ui-sref="organization({Id: organization.id})" ng-click="vm.setCurrentOrganization(organization)"> {{organization.organizationName }}</a>
</div>
</div>
Your contactController does not have the function setCurrentOrganization. Instead its in another controller. you can remove the code ng-click="vm.setCurrentOrganization(organization)" from the HTML. and read the id using $stateParams in the organizationsController. After getting the id, use it call the service as below:
dataService.getCurrentOrganization(id).then(function (result) {
vm.organizationData = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});
I have a main controller in which I load data into a "angular-ui-grid" and where I use a bootstrap modal form to modify detail data, calling ng-dlbclick in a modified row template :
app.controller('MainController', function ($scope, $modal, $log, SubjectService) {
var vm = this;
gridDataBindings();
//Function to load all records
function gridDataBindings() {
var subjectListGet = SubjectService.getSubjects(); //Call WebApi by a service
subjectListGet.then(function (result) {
$scope.resultData = result.data;
}, function (ex) {
$log.error('Subject GET error', ex);
});
$scope.gridOptions = { //grid definition
columnDefs: [
{ name: 'Id', field: 'Id' }
],
data: 'resultData',
rowTemplate: "<div ng-dblclick=\"grid.appScope.editRow(grid,row)\" ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
};
$scope.editRow = function (grid, row) { //edit row
$modal.open({
templateUrl: 'ngTemplate/SubjectDetail.aspx',
controller: 'RowEditCtrl',
controllerAs: 'vm',
windowClass: 'app-modal-window',
resolve: {
grid: function () { return grid; },
row: function () { return row; }
}
});
}
});
In the controller 'RowEditCtrl' I perform the insert/update operation and on the save function I want to rebind the grid after insert/update operation. This is the code :
app.controller('RowEditCtrl', function ($modalInstance, $log, grid, row, SubjectService) {
var vm = this;
vm.entity = angular.copy(row.entity);
vm.save = save;
function save() {
if (vm.entity.Id === '-1') {
var promisePost = SubjectService.post(vm.entity);
promisePost.then(function (result) {
//GRID REBIND ?????
}, function (ex) {
$log.error("Subject POST error",ex);
});
}
else {
var promisePut = SubjectService.put(vm.entity.Id, vm.entity);
promisePut.then(function (result) {
//row.entity = angular.extend(row.entity, vm.entity);
//CORRECT WAY?
}, function (ex) {
$log.error("Subject PUT error",ex);
});
}
$modalInstance.close(row.entity);
}
});
I tried grid.refresh() or grid.data.push() but seems that all operation on the 'grid' parameter is undefinied.
Which is the best method for rebind/refresh an ui-grid from a bootstrap modal ?
I finally solved in this way:
In RowEditCtrl
var promisePost = SubjectService.post(vm.entity);
promisePost.then(function (result) {
vm.entity.Id = result.data;
row.entity = angular.extend(row.entity, vm.entity);
$modalInstance.close({ type: "insert", result: row.entity });
}, function (ex) {
$log.error("Subject POST error",ex);
});
In MainController
modalInstance.result.then(function (opts) {
if (opts.type === "insert") {
$log.info("data push");
$scope.resultData.push(opts.result);
}
else {
$log.info("not insert");
}
});
The grid that received inside RowEditCtrl is not by reference, so it wont help to refresh inside the RowEditCtrl.
Instead do it right after the modal promise resolve in your MainController.
like this:
var modalInstance = $modal.open({ ...});
modalInstance.result.then(function (result) {
grid.refresh() or grid.data.push()
});
I have a property in my factory and a sync() method to update it, but when accessing from controller the value never changes.
My router: (Initialise events with resolve)
'use strict';
myApp
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('app', {
abstract: true,
views: {
'header': {
controller: 'HeaderCtrl',
templateUrl: 'views/header/_header.html'
},
'footer': {
templateUrl: 'views/footer/_footer.html'
}
}
})
.state('app.events', {
url: '^/',
views: {
'content#': {
controller: 'EventsCtrl',
templateUrl: 'views/events/_events.html',
resolve: {
postPromise: ['EventsServ', function(EventsServ) {
return EventsServ.getAll();
}]
}
}
}
})
.state('app.about', {
url: '^/sobre',
views: {
'content#': {
templateUrl: 'views/about/_about.html'
}
}
})
.state('app.contact', {
url: '^/contato',
views: {
'content#': {
controller: 'ContactCtrl',
templateUrl: 'views/contact/_contact.html'
}
}
});
}]);
My controller: (Now sync with facebook and update events)
'use strict';
myApp
.controller('EventsCtrl', ['$scope', 'EventsServ', '$filter', '$window', 'Facebook', 'postPromise', '$log', '$timeout', function($scope, EventsServ, $filter, $window, Facebook, postPromise, $log, $timeout) {
$scope.alerts = [];
$scope.events = EventsServ.all(); // <<<< Never update, keep the same value obtained in router.
$scope.periods = [{
label: 'HOJE',
labelColor: 'success',
startTime: $filter('clearTime')(new Date()),
endTime: $filter('clearTime')(new Date()),
events: []
}, {
label: 'PRÓXIMOS DIAS',
labelColor: 'primary',
startTime: $filter('clearTime')($filter('addDay')(new Date(), 1)),
endTime: $filter('clearTime')($filter('addDay')(new Date(), 8)),
events: []
}, {
label: 'PRÓXIMAS SEMANAS',
labelColor: 'warning',
startTime: $filter('clearTime')($filter('addDay')(new Date(), 9)),
events: []
}];
if (postPromise.status >= 200 && postPromise.status < 300) {
angular.forEach($scope.events, (function(event) {
var eventDate = $filter('clearTime')(event.start_time);
angular.forEach($scope.periods, (function(period) {
if (eventDate >= period.startTime && (eventDate <= period.endTime || !period.endTime)) {
period.events.push(event);
}
}));
}));
Facebook.getLoginStatus(function(response) {
if(response.status === 'connected') {
EventsServ.sync();
$log.info($scope.events);
} else {
$log.info('notLoggedIn');
}
});
} else {
$scope.alerts.push({
type: 'danger',
msg: 'Ooops! Não foi possível buscar os eventos.'
});
}
$scope.openEvent = function(event) {
$window.open('http://facebook.com/events/' + event.id, '_blank');
};
$scope.closeAlert = function(index) {
$scope.alerts.splice(index, 1);
};
}])
.filter('addDay', function() {
return function(date, days) {
return new Date(date.setDate(date.getDate() + days));
};
})
.filter('clearTime', function() {
return function(date) {
var d = new Date(date);
d.setHours(0,0,0,0);
return d;
};
});
I build my view looping through $scope.events.
My factory:
'use strict';
myApp
.factory('EventsServ', ['$http', '$q', 'Facebook', 'PagesServ', '$log', function($http, $q, Facebook, PagesServ, $log) {
var factory = {
events: []
};
factory.all = function() {
return factory.events;
};
factory.getAll = function() {
return $http.get('/events.json')
.success(function(response) {
angular.copy(response, factory.events);
})
.error(function(response) {
$log.error('Failed to get events.');
});
};
factory.sync = function() {
PagesServ.getAll().then(function(response) {
var pages = PagesServ.pages;
var events = [];
var pagesPromises = [];
var eventsPromises = [];
angular.forEach(pages, function(page, key) {
pagesPromises.push(Facebook.api(page.facebook_id, function(response) {
page.facebook_id = response.id;
page.name = response.name;
page.image = 'image.jpg';
delete page.events;
delete page.created_at;
delete page.updated_at;
}));
eventsPromises.push(Facebook.api(page.facebook_id + '/events', function(response) {
var pageEvents = response.data;
angular.forEach(pageEvents, function(event, key) {
event.page = page;
});
events = events.concat(pageEvents);
}));
});
$q.all(pagesPromises).then(function() {
$log.info(pages);
}, function(reason) {
$log.error('Failed to syncs pages: ' + reason);
});
$q.all(eventsPromises).then(function() {
factory.events = [];
angular.forEach(events, function(event, key) {
var eventSynced = {
facebook_id: event.id,
image: '',
name: event.name,
description: event.description,
start_time: event.start_time,
end_time: event.end_time,
going: 397,
address: '...',
page: event.page
}
factory.events.push(eventSynced);
});
$log.info(factory.events); // <<<<< Here the new value is correct!
}, function(reason) {
$log.error('Failed to syncs events: ' + reason);
});
});
};
return factory;
}]);
The new value of the property inside factory is correct when printing to console, but in controller the value never changes, is always [ ].
When have data I want to stay in sync between a controller and a factory, or a factory and multiple controllers, I set the data item I want to access in my controller to the object or array in the factory:
// in your controller change this
$scope.events = EventsServ.all();
// to use the object
$scope.events = EventsServ.events;
In your sync function where you are iterating over the events, push each one into a temporary array, then use angular.copy to make the update to the array available to the controller.
// at the line right before you log the events in the factory use
angular.copy(tempArray, factory.events);
$log.info(factory.events);
More info: http://www.justinobney.com/keeping-angular-service-list-data-in-sync-among-multiple-controllers/
.controller('CyclesController', function ($scope, $state) {
$scope.age = 0;
$scope.name = "";
$scope.email = "";
$scope.calculateByAge = function (age, name, email) {
$scope.data = $scope.data || {};
if (age > 0) {
$scope.data.age = age;
$scope.data.name = name;
$scope.data.email = email;
$state.go('tab.cycles-detail');
}
}
})
.controller('CyclesDetailController', function ($scope, $stateParams, CyclesService) {
console.log('scope data', $scope.data); // <--- undefined.
})
This may be a dumb question, but can get to get the data from the form on the CyclesDetailController controller.
If it's simple property you could do it by routing. Just change your "tab.cycles-detai' to 'tab.cycles-detai/:age' in your ui-router configuration and pass it when you're redirecting: $state.go('tab.cycles-detail', {age: age});
in 'CyclesDetailController' access it by $stateParams.age;
e.g:
//app.config
//...
.state('tab.cycles-detail', {
url: "^detail/{age:int}",
controller: 'CyclesDetailController',
templateUrl: "url_for_detail_template"
})
//...
// CyclesController
.controller('CyclesController', function ($scope, $state) {
$scope.age = 0;
$scope.calculateByAge = function (age) {
$scope.data = $scope.data || {};
if (age > 0) {
$scope.data.age = age;
$state.go('tab.cycles-detail', {age: age);
}
}
})
//CyclesDetailController
.controller('CyclesDetailController', function ($scope, $stateParams, CyclesService) {
console.log('scope data', $stateParams.age);
})
//
If you want to pass data from one route to another but dont want to expose it in browser menu bar, you can use squash.
Example -
.state('app.enroll', {
url: '/enroll/',
params: {
classId: {
value: null,
squash: true
},
className: {
value: null,
squash: true
}
},
title: 'Students Enrollment',
templateUrl: helper.basepath('enroll.html')
})
2nd Technique -
You can use localStorage / cookies to save data and retrieve at later stage.
3rd Technique -
You can always share data via services/factory in between controllers.