Angular : load lots of data via directive causing browser issue - angularjs

I have an angular directive loading a svg map (using amchart) where I add thousands of svg circles. In the end everything works but my browser seems in pain and I would need to (1) optimize my loading and (2) display a loading symbol that could last till the map can actually display for real.
Today I use this kind of directive attribute to know when my directive is loaded :
directive('initialisation',['$rootScope',function($rootScope) {
return {
restrict: 'A',
link: function($scope) {
var to;
var listener = $scope.$watch(function() {
clearTimeout(to);
to = setTimeout(function () {
listener();
$rootScope.$broadcast('initialised');
}, 50);
});
}
};
Well this is not good to me as my loading symbol (angular-material) freezes, and then disappear to leaves an empty browser for a few seconds, before the map can render. For information I use ng-hide on the loading div and ng-show on the map div, and this is the way I apply it :
$scope.$on('initialised', function() {
$scope.$apply(function(){
$scope.mapLoaded = true;
});
})
Do you know a way to solve my (1) and (2) issue ? Or should I look for another js library to do this?
Thank you
PS : here is my map directive (images is an array with 20k entry at the moment) :
directive('amChartsLanguage', function() {
return {
restrict: 'E',
replace:true,
template: '<div id="mapLanguage" style="height: 1000px; margin: 0 auto"> </div>',
link: function(scope, element, attrs) {
var chart = false;
var initChart = function() {
if (chart) chart.destroy();
var images = [];
var legendData = [];
for(var i=0 ; i < scope.languageZeppelin.length ; i ++ ) {
images.push( {
"type": "circle",
"width": 7,
"height": 7,
"color": scope.languageZeppelin[i].color,
"longitude": scope.languageZeppelin[i].lon,
"latitude": scope.languageZeppelin[i].lat
} );
}
var legend = new AmCharts.AmLegend();
legend.width="10%";
legend.height="300";
legend.equalWidths = false;
legend.backgroundAlpha = 0.5;
legend.backgroundColor = "#FFFFFF";
legend.borderColor = "#ffffff";
legend.borderAlpha = 1;
legend.verticalGap = 10;
legend.top = 150;
legend.left = 70;
legend.position = "left";
legend.maxColumns = 1;
legend.data = scope.legend;
// build map
chart = AmCharts.makeChart( "mapLanguage", {
"type": "map",
"areasSettings": {
"unlistedAreasColor": "#15A892",
"autoZoom": true,
"selectedColor": "#FFCC00",
"color": "#909090"
},
"dataProvider": {
"map": "worldLow",
"getAreasFromMap": true,
"images": images,
"zoomLevel": 1,
"zoomLongitude": 6,
"zoomLatitude": 11
},
"export": {
"enabled": false
}
} );
chart.addLegend(legend);
chart.validateNow(legend);
};
initChart();
}
}
})

we have angular with a lot more data on the page. with poor design og architechture. loading ofcoarse too long but after that performance is great. we use d3

Related

Load more button in AngularJS and lightGallery

I am using lightGallery for a website and I wanted to add a "load more" button to the gallery page, mostly for faster loading on mobile phones. I found various methods and tried them. Most of them don't work and/or doesn't suit my need for loading the elements on request.
One of them was with AngularJS:
var DemoApp = angular.module("DemoApp", []);
DemoApp.controller("DemoController",
function DemoController($scope) {
$scope.quantity = 0;
$scope.temp = [];
$scope.loadMore = function () {
for (i = $scope.quantity; i <= $scope.quantity + 1; i++) {
$scope.temp.push($scope.images[i]);
}
$scope.quantity = i;
}
$scope.images = [{
"src": "https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13244856_238092939903469_3778800896503555327_n.jpg?oh=e539748b060ba0cb43852314e2fdef0b&oe=57F01511"
}, {
"src": "https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13263891_238096316569798_4073904852035872297_n.jpg?oh=91a76b3515ac628706b912fdd3e9a346&oe=585C3DD1"
}, {
"src": "https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13260007_238096336569796_6324932140560503740_n.jpg?oh=1795ba25c4604dced3cdcc91b9729cc7&oe=5820EE5A"
}, {
"src": "https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/12871473_238096353236461_8115646425269026926_n.jpg?oh=b8958326d24a1a649e6a40adf29b062b&oe=582BFD38"
}, {
"src": "https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13256520_238096376569792_9057528716929719317_n.jpg?oh=a6bc66f75992c88260ae35bd4dbc9ff1&oe=5856F934"
}, {
"src": "https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13254297_238096389903124_1429633590050411734_n.jpg?oh=5e8c94a0b6a77dea110704a5727e0ee5&oe=5819B551"
}, {
"src": "https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13267713_238096416569788_8740461856631991826_n.jpg?oh=739e3268996e498f65867b314265250b&oe=585E4C93"
}];
$scope.loadMore();
});
And this is my HTML mark up:
<div class="col-xs-12">
<div ng-app="DemoApp" ng-controller="DemoController">
<div id="fotoalbum" class="col-thumb-wrap">
<div class="col-thumb" ng-repeat="image in temp" data-src="{{image.src}}">
<a href="{{image.src}}">
<i class="thumb" style="background-image: url({{image.src}});"></i>
</a>
</div>
</div>
<button class="btn btn-default" ng-click="loadMore()">Ik wil meer</button>
</div>
</div>
The "load more" button it self worked, however it broke the lightGallery itself.
Example: http://cytex.nl/projects/jk-installaties/album2.php
Then I found the solution for making lightGallery work with AngularJS in this StackOverflow question
I tried to combine the two but it still doesn't work. Now lightGallery gets fired up OK, but the "load more" button doesn't do anything!
Example: http://cytex.nl/projects/jk-installaties/album1.php
var DemoApp = angular.module('DemoApp', []);
DemoApp.controller('DemoController',
function DemoController($scope, $sce) {
$scope.total = 0;
$scope.temp = [];
$scope.loadMore = function () {
for (x = $scope.total; x <= $scope.total + 1; x++) {
$scope.temp.push($scope.photos[x]);
}
$scope.total = x;
}
$scope.photos = [{
fullres: 'https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13244856_238092939903469_3778800896503555327_n.jpg?oh=e539748b060ba0cb43852314e2fdef0b&oe=57F01511'
}, {
fullres: 'https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13263891_238096316569798_4073904852035872297_n.jpg?oh=91a76b3515ac628706b912fdd3e9a346&oe=585C3DD1'
}, {
fullres: 'https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13260007_238096336569796_6324932140560503740_n.jpg?oh=1795ba25c4604dced3cdcc91b9729cc7&oe=5820EE5A'
}, {
fullres: 'https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/12871473_238096353236461_8115646425269026926_n.jpg?oh=b8958326d24a1a649e6a40adf29b062b&oe=582BFD38'
}, {
fullres: 'https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13256520_238096376569792_9057528716929719317_n.jpg?oh=a6bc66f75992c88260ae35bd4dbc9ff1&oe=5856F934'
}, {
fullres: 'https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13254297_238096389903124_1429633590050411734_n.jpg?oh=5e8c94a0b6a77dea110704a5727e0ee5&oe=5819B551'
},{
fullres: 'https://scontent-ams3-1.xx.fbcdn.net/v/t1.0-9/13267713_238096416569788_8740461856631991826_n.jpg?oh=739e3268996e498f65867b314265250b&oe=585E4C93'
}];
$scope.loadMore();
for (var i = 0; i < $scope.photos.length; i++) {
$scope.photos[i].fullres = $sce.trustAsResourceUrl($scope.photos[i].fullres);
}
})
.directive('lightgallery', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
if (scope.$last) {
element.parent().lightGallery({
showThumbByDefault: false
});
}
}
};
});
I am very new to AngularJS,so I'm sorry if this is a really stupid question. Could you guys help to identify the problem and maybe pointers on how to tackle this?
Append this fragment of your code to the last row of loadMore function:
for (var i = 0; i < $scope.photos.length; i++) {
$scope.photos[i].fullres = $sce.trustAsResourceUrl($scope.photos[i].fullres);
}
This part should be run each time you add an item to the array, It means this should be run each time the function loadMore triggers.
Hope this will be helpfull. Regards.
For others who ran into this issue:
The answer of Ramin Esfahani is of course correct. But you also have to destroy the lightGallery data ever time the "Load More" button is clicked. This is in done in the directive part. Of course change the "#fotoalbum" to your own ID or class. This is the code:
.directive('lightgallery', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
if (scope.$last) {
element.parent().lightGallery({
showThumbByDefault: false
});
$('#LoadMore').on('click', function(){
$('#fotoalbum').data('lightGallery').destroy('true');
$('#fotoalbum').lightGallery({
showThumbByDefault: false
});
});
}
}
};
})

