0

I've been avoiding asking this here as there are loads of examples out there but I have no idea what's I'm doing wrong. I'm trying to put a little angular app in place but I'm struggling to get it working pass the very basics.

I want to get a little CRUD happening but using a reasonable clean structure that I could use as a template for other apps. I've found millions of examples but only using controllers and I found millions of examples on how to implement and DI services. I'm now trying to put them together but no joy.

Here we go.

I have a simple accounts.html

<h1>Accounts</h1>

<div ng-controller="AccountController">
    <div>
        <table>
            <tr>
                <td>Name</td>
                <td>Description</td>
                <td>number</td>
                <td>accountType</td>
                <td>Delete</td>
            </tr>

            <tr ng-repeat="acct in accounts">
                <td>{{acct.name}}</td>
                <td>{{acct.description}}</td>
                <td>{{acct.number}}</td>
                <td>{{acct.accountType}}</td>
                <td>{{delete(acct)}}</td>
            </tr>
        </table>
    </div>

    <hr>

    <div>
        <div>
            Name:<input type="text" ng-model="account.name">
        </div>
        <div>
            Description:<input type="text"
                ng-model="account.description">
        </div>
        <div>
            Number:<input type="text" ng-model="account.number">
        </div>
        <div>
            Account Type:<select ng-model="account.accountType">
                <option ng-repeat="acctType in accountTypes">{{acctType}}</option>
            </select>
        </div>
    </div>  

    <div>
        <input type="button" value="Save" ng-click="save()">
        <input type="button" value="Cancel">
    </div>
</div>

<!-- Angular JS -->
<script src="assets/thirdparty/angular/1.4.8/js/angular.js"></script>

<!-- App Angular JS -->
<script src="assets/local/js/angular/accounts-app.js"></script>
<script src="assets/local/js/angular/controller/AccountController.js"></script>
<script src="assets/local/js/angular/service/RefDataService.js"></script>

An AccountController.js

(function() {

'use strict';

var app = angular.module('accounts-app', ['account-service']);
app.controller('AccountController', ['$scope', 'RefDataService', function($scope, RefDataService) {

    $scope.accountTypes = RefDataService.refData.accountTypes;

    var account = {
        'name' : '',
        'description' : '',
        'number' : '',
        'accountType' : ''
    };

    $scope.account = account;
    $scope.accounts = [];

    $scope.save = function save() {
        $scope.accounts.push(this.account);
        $scope.account = {
            'name' : '',
            'description' : '',
            'number' : '',
            'accountType' : ''
        };

    };

}]);

})();

And a RefDataService.js

(function() {

    'use strict';

    var serviceModule = angular.module('account-service', []);

    serviceModule.service ('RefDataService', ['$http', 
        function($http) {
            var url = 'http://localhost:8080/accounts-rest/api/refdata';

            var refData = {};

            refData.accountTypes = {};
            refData.accountTypes = function() {
                return $http.get(url + '/accounttypes');
            }

            return refData;

    }]);
})();

I'm trying to load the account types from the rest and populate the select dropdown. I've tried and changed everything I could to make it happen but I either get a console error or no error but an empty dropdown as well.

Ideally, in a real application, this refDataService would load, as the name says, reference data. Advice on how to improve it are welcome.

halfer
  • 19,824
  • 17
  • 99
  • 186
Desorder
  • 1,549
  • 12
  • 16

2 Answers2

2

You're trying to use accountTypes as an object/array:

$scope.accountTypes = RefDataService.refData.accountTypes;

...but you've defined it as a function in your controller:

refData.accountTypes = function() {
    return $http.get(url + '/accounttypes');
}

Additionally, it looks like you're expecting $http.get() to return the data directly - it actually returns a promise with the response of the request as an argument. You need to use it like this (assuming your REST call returns the object you need):

$http.get(url + "accounttypes").then(function (response) {
    refData.accountTypes = response;
});
Joe Clay
  • 33,401
  • 4
  • 85
  • 85
  • Yes. If I call accounts-rest/api/refdata/accounttypes directly on my browser, it returns ["type1","type2","type3"] – Desorder Feb 08 '16 at 23:48
  • @JúliusRetzer Not really. I'm not sure what to change... My JS skill go as far as JQuery to manipulate elements. – Desorder Feb 09 '16 at 00:05
  • Then yeah, I'd say the best approach would be to create a `loadAccountTypes` function within RefDataService which handles updating the state of the accountTypes array. Although be careful - the way you're binding your array to the scope now (`$scope.accountTypes = RefDataService.refData.accountTypes;`) means that if the array gets replaced within your service, the version in your scope won't update, as it's still referencing the old version. You're better off doing `$scope.refData = RefDataService.refData;` – Joe Clay Feb 09 '16 at 00:10
  • Give me a few minutes and I'll put together some example code for you. – Joe Clay Feb 09 '16 at 00:12
  • https://jsfiddle.net/u1az5zj6/3/ - Obviously it won't fully function, as the HTTP request is looking for a URL that doesn't exist, but hopefully this will point you in the right direction. The main mistake I found in your code was that you are returning `refData` from your service function and expecting this to equal `RefDataService.refData` in your controller, when in reality whatever you return in the service function will _become_ the service. I'd recommend running through the tutorial on the Angular website - it covers a lot of this stuff! – Joe Clay Feb 09 '16 at 00:30
  • I'd recommend looking at Július Retzer's answer, actually, his code example is a little better than mine. – Joe Clay Feb 09 '16 at 00:35
  • Yep. Now it's working. Also it needs to be response.data. :) – Desorder Feb 09 '16 at 00:58
2

Here is a working plunker.

app.controller('AccountController', ['$scope', 'RefDataService', function($scope, RefDataService) {
RefDataService.accountTypes().then(function(response){
  $scope.accountTypes = response;
});

$scope.account = {
    'name' : '',
    'description' : '',
    'number' : '',
    'accountType' : ''
};
$scope.accounts = [];

$scope.save = function save() {
    $scope.accounts.push($scope.account);
    $scope.account = {
        'name' : '',
        'description' : '',
        'number' : '',
        'accountType' : ''
    };

};

}]);

var serviceModule = angular.module('account-service', []);

serviceModule.service ('RefDataService', ['$http',
    function($http) {
        var url = 'http://localhost:8080/accounts-rest/api/refdata';

        this.accountTypes = function() {
            return $http.get(url + '/accounttypes');
        }
}]);

Things I changed:

  • Your RefDataService declaration looked more like factory than service (you should read about the difference for example [here])(AngularJS: Service vs provider vs factory). Module.service expects a constructor function which is on injection invoked with new operator so here I attach accountTypes method to this
  • In your controller you then use the service as Joe Clay described in his answer
  • I fixed $scope.accounts.push(this.account); to $scope.accounts.push($scope.account);. You would use this.account if you were using the controllerAs syntax.
Community
  • 1
  • 1
Július Retzer
  • 1,055
  • 1
  • 10
  • 25
  • Joe's last comment helped getting working but your answer also gave me another perceptive. Also, response is the promise as Joe said, we need to get the data from that. – Desorder Feb 09 '16 at 00:57