Kyle V.
Kyle V.

Reputation: 4792

Accessing Fetched Resources From a Controller?

In my AngularJS controller I'm trying to do something relatively simple: I'm trying to populate a <select> element dynamically in the controller. To do so I need to wait for my localized UI text data to be loaded and data from my server to be loaded and this is causing a problem for me.

What my HTML Looks like:

<select 
data-ng-model="group"
data-ng-options="options.value as options.label for options in userGroups">
<option>--</option>
</select>

Then my controller is actually implementing a base controller "class" which allows me to share logic between controllers:

// exampleController.js
myModule.controller('exampleController',
    ['$scope', '$timeout', '$routeParams', '$controller',
        function ($scope, $timeout, $routeParams, $controller) {
            // Instantiate the base controller class and set it's scope 
            // to this controller's scope. This is how the base and child
            // controllers will share data and communicate.
            var base = $controller('baseController', { $scope: $scope });
}]);

And here is a relevant snippet of the baseController:

// baseController.js
$scope.getDataFromUrl = function (url, cache, successFunction) {
    $http.get(url, { cache: cache })
    .success(function (data) {
        if (!handleErrorInData(data))
        {
            successFunction(data);
        }
    });
};

$scope.getDataFromUrl(uiTextResourceUrl, true, function (data) {
    $scope.uiText = data;
});

So baseController fetches the text resources when it loads and sets it to the scope when it's finished retrieving the data. exampleController on the other hand will fetch other data from the server via the getDataFromUrl() function defined in baseController like so:

$scope.getDataFromUrl(dataUrl, false, function (data) {
    // Do stuff with the returned data...
};

My issue is coming from this part of the exampleController code where I populate the data of the <select> element from earlier:

// exampleController.js (Continued...)

$scope.getDataFromUrl(userGroupsUrl, false, function (data) {
    initSelectDropdown(data);
});

var initSelectDropdown = function (data) {
    var userGroups = [];

    // Parse data retrieved from the server and populate the <select> bound data
    // array with it
    var index;
    for (index = 0; index < data.length; ++index)
    {
        var newGroup = {
            value: data[index],
            label: data[index]
        };

        // One of the data entries will have a value of "", this group needs its
        // label to be set to the localized string "No Group"
        if (newGroup.value === "")
        {
            newGroup.label = '<' + $scope.uiText['NoGroup.Text'] + '>';
        }
        userGroups.push(newGroup);
    }

    // Set local userGroups to scope
    $scope.userGroups = userGroups;
};

The problem I'm having is here in the initSelectDropdown() function. I need to have both the data from the server and the uiText resource data from the server, particularly the line newGroup.label = '<' + $scope.uiText['NoGroup.Text'] + '>'; where the data is being transformed in a way that is dependant on localized resources being loaded. I researched the issue and saw that using $q.all() might be a solution but unfortunately in my case there is no way for me to call $q.all() because the two calls to fetch data are being made from different functions in different controllers (data being requested from child controller and resources being requested from base controller).

In the view it's easy to fix this because if I bind an element to $scope.uiText['SomeText.Text'] then it doesn't care if SomeText.Text is undefined at first and when it is eventually populated the UI will automatically pick up on the change.

How can I make this work? Is it possible to achieve something like how binding works in the view?

Upvotes: 0

Views: 48

Answers (1)

coder
coder

Reputation: 4466

For sharing code angular provides services/factory, you don't need to use base controller.

Define a factory class and add two methods, one to fetch your server data and other to fetch uiText data. these methods will return promises.

Now in your controller you can use $q.all() passing the two promises that will be resolved when ajax call is complete. Hope it makes sense ?

Upvotes: 3

Related Questions