Angular how to correctly destroy directive

I have a 'regionMap' directive that includes methods for rendering and destroying the map. The map is rendered inside of a modal and upon clicking the modal close button the 'regionMap' destroy method is called, which should remove the element and scope from the page. However, when returning to the modal page, that includes the 'region-map' element, the previous 'region-map' element is not removed, resulting in multiple maps being displayed. What is the correct way to remove the regionMap directive from the page when the modal is closed?
// directive
(function(){
'use strict';
angular.module('homeModule')
.directive('regionMap', regionMap);
function regionMap() {
var directive = {
restrict: 'E',
template: '',
replace: true,
link: link,
scope: {
regionItem: '=',
accessor: '='
}
}
return directive;
function link(scope, el, attrs, controller) {
if (scope.accessor) {
scope.accessor.renderMap = function(selectedRegion) {
var paper = Raphael(el[0], 665, 245);
paper.setViewBox(0, 0, 1100, 350, false);
paper.setStart();
for (var country in worldmap.shapes) {
paper.path(worldmap.shapes[country]).attr({
"font-size": 12,
"font-weight": "bold",
title: worldmap.names[country],
stroke: "none",
fill: '#EBE9E9',
"stroke-opacity": 1
}).data({'regionId': country});
}
paper.forEach(function(el) {
if (el.data('regionId') != selectedRegion.name) {
el.stop().attr({fill: '#ebe9e9'});
} else {
el.stop().attr({fill: '#06767e'});
}
});
}
scope.accessor.destroyMap = function() {
scope.$destroy();
el.remove();
}
}
}
}
})();
// controller template:
<region-map accessor="modalvm.accessor" region-item="modalvm.sregion"></region-map>
// controller:
vm.accessor = {};
...
function showMap() {
$rootScope.$on('$includeContentLoaded', function(event) {
if (vm.accessor.renderMap) {
vm.accessor.renderMap(vm.sregion);
}
});
function closeMap() {
if (vm.accessor.destroyMap) {
vm.accessor.destroyMap();
}
$modalInstance.dismiss('cancel');
}
The issue is related to loading a template with a directive inside of it. Fixed it by adding a var to check if the map has previously been rendered:
vm.accessor.mapRendered = false;
$rootScope.$on('$includeContentLoaded', function(event) {
if (vm.accessor.renderMap && !vm.accessor.mapRendered) {
vm.accessor.renderMap(vm.selectedRegions);
vm.accessor.mapRendered = true;
}
});

Angular directive for D3 datamap rendering only once

So, I made an Angular directive which renders a D3 datamap in an HTML template. I pass the data to the directive via a 'data' attribute. The problem I am facing is that the map displays perfectly when the page is loaded for the first time. However, when I come back to the template by navigating from other templates (routing done through 'ui-route'), the map doesn't get rendered and there is no error in the console either. Here's my directive:
app.directive('stabilityMap', function() {
var containerid = document.getElementById('world-map-container');
var margin = 20,
padding = 50,
width = containerid.offsetWidth - margin;
height = containerid.offsetHeight - margin;
return {
restrict: 'A',
scope: {
data: '=',
},
link : function(scope, element, attrs) {
scope.$watch('data', function(newVal, oldVal) {
var colorScale = d3.scale.linear().domain([50, 100]).range(['#ff0000', '#280000']);
var Fills = {defaultFill: '#ddd'};
var Data = {};
var countries = Datamap.prototype.worldTopo.objects.world.geometries;
for(var i = 0; i < newVal.length; i++) {
for (var j = 0; j < countries.length; j++) {
if(countries[j].properties.name == newVal[i].Country) {
Fills[countries[j].id] = colorScale(newVal[i]['Stability Index']);
Data[countries[j].id] = { fillKey : countries[j].id};
}
}
}
var map = new Datamap({
element: containerid,
responsive: true,
projection: 'mercator',
setProjection: function(element) {
var projection = d3.geo.mercator()
.center([0, padding])
.scale(105)
.translate([element.offsetWidth / 2, element.offsetHeight / 2 - 70]);
var path = d3.geo.path()
.projection(projection);
return {path: path, projection: projection};
},
fills: Fills,
data: Data
})
d3.select(window).on('resize', function() {
map.resize();
});
})
}
}
})
Here's my angular controller for the template:
app.controller('CountryCtrl', ['$scope', '$http', function($scope, $http) {
$scope.countriesData = [
{'Country': 'Australia', 'Stability Index':'85'},
{'Country':'United States of America', 'Stability Index':'90'},
{'Country':'Russia', 'Stability Index':'70'},
{'Country':'India', 'Stability Index':'84.2'},
{'Country':'China', 'Stability Index':'50'}
]
}]);
Here's the HTML template:
<div class="row" id="world-map">
<div stability-map data="countriesData" id="world-map-container">
</div>
</div>
Here is the screenshot when the page is loaded first:
And the empty container after I come back to the page after navigating from some other template of the website.
Any idea what's happening?
the map doesnt get rendered again, because the function is only run once, when the code is first executed. I suggest you wrap your creation of the map inside a function and call that function every time you load the page (from the controller).
$scope.renderMap = function() {
var map = new Datamap({
element: containerid,
responsive: true,
projection: 'mercator',
setProjection: function(element) {
var projection = d3.geo.mercator()
.center([0, padding])
.scale(105)
.translate([element.offsetWidth / 2, element.offsetHeight / 2 - 70]);
var path = d3.geo.path()
.projection(projection);
return {path: path, projection: projection};
},
fills: Fills,
data: Data
})
}
The code you will then need to render the map is the following:
$scope.renderMap()
I hope this helps.
xoxo
I found the answer to this. You have to put your variables inside your link function. This means moving
var containerid = document.getElementById('world-map-container');
var margin = 20,
padding = 50,
width = containerid.offsetWidth - margin;
height = containerid.offsetHeight - margin;
right inside your link function. This solved the problem for me.

Multiple instances of custom directive, confusion with ngModel

I've created a custom directive to render a slider for a question (essentially wrapping jquery ui slider). The directive takes an ngModel and updates it when the user uses the slider, and there's a $watch attached to the parent model (the ngModel passed to the directive is only a part of a parent model). The directive has multiple instances on a page.
I've encountered an issue with the watch, as it seems as the watch always occurs on the last question on the page. So for example a page with 10 question, using the slider on question 1 - triggers the watch on the last question (question 10). I believe the issue has something to do with directives/isolated scope and/or the watch function, but I'm unable to solve it.
this.app.directive('questionslider', () => {
var onChangeEvent = (event, ui) => {
updateModel(ui.value);
};
var onSlideEvent = (event, ui) => {
updateUi(event, ui);
};
var updateUi = (event, ui) => {
$(ui.handle).find(".ff-handle-glyph > div").css("top", (ui.value) * - 10);
}
var updateModel = (newValue) => {
// find value in values list...
angular.forEach(isolatedScope.model.PossibleValues, function(value) {
if (parseInt(value.Name) === newValue) {
isolatedScope.$apply(function() {
isolatedScope.model.Value = value;
});
}
});
};
var isolatedScope: any;
return {
restrict: 'AE',
replace: true,
template: '<div></div>',
scope: {
model: '=ngModel',
},
link: function(scope, element, attrs, ctrl) {
isolatedScope = scope;
scope.$watch(ngModelCtrl, function() {
// use provided defaultValue if model is empty
var value = isolatedScope.model.Value === null ? isolatedScope.model.DefaultValue : isolatedScope.model.Value;
element.slider({
min: 0,
max: isolatedScope.model.PossibleValues.length,
value: value.Name,
change: onChangeEvent,
slide: onSlideEvent
});
}
}
};
};
Code to add watch in controller
this.$scope.questions.forEach(function(question) {
this.$scope.$watch(
function() { return question; },
function(newVal, oldVal) { this.updateQuestion(newVal, oldVal) },
true
);
});
UpdateQuestion function (right now just outputting current question)
function updateQuestion(newVal, oldVal) {
// prevent event on initial load
if (newVal === oldVal) {
return;
}
console.log(newVal);
}
The ng-repeat markup instantiating questionsliders
<div data-ng-repeat="question in Questions">
<h4>{{question.QuestionText}}</h4>
<p>{{question.RangeMinText}}</p>
<questionslider ng-model="question"></questionslider>
<p>{{question.RangeMaxText}}</p>
</div>
Question JSON would look like this
{
"DefaultValue": {
"Id": "5",
"Name": "5"
},
"Id": "1",
"IsAnswered": false,
"PossibleValues": [
{
"Id": "1",
"Name": "1"
},
{
"Id": "2",
"Name": "2"
},
{
"Id": "3",
"Name": "3"
},
{
"Id": "4",
"Name": "4"
},
{
"Id": "5",
"Name": "5"
},
{
"Id": "6",
"Name": "6"
},
{
"Id": "7",
"Name": "7"
},
{
"Id": "8",
"Name": "8"
},
{
"Id": "9",
"Name": "9"
},
{
"Id": "10",
"Name": "10"
}
],
"QuestionText": "hows it haning?",
"RangeMaxText": "not good",
"RangeMinText": "Very good",
"Type": 0,
"Value": null
}
],
"Title": "Question title",
"Type": 0
}
So issue is, no matter which question I update with the slider directive, it's always the last on page passed into updateQuestion.
UPDATE
I tried using $watchCollection, but nothing seems to fire the event.
this.$scope.$watchCollection(
'questions',
function (newVal, oldVal) {
// prevent event on initial load
if (newVal === oldVal) {
return;
}
for (var i = 0; i < newVal.length; i++) {
if (newVal[i] != oldVal[i]) {
this.$log.info("update : " + newVal.Id);
}
}
}
);
I also tried with
function() { return questions; }
as first expressions. Still no luck.
Maybe using individual controllers for each question is my only option, but it seems a bit of a workaround.
UPDATE
So i tried using individual controllers for each question, adding a watch per question in the controller, and the strange thing is that even this is reproducing same scenario. It's still the last question on the page passed into the watch function.
markup
<div data-ng-repeat="question in Questions" data-ng-controller="QuestionInstanceController">
<h4>{{question.QuestionText}}</h4>
<p>{{question.RangeMinText}}</p>
<questionslider ng-model="question"></questionslider>
<p>{{question.RangeMaxText}}</p>
</div>
Controller code
app.controller('QuestionInstanceController', function($scope) {
console.log($scope.question); // outputs correct question here!
$scope.$watch(
function() { return $scope.question; },
function(newValue, oldValue) {
console.log(newValue); // always outputs last question on page
},
true);
}
}
It must have something to do with my custom directive, am i somehow overwriting previous instances when having multiple instances on the page?
So i managed to find the solution myself. The issue was that i had a "var isolatedScope;" in the directive which was assigned on every run of the link(). I thought vars declared in the directive were isolated on each instance but infact they are overwritten on every implementation of the directive.
The solution therefore was to move the implementation of onChange directly to the init of the slider component, and thus avoiding the need of access to the scope variable later
this.app.directive('questionslider', () => {
var onChangeEvent = (event, ui) => {
};
var onSlideEvent = (event, ui) => {
updateUi(ui.value, ui.handle);
};
var updateUi = (value, element) => {
}
var onStartSlide = (event, ui) => {
}
var onEndSlide = (event, ui) => {
}
return {
restrict: 'AE',
require: 'ngModel',
replace: true,
templateUrl: 'templates/questionSlider.html',
scope: {
model: '=ngModel'
},
link: (scope: any, element, attrs, ngModelCtrl: ng.INgModelController) => {
scope.$watch(ngModelCtrl, () => {
// use provided defaultValue if model is empty
var value = scope.model.Value === null ? scope.model.DefaultValue : scope.model.Value;
var hasNoValue = scope.model.Value === null;
if (hasNoValue) {
element.find('.ui-slider-handle').addClass('dg-notset');
}
element.slider({
min: parseInt(scope.model.PossibleValues[0].Name),
max: scope.model.PossibleValues.length,
value: parseInt(value.Name),
slide: onSlideEvent,
start: onStartSlide,
stop: onEndSlide,
animate: true,
change: (event, ui) => {
// find value in values list...
angular.forEach(scope.model.PossibleValues, (val) => {
if (parseInt(val.Name) === ui.value) {
scope.$apply(() => {
scope.model.Value = val;
});
}
});
onChangeEvent(event, ui);
}
});
});
}
};
});
I expect that your $scope.$watch logic is throwing you off. The simplest way might be to put a watch on the entire array of questions using $watchCollection:
$scope.$watchCollection(questions, function(newValue, oldValue) {
for(index=0; index<newValue.length; index++) {
if (newValue[index] !== oldValue[index]) {
console.log("Question " + index + " updated to: " + newValue[index]);
}
}
});
Otherwise, you could probably create a separate controller for each item in your ng-repeat loop and have a watch there that deals with the change. I don't love this solution, either, as it's kinda long-winded. First, a new controller for dealing with the questions:
app.controller('QuestionCtrl', function($scope) {
$scope.$watch('question', function(newValue, oldValue) {
if (newVal === oldVal) {
return;
}
console.log(newVal);
}
});
With your view slightly modified to include a reference to the new QuestionCtrl:
<div data-ng-repeat="question in Questions" ng-controller='QuestionCtrl'>
<h4>{{question.QuestionText}}</h4>
<p>{{question.RangeMinText}}</p>
<questionslider ng-model="question"></questionslider>
<p>{{question.RangeMaxText}}</p>
</div>
This article gives more information about using controllers with ng-repeat.
I hope one of these helps you out.

How to redraw flot chart in angularjs?

I am using flot chart Angularjs directive to draw a stacked bar chart. When I make a async call to an end point to fetch data for chart, it is unable show up. I suspect it needs to redraw. There is a draw() function which looks like re draws flot chart. Please help me re-draw my flot chart in Angularjs.
<flot dataset="tasksRunData" options="tasksRunChartOptions" class="center-block" width="100%" height="400px" id="reportTasksRunRange.id"></flot>
angular.module('myApp').controller('Step2Controller', function($scope, $location, $interval, dialogs, $modal, $transition, ReportingService) {
...
$scope.tasksRunData = mainArray;
$scope.tasksRunChartOptions = {
legend: {
show: true,
margin: 2
},
xaxis: {
ticks: yaxisArray,
alignTicksWithAxis: "right"
},
grid: {
labelMargin: 10,
hoverable: true,
borderWidth: 0
},
series: {
stack: true
},
colors: colorCodesArray,
tooltip: true
};
...
$scope.redrawTasksRunDataHistoByChart();
...
$scope.redrawTasksRunDataHistoByChart = function() {
$scope.tasksRunData.draw(); //TypeError: undefined is not a function
alert("AAAA");
}
});
Update
ReportService.getTasksRunDateHistoByType().then(function(result) {
$scope.renderTasksRunDateHistoByType(result);
});
$scope.renderTasksRunDateHistoByType = function(jsonInput) {
console.log(json[RUN_AGG_BY_DATE_HISTO].aggregations[TASK_TYPE_AGG].buckets);
var yaxis = [];
var buckets = json[RUN_AGG_BY_DATE_HISTO].aggregations[TASK_TYPE_AGG].buckets;
var log = [];
var mainArray = [];
var colorCodes = ["#5C832F","#7B52AB","#263248","#AB1A25","#FF8598","#AB1A25","#FEB41C","#193441","#193441","#BEEB9F","#E3DB9A","#917A56"],
idx = 0;
angular.forEach(buckets, function(value, key) {
this.push(key + ': ' + value +", "+value["key"]);
var dataArray = [], index = 0;
console.log(JSON.stringify(value[RUN_OVER_TIME_KEY]["buckets"]));
angular.forEach(value[RUN_OVER_TIME_KEY]["buckets"], function(value, key) {
var dataArr = [];
dataArr.push('['+index+', '+value["doc_count"]+']');
dataArray.push(dataArr);
yaxis.push(JSON.parse('['+index+', "'+$scope.translate(value["key"])+'", "'+value["key"]+'"]'));
index++;
}, log);
var barObject = '"bars": {"show": "true", "barWidth":0.8, "fillColor": "'+colorCodes[idx]+'", "order": 1, "align": "center"}';
var object = '{ "data": ['+dataArray+'], "label": "'+value["key"]+'", '+barObject+'}';
mainArray.push(JSON.parse(object));
idx++;
}, log);
console.log(yaxis);
$scope.tasksRunData = mainArray;
$scope.tasksRunChartOptions = {
legend: {
show: true,
margin: 2
},
xaxis: {
//ticks:[[0,'Oct 4'],[1,'Oct 5'],[2,'Oct 6'],[3,'Oct 7'],[4,'Oct 8'],[5,'Oct 9']],
ticks: yaxis,
alignTicksWithAxis: "right"
},
grid: {
labelMargin: 10,
hoverable: true,
borderWidth: 0
},
series: {
stack: true
},
colors: colorCodes,
tooltip: true
};
};
angularjs service
angular.module('myApp')
.service('ReportService', function ReportService($http, $q) {
var getTasksRunDateHistoByType = function() {
var deferred = $q.defer();
$http({
method: 'POST',
url: "http://localhost:4040/reports/taskRun",
data: '{ "client_user_info": { "client_id": "MU03"}}'
}).
success(function(result, status, headers, config) {
deferred.resolve(result);
}).
error(function(result, status, headers, config) {
console.log("Error");
});
return deferred.promise;
};
return {
getTasksRunDateHistoByType: getTasksRunDateHistoByType
};
});
Looking at the source code to the directive, it'll redraw automatically when $scope.dataset changes.
$scope.redrawChart = function() {
var tmp = [];
for (var i = 0; i < 10; i++){
tmp.push([i,Math.random() * 10]);
}
$scope.dataset = [{ data: tmp }];
};
Here's an example.
EDITS FOR UPDATES
I'm having a hard time following your code, but in the end, you'll end up in the $scope.renderTasksRunDateHistoByType with data in the variable jsonInput. You then store some variable mainArray (which doesn't exist as far as I can tell) into other $scope level variables. I never see you assign data back to $scope.dataset. This is what the flot directive is watching to trigger a redraw. It's just that simple.
$scope.renderTasksRunDateHistoByType = function(jsonInput) {
$scope.dataset = [{
data: jsonInput
}];
//console.log(jsonInput);
//$scope.tasksRunData = mainArray;
//$scope.tasksRunChartOptions
//getting data here once response is received from server
};
See updates here.

Resources