Oliver Watkins
Oliver Watkins

Reputation: 13539

Dynamically set data on Angular-chart.js

To be honest I am a bit new to angularjs, so this may be problem with my fundamental understanding of angular, rather than angular-charts.

I have two controllers (PieItemsCtrl and PieCtrl) and I would like to communicate between them by using a factory service (called pieItems)

On the one hand the pieItems works as designed in the PieItemsCtrl.

ie:

$scope.slices =  pieItems.list();

Whenever something changes in the pieItems service (ie another element is added), then the HTML is automatically updated via a repeater :

<div ng-repeat="(key, val) in slices">

However in the PieCtrl I have this line, and i would expect the pie chart to update automatically :

$scope.labels = pieItems.labelsItems();
$scope.data = pieItems.data();

It seems to set these data values upon loading/initialisation of the PieCtrl and that's it. Whenever the pieItems data changes these scope values are not updated.

The source of the two controller and factory object are below. And I also made an unworkable fiddle, incase that helps

PieItemsCtrl :

app.controller('PieItemsCtrl', function($scope, $http, $rootScope, pieItems) {

        $scope.slices =  pieItems.list();
        $scope.buttonClick = function($event) {
            pieItems.add(
                {
                    Name: $scope.newSliceName,
                    Percent: $scope.newSlicePercent,
                    Color: $scope.newSliceColor
                }
            )
        }

        $scope.deleteClick = function(item, $event) {
            pieItems.delete(item);
        }
    } 
)

PieCtrl :

app.controller("PieCtrl", function ($scope, $timeout, pieItems) {
    $scope.labels = pieItems.labelsItems();
    $scope.data = pieItems.data();
});

pieItems :

app.factory('pieItems', function() {
    var items = [];

    var itemsService = {};

    itemsService.add = function(item) {
        items.push(item);
    };
    itemsService.delete = function(item) {

        for (i = 0; i < items.length; i++) {
            if (items[i].Name === item.Name) {
                items.splice(i, 1);
            }
        }
    };
    itemsService.list = function() {
        return items;
    };

    itemsService.labelsItems = function() {

        var a = ['x', 'y'];
        for (i = 0; i < items.length; i++) {
            a.push(items[i].Name);
        }
        return a;
    };
    itemsService.data = function() {

        var a = [50,50];
        for (i = 0; i < items.length; i++) {
            a.push(items[i].Percent);
        }
        return a;
    };

    return itemsService;
});

Upvotes: 1

Views: 3043

Answers (1)

CMR
CMR

Reputation: 933

The controller doesn't notice when the value in your factory changes. To include your item-Array in an Angular digest-cycle, tell Angular to $watch that Array.

If you don't want to expose the Array, create a getter:

itemsService.get = function() { return items; }

Then you can include that getter in your $watch expression in your controller:

$scope.$watch(getItems, watcherFunction, true);
function getItems() {
    return pieItems.get();
}

The getItems-Function gets called on digest cycle and fires the watcherFunction if the value changed and has the newData as argument. true as 3rd argument creates a deep watch.

function watcherFunction(newData) {
     console.log(newData);
     // do sth if array was changed
}

For more complex objets, you can use a $watchCollection.

Upvotes: 1

Related Questions