4

I have just came up with a directive that loads a dropdown box according to a list coming from an API call ($resource).

Controller:

App.controller(
'TestCtrl', [
'$scope', 'countriesFactory',
function($scope, countriesFactory){

        /* Call API */
        countriesFactory().then(function(data){
              $scope.countryList = data;
        });

}])

The API call returns:

{"country":[{"code":"ABW","label":"Aruba"},{"code":"AFG","label":"Afghanistan"},{"code":"AGO","label":"Angola"}]}

Template:

<input-select model-ref-list="countryList"></input-select>

Directive:

App
.directive("inputSelect"
, function() {

    var Template =
        '<select ng-options="item.label for item in modelRefList" required></select>';

    return {
        restrict: 'EA',
        template: Template,
        scope: {
            modelRefList: '='       
        },
        link: function(scope){
          console.log(scope.modelRefList);
        }
      };
   }
);

First of all: I simplified a lot the overall issue, so that it looks that the directive is completely overkill in that situation, but in the end, it is not :D.

Problem: My console.log is always undefined.

I made a bit of research and realized that I needed to play with promises to wait for my country list to appear to be actually given to the directive. So I tried modifying my controller and not use the result of the API call promise, but directly the resource itself:

New Controller:

App.controller(
'TestCtrl', [
'$scope', 'countriesFactory',
function($scope, countriesFactory){

        /* Call API */
        $scope.countryList = resourceAPICall();

}])

But still undefined :/.

How can I pass direclty the resource (containing the promise I can then use to defer the load of the select) to the directive?

SOLUTION FOR ANGULARJS 1.2:

Directive:

App
.directive("inputSelect"
, function() {

    var Template =
        '<select ng-options="item.label for item in modelRefList" required></select>';

    return {
        restrict: 'EA',
        template: Template,
        scope: {
            modelRefList: '='       
        },
        link: function(scope){
           scope.modelRefList.$promise.then(function(data){
                    console.log(data);
           }
      };
   }
);

To pass a API call result to a directive, you need to pass its resource and play with its promise inside the directive itself.

Thanks everybody for the help.

5
  • If you don't have any other logic in that directive, definitely it's overkill you can do the same just adding the template contents in the view. Commented Dec 2, 2013 at 16:51
  • Can you provide countriesFactory or at least expected countryList you get Commented Dec 2, 2013 at 16:54
  • Where is resourceAPICall defined? Commented Dec 2, 2013 at 16:58
  • @EvertonYoshitani Yes I know... That is what I wrote as a warning. Commented Dec 2, 2013 at 17:00
  • @MaximShoustin I updated the API response, but it's not very important. What is important is just that it is a $resource. Commented Dec 2, 2013 at 17:02

2 Answers 2

5

Here we simulated async call factory by using wrapper with $q.

  • We changed modelReflist to modelRefList
  • added ng-model="item" to template

HTML

<div ng-controller="TestCtrl">
    <input-select model-ref-list="countryList"></input-select>    
</div>     

JS

var App = angular.module('myModule', ['ngResource']);

App.controller(
    'TestCtrl', [
    '$scope', 'countriesFactory',

function ($scope, countriesFactory) {
    /* Call API */
    countriesFactory.resourceAPICall().then(function (data) {

        $scope.countryList = data.country;

         console.log($scope.countryList);
    });
}])

App.$inject = ['$scope', 'countriesFactory'];


App.directive("inputSelect", function () {
    var Template = '<select ng-model="item" ng-options="item.label as item.label for item in modelRefList" required></select>';
    return {
        restrict: 'EA',
        template: Template,
        scope: {
            modelRefList: '='
        },
        link: function (scope) {
            console.log(scope.countryList);
        }
    };
});

App.factory('countriesFactory', ['$resource', '$q', function ($resource, $q) {
    var data = {
        "country": [{
            "code": "ABW",
            "label": "Aruba"
        }, {
            "code": "AFG",
            "label": "Afghanistan"
        }, {
            "code": "AGO",
            "label": "Angola"
        }]
    };

    var factory = {
        resourceAPICall: function () {
            var deferred = $q.defer();

            deferred.resolve(data);
            return deferred.promise;
        }
    }
    return factory;
}]);

Demo Fiddle

Sign up to request clarification or add additional context in comments.

6 Comments

I am actually using angular 1.2, so there is already a promise inside the resource object. The problem is that the resource is not given to the directive, for some reason :/.
And gj for the fiddle, you did that pretty fast :D.
But if you look carefully, the log still states "undefined".
@user2425491, sure, it happens because you call link before got data. To make it work in link, pass service to directive and write callback (...then(...)) into the link. Or add $watch there
That's my point, when I pass the resource to the directive as shown in example, I can't get the promise, it is undefined. I thought when I pass the service directly to the directive, it will immediately allow me to get its promise, whereas the data is not there yet. Am I wrong?
|
1

modelReflist needs to be fully camel-cased in your directive scope. modelRefList.

1 Comment

Indeed, very good point, I updated the code and retested, but same result :/, undefined.

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.