0

I am new to angularjs and I have a very small app that loads contacts from my server. The code snippet here is the complete app.js. The problem is that I can't figure out how to do the server call with sync. In the code snippet, when I refresh the page, alert 3 is displayed, then alert 2, and then finally alert 4. The function is immediately returning since the server http call take some time to do. So what I get in the browser is a display of the 2 test item in the array "contacts". Alert 4 finally comes along, but it is too late. Any help would be appreciated.

var module = angular.module('app', []);

module.service('ContactService', function ($http) {

    //contacts array to hold list of all contacts - 2 entries for test

    //var $contacts = [];
    var contacts = [
        {
        id: 0,
        'First_Name': 'Harmon',
        'Last_Name': 'Adams',
        'Home_Phone': '123-2343-44'
        },
        {
            id: 1,
            'First_Name': 'Sam',
            'Last_Name': 'Spade',
            'Home_Phone': '123-2343-44'
        }
    ];

    // returns the contacts list
    this.list = function () {
    //    var contacts = [];
        $http.post('http://localhost/Contacts7/GetData.php', {'cat' : 'Friends'}).
            success(function(data)  {
                contacts =  data.datarecords;
                alert('4 - within $post - '+contacts);
            }).
            error(function(data, status){
                alert('error!');
            });
        alert('3 - before return - '+contacts);
        return contacts;
    }
});

module.controller('ContactController', function ($scope, ContactService ) {
    $scope.contacts = ContactService.list();
    alert('2 - after list - '+ $scope.contacts);
});
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title>Contact Dialer </title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link href="css/style.css" rel="stylesheet">
</head>
<body>
<div ng-app="app" ng-controller="ContactController">

    <div class="container" >
    <div class="row row-centered">
        <div class="col-md-2 button-row col-centered">
            <button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Favorites')">Favorites</button>
        </div>
        <div class="col-md-2 button-row col-centered">
            <button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Friends')">Friends</button>
        </div>
        <div class="col-md-2 button-row col-centered">
            <button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Loose Friends')">Loose Friends</button>
        </div>
        <div class="col-md-2 button-row col-centered">
            <button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Loose_Loose Friends')">Loose-Loose Friends</button>
        </div>
        <div class="col-md-2 button-row col-centered">
            <button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Business')">Business</button>
        </div>
        <div class="col-md-2 button-row">
        </div>
    </div>
        {{xxx}}
        <table class='table table-striped table-bordered'>
            <th class = 'text-center'>Name</th>
            <th class = 'text-center'>Home Phone</th>
            <th class = 'text-center'>Mobile Phone</th>
            <th class = 'text-center'>Bus. Phone</th>
            </tr>
            <tr ng-repeat='contact in contacts'>
                <th class = 'text-center' >{{contact.Last_Name}}, {{contact.First_Name}}</th>
                <td class = 'text-center'>{{contact.Home_Phone}}</td>
                <td class = 'text-center'>{{contact.Mobile_Phone}}</td>
                <td class = 'text-center'>{{contact.Business_Phone}}</td>
            </tr>
        </table></div>
    </div>
<script src="js/jquery-1.11.0.min.js"></script>
<script src="js/underscore-min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/angular.min.js"></script>
<script src="js/angular-route.min.js"></script>
<script src="js/app.js"></script>
</body>
</h

2 Answers 2

3

You can't return contacts from your service because contacts is going to be determined asynchronously. Instead you need to return a promise for the contacts, which you can use to populate your controller's contacts when they are done being retrieved.

Service:

module.service('ContactService', ['$http', function ($http) {
    return {
        list: function () {
            return $http.post('http://localhost/Contacts7/GetData.php', 
                              {'cat' : 'Friends'})
            .then(function (response) {
                return response.data.datarecords;
            })
            .catch(function (error) {
                throw new Error("Failed to retrieve contacts!");
            });
        }
    };
}]);

Note You may have noticed that I changed the first line from using the magic dependency injection style to using the array-style dependency injection. This is just my personal preference (because I consider the magic DI style to be a bad idea), and not something that you have to do. The same applies to the code below.

Controller:

module.controller('ContactController', ['$scope', 'ContactService',
                                        function ($scope, ContactService ) {
    $scope.contacts = [];
    ContactService.list()
    .then(function (contacts) {
        $scope.contacts = contacts;
        alert('2 - after list - '+ $scope.contacts);
    });
}]);
Sign up to request clarification or add additional context in comments.

8 Comments

This answer is good but why did you change his DI syntax to array syntax?
@BenjaminGruenbaum Because using the magic DI syntax is an antipractice.
Yeah, but in my humble opinion it is best not to make subjective changes to OP's code - having advised to several Angular workshops in the past I'd say they are divided roughly equally between people using the array syntax and people using ng-min (now ng-annotate). I would definitely not call it "abuse of the language" or an antipattern per se - after all minifiers are tooling themselves and are not 'above frameworks' - when the minifiers make assumptions about source code that are not viable here the minifiers are at fault.
Fair enough, you're well within your right to promote whatever practices you'd like in your answers - but Function#toString is part of the language specification (15.3.4.2) and changing Function.prototype.toString is as bad as changing Function.prototype.apply which basically breaks everything in modern JS engines. Most other languages I know let you get parameter names too: C#, Java (8), Python, Ruby and really most modern high level languages. I guess I just disagree it's a loophole: minifiers are the ones jumping through hoops but again - you're entitled to your favorite practices :)
@BenjaminGruenbaum If JavaScript provided a clean mechanism for getting parameter names (and it's almost surprising that it doesn't), then I would be on board with magic DI. The .toString() approach just seems way too hacky to me (though you may well be right that my concerns here are unfounded). C#'s nameof() is still in beta. JS may well get something similar before long, and if that happens and magic DI is updated to use that, it will get my un-coveted seal of approval and it will be the minifiers' turn to get in line with what's considered acceptable use.
|
0

Don't return contacts object from outside ajax. It should be return contacts object from its success callback.

// returns the contacts list
this.list = function () {
//    var contacts = [];
$http.post('http://localhost/Contacts7/GetData.php', {'cat' : 'Friends'}).then(
//success call back
function(data)  {
    contacts =  data.datarecords;
    alert('4 - within $post - '+contacts);
    return contacts;
},
//error call back
function(data, status){
    //error handling can be done here
    alert('error!');
    return;
});

Hope this may help full to you.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.