Highcharts send global data to angular controller - angularjs

I've recently decided to use angular on a webpage, but having never used it before and being new to web dev I've run into some issues. The page has some highchart graphs where, upon clicking on a point triggers a modal with a table of data. This table is created with an angular controller.
Initially the table is empty because the user hasn't selected the data to populate it. So the data called: cases starts:var cases = []; and the controller initializes with: $scope.items = cases;
Here is where I get the data for the table:
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function () {
if (this.series.name == 'Work left')
{
cases = [];
//GET THE DATA
$.getJSON(uri + '/get?team=' + team + '&sprint=' + sprint + '&day=' + this.category)
.done(function (data) {
$.each(data, function (n, field) {
n++
cases.push({ "DT": field.dt, "Title": field.subject, "Type": field.type, "Est": field.est, "Product": field.Prod, "Sprint": field.Sprint, "Status": field.Status, "CreatedDate": field.cDate });
});
});
//UPDATE THE TABLE WITH NEW DATA HERE
$("#myModal").modal();//TRIGGER MODAL
}
}
}
}
}
}
In this highchart function I get the parameters: team,sprint and day based off of which point on which graph the user clicked. Then get the data from an api call.
What I want to know is if it's possible to "reinitialize" the angular controller at //UPDATE THE TABLE WITH NEW DATA HERE line, before triggering the modal. I need $scope.items = cases; but with cases being populated with the new data.
Basically I get the data dynamically with a highchart function, and I want to send this data to the angular controller where the table is updated, so that when I trigger the modal the table on it has the specified data.
Angular table controller:
var sortingOrder = 'CreatedDate'; //default sort
var app = angular.module("casetable", []);
app.controller('initApp', ['$scope', '$filter',
function ($scope, $filter) {
// init
$scope.sortingOrder = sortingOrder;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 9;
$scope.pagedItems = [];
$scope.currentPage = 0;
$scope.items = cases;
var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
// init the filtered items
$scope.search = function () {
$scope.filteredItems = $filter('filter')($scope.items, function (item) {
for (var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
if ($scope.sortingOrder !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
// show items per page
$scope.perPage = function () {
$scope.groupToPages();
};
// calculate page in place
$scope.groupToPages = function () {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [$scope.filteredItems[i]];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
}
}
};
$scope.deleteItem = function (idx) {
var itemToDelete = $scope.pagedItems[$scope.currentPage][idx];
var idxInItems = $scope.items.indexOf(itemToDelete);
$scope.items.splice(idxInItems, 1);
$scope.search();
return false;
};
$scope.range = function (start, end) {
var ret = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
// functions have been describe process the data for display
$scope.search();
// change sorting order
$scope.sort_by = function (newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
};
}]);

Related

Angularjs State transition

I am building a hybrid mobile app using ionic framework and cordova (first time).I am having problems with state transition because by default angular renders the template before completing the transition.This makes the the app look slow (when you click a menu item and wait for it to come).This happens only for those who load data from local storage or service! My Question is: How can I make the template come empty in the moment I click the menu item , then show a loader until the template is ready.Below is some code is use in my menu controller for the state transition!
//I use ng-click="navigateTo('state name')"
$scope.navigateTo = function (stateName) {
$timeout(function () {
$mdSidenav('left').close();
if ($ionicHistory.currentStateName() != stateName) {
$ionicHistory.nextViewOptions({
disableAnimate: false,
disableBack: true
});
$state.go(stateName);
}
}, ($scope.isAndroid == true ? 1000 : 0));
};// End navigateTo.
Below is the controller code for the view that needs a solution
appControllers.controller("calendar_Ctrl", function($scope,$rootScope, $state,$stateParams, $ionicHistory, $filter, $q, $timeout, $log, MaterialCalendarData, $moment) {
$scope.isAnimated = $stateParams.isAnimated;
$scope.selectedDate = null;
$scope.weekStartsOn = 0;
$scope.dayFormat = "d";
$scope.disableFutureDates = false;
$scope.directionn = "horizontal";
$scope.setDirection = function(direction) {
$scope.directionn = direction;
$scope.dayFormat = direction === "vertical" ? "EEEE, MMMM d" : "d";
};
$scope.dayClick = function(date) {
$scope.msg = "You clicked " + $filter("date")(date, "MMM d, y h:mm:ss a Z");
};
$scope.setContentViaService = function() {
var today = new Date();
MaterialCalendarData.setDayContent(today, '<span> :oD </span>')
}
$scope.getItems = function(){
if(localStorage.getItem("eventsData")){
var eventsData = localStorage.getItem("eventsData");
return JSON.parse(eventsData);
}else{
return [];
}
}
var events = $scope.getItems();
// You would inject any HTML you wanted for
// that particular date here.
var numFmt = function(num) {
num = num.toString();
if (num.length < 2) {
num = "0" + num;
}
return num;
};
var loadContentAsync = false;
$log.info("setDayContent.async", loadContentAsync);
$scope.setDayContent = function(date) {
var key = [date.getFullYear(), numFmt(date.getMonth()+1), numFmt(date.getDate())].join("-");
var data = (events[key]||[{ type: ""}]);
if (loadContentAsync) {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve(data);
});
return deferred.promise;
}
return data;
};
$scope.isAnimated = $stateParams.isAnimated;
});
Thank You Very Much for your time and help!!
Hi Use $ionicLoading Service to solve this problem,
http://ionicframework.com/docs/api/service/$ionicLoading/

ng-infinite scroll angular setting offset

Need to keep track of my offset so that I can get the next set each time either scroll or click 'Load more'. It improves performance. I am trying out here by setting offset and limit and passing as request params to my node server,but how to update or increment after that limit using offset:
my url as: /foo?limit=7&&offset=0;
My angular controller function as:
$scope.findDetails = function(){
var limit = 10;
var offset = 0;
//DataService.getUsers(limit,offset).then(function(customerdetails){
DataService.getUsers({limit,offset},function(customerdetails){
$scope.customers = customerdetails;
}, function(error){
$scope.status = 'Unable to load customer data: ' + error.message;
});
};
You must keep the offset in the scope of the controller and update the offset every time the infinite directive request more records to display:
$scope.limit = 10;
$scope.offset = 0;
//bind this function to the ng-infinite directive
$scope.infiniteScrollFunction = function() {
$scope.offset += $scope.limit;
$scope.findDetails();
};
$scope.findDetails = function() {
DataService.getUsers({limit: $scope.limit,offset: $scope.offset},
function(customerdetails){
...
}
var $scope.height = $('#div-height').height()
var flag = false;
var $scope.customers = []
$(window).scroll(function() {
if ($(this).scrollTop() > $scope.height-2000) {
if (!flag) {
flag = true;
refreshCustomers();
}
}
});
function refreshCustomers() {
DataService.getCustomers().then(function (data) {
$scope.customers = $scope.customers.concat(data);
setTimeout(function () {
$scope.height = $('#div-height').height();
flag = false
}, 0.1);
});
}
In DataService
factory.getCustomers = function(){
return $http.get(...api......&&limit=7).then(function (results) {
var customers = results.data.customers;
return customers;
});
};
Now after the window is scrolled up to certain height(windowHeight-2000px), the api is called again to get data. The previous data is being concatenated with present data.

AngularJS custom filter don't receive data

I have a problem with a new filter which don't receive the data:
here my error log:
Controller Code:
angular.module('reklaApp')
.controller('MainCtrl', function ($scope, $http, Reklas, Modal) {
$scope.newRekla = {};
Reklas.getAll()
.success(function(data) {
$scope.reklas = data;
});
Filter Code:
angular.module('reklaApp')
.filter('dateFilter', function () {
return function (items) {
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
filtered.push(item);
}
return filtered;
};
});
HTML Code:
<tr ng-repeat="rekla in reklas | dateFilter">
<td>{{rekla.dt | date: 'dd.MM.yyyy'}}</td>
<td>{{rekla.order}}</td>
<td>{{rekla.personal}}</td>
<td>{{rekla.department}}</td>
<td>{{rekla.xyz}}</td>
<td>{{rekla.desc | limitTo: '50'}}</td>
<td>{{rekla.costs}}</td>
I think the "item" variable dont receive the data from the ng-repeat!?
It's because you didn't create it to begin with on your $scope. So since your getAll function takes some time the filter doesn't have the data. You can fix this two ways:
By first initializing the variable:
angular.module('reklaApp')
.controller('MainCtrl', function ($scope, $http, Reklas, Modal) {
$scope.newRekla = {};
$scope.reklas = [];
Reklas.getAll()
.success(function(data) {
$scope.reklas = data;
});
Or by updating your filter:
angular.module('reklaApp')
.filter('dateFilter', function () {
return function (items) {
if(!angular.isArray(items)){ return items }
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
filtered.push(item);
}
return filtered;
};
});

AngularJS paging

I made AngularJS pagination with spring mvc It works well ,but the application get a large amount of data from database so the application is very slow when I get first page because it get all records,Can anyone help me to solve this problem?I want to get subset of data from database depending on angularJS pagination
Spring mvc Controlller
#RequestMapping(value = "/rest/contacts",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<Contact> getAll() {
return contactRepository.findAll();
}
AngularJS Service
pagingpocApp.factory('Contact', function ($resource) {
return $resource('app/rest/contacts/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': { method: 'GET'}
});
});
AngularJS Controller
pagingpocApp.controller('ContactController', function ($scope, $filter,resolvedContact, Contact, resolvedRole) {
$scope.contacts = resolvedContact;
var sortingOrder = 'firstName';
$scope.sortingOrder = sortingOrder;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 10;
$scope.pagedItems = [];
$scope.currentPage = 0;
var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
// init the filtered items
$scope.search = function () {
$scope.filteredItems = $filter('filter')($scope.contacts, function (item) {
for(var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
if ($scope.sortingOrder !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
// calculate page in place
$scope.groupToPages = function () {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
}
}
};
$scope.range = function (start, end) {
var ret = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
// functions have been describe process the data for display
$scope.search();
// change sorting order
$scope.sort_by = function(newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
// icon setup
$('th i').each(function(){
// icon reset
$(this).removeClass().addClass('icon-sort');
});
if ($scope.reverse)
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-up');
else
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-down');
};
});
One quick option would be to create a get method on your API that only returns a subset of the data, maybe only 25 contacts at a time, or a page or two worth of data. Then you could create a service in angular that makes that get call every 3 seconds or so to get the next 25 contacts. A sort of lazy loading technique.
Ben Nadel does a great job in this article of outlining how his company handles large sets of images being loaded to a page using a lazy loading technique. Reading through his example could give you a nice starting point.
Edit: I'm also going to recommend you refer to this solution for an answer slightly more on point to what you're looking to achieve. He recommends pushing data to your controller as soon as it's found:
function MyCtrl($scope, $timeout, $q) {
var fetchOne = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve([random(), random() + 100, random() + 200]);
}, random() * 5000);
return deferred.promise;
};
$scope.scans = [];
for (var i = 0; i < 2; i++) {
fetchOne().then(function(items) {
angular.forEach(items, function(item) {
$scope.scans.push(item);
});
});
};
}

Load data to dropdown in angularjs

I am new to this angular js.
In my code a dropdown control has been loaded with some items, i know this list should be loaded from a xml file.
I want to know where/how it is been coded to load the data. Check this code and help me...
<select size="10" ng-model="model.addSelection" ng-options="a.name for a in availableList | availableList | propertyFilter:model.availableFilter" class="listBoxStyle" wat-focus/>
angular.module('readbackSelectModule', [])
.filter('availableList', [
function () {
return function (input) {
if (!angular.isArray(input)) return input;
var out = [];
for (var i = 0; i < input.length; i++) {
if (input[i].visible == true)
out.push(input[i]);
}
return out;
}
}
])
.filter('plotList', [
function () {
return function (input) {
if (!angular.isArray(input)) return input;
var out = [];
for (var i = 0; i < input.length; i++) {
if (input[i].visible == false)
out.push(input[i]);
}
return out;
}
}
])
.controller('readbackSelectCtrl', ['$scope', '$modalInstance', 'generalDataService', 'keyService', 'propertyFilterFilter', 'availableListFilter', 'plotListFilter', 'plotPanelService',
function ($scope, $modalInstance, generalDataService, keyService, propertyFilterFilter, availableListFilter, plotListFilter, plotPanelService) {
var CANCEL_MESSAGE = 'cancel';
var GET_DATA_MESSAGE = 'getdata';
var REQUEST_PROPERTY_LIST_MESSAGE = 'requestplotdata';
var SUBSCRIBE = 'plotsubscribe';
var UNSUBSCRIBE = 'plotunsubscribe';
var STREAM_TYPE = '4';
$scope.model = {};
$scope.model.addSelection;
$scope.model.removeSelection;
$scope.model.availableFilter;
// List of properties
$scope.availableList = [];
};
Use Angular's $http service.
You can do it in your readbackSelectCtrl, like this:
...
$scope.model = {};
$scope.model.addSelection;
$scope.model.removeSelection;
$scope.model.availableFilter;
$http.get(/** insert XML file URL here **/)
.success(function(data) {
// process the data and extract the XML elements you want
$scope.availableList = xmlExtractedArray;
})
.error(function(err) {
// handle error
});
Check this plunker for a working demo.

Resources