Search code examples
phpangularjsangular-nvd3

Why can't I update a variable value in an AngularJS service from a controller?


I'm using an AngularJS service to get JSON data from a PHP page in order to render an Angular NVD3 chart.

At first, the whole page works fine, but then when I use HTML buttons to change the value of the parameter, the data won't update/change accordingly.

<h1>Infográficos</h1>
<div class="btn-group btn-group-sm">
    <button type="button" ng-click="mudaValorDoFiltro('ma')" class="btn btn-default">Macrossegmento</button>
    <button type="button" ng-click="mudaValorDoFiltro('es')" class="btn btn-default">Esfera</button>
    <button type="button" ng-click="mudaValorDoFiltro('mo')" class="btn btn-default">Modalidade</button>
    <button type="button" ng-click="mudaValorDoFiltro('st')" class="btn btn-default">Status</button>
</div>
<nvd3 options="options" data="data"></nvd3>

Since I want to create an AngularJS NVD3 chart, I needed to include the following code too:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.5/nv.d3.min.css">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.11/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.5/nv.d3.min.js"></script>
<script src="bower_components/angular-nvd3/angular-nvd3.min.js" type="text/javascript"></script>

As you can see, ng-click calls a fnction that changes the value of $scope.filtro in the controller.

.controller('InfograficosCtrl', ['$scope', 'InfograficosServico' , function($scope, InfograficosServico) {
    $scope.options = {
        chart: {
            type: 'discreteBarChart',
            height: 450,
            margin: {
                top: 20,
                right: 20,
                bottom: 50,
                left: 55
            },
            x: function (d) {
                return d.label;
            },
            y: function (d) {
                return d.value;
            },
            showValues: true,
            valueFormat: function (d) {
                return d3.format(',.0f')(d);
            },
            duration: 500,
            xAxis: {
                axisLabel: 'Macrossegmento'
            },
            yAxis: {
                axisLabel: 'Quantidade',
                axisLabelDistance: -10
            }
        }
    };

    // This is the data that come from a PHP pade through an AngularJS service
    $scope.data = [];

    // This is the default value to $scope.filtro
    $scope.filtro = "ma";

    // This is the function that I'm using to get the values from the button
    $scope.mudaValorDoFiltro = function(novoValorDoFiltro){
        $scope.filtro = novoValorDoFiltro;
    };
    $scope.$watch('filtro', function(filtro){
        $scope.filtro = filtro;
        console.log(filtro); // The variable is being updated when I click the buttons
    });

    // The data in the service is NOT being updated
    InfograficosServico.barChart({filtro: $scope.filtro}).then(function(data) {
        // This is the AngularJS NVD3 object
        $scope.data = [{
            key: "Quantidade de projetos por macrosssegmento",
            values: data
        }];
    });
}]);

Here is the full code of the service

.factory('InfograficosServico', ['$q', '$http', function ($q, $http) {
    return {
        barChart: function(filtro){
            var defer = $q.defer();
            $http.get(
                'api/bar-chart.php',
                {
                    cache: 'true',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    params: {
                        filtro: filtro.filtro
                    }
                }
            )
            .success(function(data) {
                defer.resolve(data);
            });

            return defer.promise;
        }
    };
}]);

I don't understand why the data is not being updated, but the variable is being watched successfully in the controller.

What am I doing wrong?

Excuse any English mistakes.


Solution

  • I suppose what you want is to update $scope.data, so... here it is my guess:

    The changes are being watched properly, but you're not doing anything about it.

    In your watcher you have to take action and update the value like this:

    $scope.$watch('filtro', function(filtro){
            $scope.filtro = filtro;
            console.log(filtro); // The variable is being updated when I click the buttons
           //now do something about it, and update the values with the new filter
           _update();
        });
    

    ...and your _update function then call the service again

    function _update(){
        // The data should be updated now
        InfograficosServico.barChart({filtro: $scope.filtro}).then(function(data) {
            // This is the AngularJS NVD3 object
            $scope.data = [{
                key: "Quantidade de projetos por macrosssegmento",
                values: data
            }];
        });
    }