0

I have a trouble with $http.get. When my service.js access my MVC Controller, the $http.get don't wait for response. How can I do $http.get wait MVC Controller response? My code.

AngularJS Service:

angular.module("cadastroCliente").factory("clientesAPI", function($http) {
var getClientes = function () {
    return $http.get("http://localhost:39732/Cadastro/BuscarClientes/");
};

return {
    getClientes: getClientes
};
});

ControllerJS - Edited

angular.module("cadastroCliente").controller("cadastroClienteCtrl", function ($scope, $http, $q, $timeout, clientesAPI) {
$scope.app = "Pesquisar Clientes";
$scope.clientes = [];

var carregarClientes = function () {
    clientesAPI.getClientes().success(function (data) {
        $scope.clientes = data;
    }).error(function (data, status) {
        $scope.message = "Aconteceu um problema: " + data;
    });
};

carregarClientes();

$scope.totalItems = $scope.clientes.length;
$scope.itemsPerPage = 2;
$scope.currentPage = 1;

$scope.maxSize = 5;
$scope.bigTotalItems = 175;
$scope.bigCurrentPage = 1;

$scope.pageCount = function () {
    return Math.ceil($scope.clientes.length / $scope.itemsPerPage);
};

$scope.$watch('currentPage + itemsPerPage', function () {
    var begin = (($scope.currentPage - 1) * $scope.itemsPerPage),
        end = begin + $scope.itemsPerPage;

    $scope.filteredClientes = $scope.clientes.slice(begin, end);
});
});

View:

<div class="table-responsive">
                        <table class="table table-bordered table-hover table-striped" id="clienteId">
                            <thead>
                                <tr>
                                    <th class="col-lg-1">Código</th>
                                    <th class="col-lg-7">Nome</th>
                                    <th class="col-lg-3">Documento</th>
                                    <th class="col-lg-1">Extrato</th>
                                </tr>
                            </thead>
                            <tbody ng-repeat="cliente in filteredClientes">
                                <tr>
                                    <td>{{cliente.ClienteId}}</td>
                                    <td>{{cliente.Nome}}</td>
                                    <td>{{cliente.CpfCnpj}}</td>
                                    <td style="cursor: pointer"><i class="glyphicon glyphicon-search"></i></td>
                                </tr>
                            </tbody>
                        </table>
                    </div>

                    <uib-pagination total-items="totalItems" items-per-page="itemsPerPage" ng-model="currentPage" ng-change="pageChanged()"></uib-pagination>
  • Try to change **this** `return $http.get("http://localhost:39732/Cadastro/BuscarClientes/");` **for**: `return $http.get("http://localhost:39732/Cadastro/BuscarClientes/").then(function(response) { return response.data; });` and see what happens. – developer033 Jul 10 '16 at 02:54
  • Why do you say it won't wait for response? What happens? – charlietfl Jul 10 '16 at 03:08
  • I want get response from getClientes() and use in another function, but the response is empty – Alexandre Bueno Jul 10 '16 at 03:38
  • Need to explain that in more detail. The code shown [works fine here](http://plnkr.co/edit/FF1Ijs2c4AEC1glgWWse) – charlietfl Jul 10 '16 at 03:40
  • When i put data direct in service to simule a response, works fine, but when i call the mvc controller to get data, the response is empty. I think it's the controller response time. – Alexandre Bueno Jul 10 '16 at 03:54
  • But did you see that it works in the above link (with very minor changes of variable name and source path)? There is something you aren't telling us or showing us – charlietfl Jul 10 '16 at 03:55
  • Well now you removed the call to service and we can't see where this new code gets called in relation to that success callback. You can't check the length of `$scope.clientes` until you receive it in the callback. Are you seeing any errors in console? – charlietfl Jul 10 '16 at 04:10
  • OK....this all boils down to not understanding that `$http` is asynchronous. The data hasn't arrived when you start setting things like `$scope.totalItems`. You need to move that into the success callback – charlietfl Jul 10 '16 at 04:17
  • Go through this for a detailed explanation of the problem http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – charlietfl Jul 10 '16 at 04:19
  • Nice, this fix my problem. Thanks @charlietfl – Alexandre Bueno Jul 10 '16 at 04:21
  • 1
    @AlexandreBueno good lesson learned for future issues you might ask questions about ... to show all relevant code. The missing code caused a lot of confusion. See [mcve] – charlietfl Jul 10 '16 at 04:28

2 Answers2

1

You can't set $scope.totalItems until the data has arrived which means you need to set it in the success callback where you assign $scope.clientes from the response data.

$http is an ajax request and the first A in ajax is for "asynchronous"

Note that success and error are deprecated and you should be using the recommendation in documentation to use the promise callbacks then() and catch()

charlietfl
  • 170,828
  • 13
  • 121
  • 150
0

I suggest that you put as much logic pertaining to the request in your factory as possible, including handling the response:

var getClientes = function () {
  return $http.get("http://localhost:39732/Cadastro/BuscarClientes/")
    .then(function(res) {
      return res.data
    });
};

Also don't forget that the get request returns the response object, and that you might need to return the data property on the response (if that's what you need). You should also favor the .then() method on promises.

In es6 we can make this very precise and also catch any errors like so:

var getClientes = () => {
  return $http.get("http://localhost:39732/Cadastro/BuscarClientes/")
    .then(({data}) => data)
    .catch(({data}) => console.log(data.message));
};

In your controller we can then do this:

var carregarClientes = function () {
  clientesAPI.getClientes()
    .then(function (data) {
      $scope.clientes = data;
    })
};

In es6:

var carregarClientes = () => {
      clientesAPI.getClientes()
        .then(data => $scope.clientes = data);
    };

EDIT: Response to update code in OP Unfortunately, anything pertaining to clientes should be done in the callback of the request:

var carregarClientes = function () {
  clientesAPI.getClientes()
    .then(function (data) {
      $scope.clientes = data;
      //Assign any other variables
    })
};

The reason being, is that all your code in the controller referencing clientes is referencing the original empty array and not the data from the request. This is because it's outside of the call. Therefore, that code is run while the request is being made. If you place it inside the callback it has access to the returned data once it arrives.

hsiung
  • 217
  • 1
  • 5