harman052
harman052

Reputation: 969

Unable to load dynamic data into ui-grid dropdown

I am using ui-grid with AngularJS (and MySQL at backend) for a project. I got a table which gets its data from MySQL database. Its rows (or cells) are editable (as mentioned in this example on ui-grid website). One column of the table has dropdown. Dropdown is working perfectly with hard coded data as described in that example. I want to populate it from database but it shows empty dropdown list everytime I tried.

Fetching of data from database is done by service which is injected into the controller with intention to run the code that gets data from database (i.e. $http.get('/some/route')) so that we have all the data for table rows and dropdown list in hand before or at the time of page loading.

But the variable (sitesD) that gets data for dropdown when printed, shows it is undefined.

Here is the controller:

angular.module('WorkersCtrl', []).controller('WorkersController', function($scope, $http, serverData) {

$scope.gridOptions = {enableHorizontalScrollbar: 1};

/* getting rows from databse by using "serverData" custom service */
serverData.getData().then(function(response) {
        $scope.gridOptions.data = response.data[0];
        $scope.sitesData = response.data[1];
});
var sitesD = $scope.sitesData;
$scope.gridOptions.columnDefs = [
    { field: 'first_name', width:150, enableCellEdit: true},
    { field: 'last_name', width:150},
    { field: 'father_first_name', width:150},
    { field: 'father_last_name', width:150},
    { field: 'mother_first_name', width:150},
    { field: 'mother_last_name', width:150},
    { field: 'sex', width:50, editableCellTemplate: 'ui-grid/dropdownEditor',
        editDropdownValueLabel: 'gender', editDropdownOptionsArray: [
          { id: 'M', gender: 'Male' },
          { id: 'F', gender: 'Female' }]},
    { field: 'address', width:250},
    { field: 'phone', width:100, type: 'number'},
    { field: 'date_of_birth', width:150, type: 'date', cellFilter: 'date:"yyyy-MM-dd"'},
    { field: 'post_code', displayName: 'Post', width:50},
    { field: 'joining_date', width:150, type: 'date', cellFilter: 'date:"yyyy-MM-dd"'},
    { field: 'rate', width:50, type: 'number'},
    { field: 'site_name', width:150, editableCellTemplate: 'ui-grid/dropdownEditor',
    editDropdownIdLabel:'site_id', editDropdownValueLabel: 'site_name', editDropdownOptionsArray: sitesD },
];
alert(sitesD); //checking the variable value: it shows undefined.

$scope.gridOptions.onRegisterApi = function(gridApi){
    $scope.gridApi = gridApi;
};

$scope.addData = function() {
    $scope.gridOptions.data.push({
        'first_name': '',
        'last_name': '',
        'father_first_name': '',
        'father_last_name': '',
        'mother_first_name': '',
        'mother_last_name': '',
        'sex': '',
        'address': '',
        'phone': '',
        'date_of_birth': '',
        'post_code': '',
        'joining_date': '',
        'rate': '',
        'site_name': ''
    });
};
});

Code of service is following:

angular.module('GeekService', []).factory('serverData', ['$http', function($http) {
    return {
        getData: function() {
            return $http.get('/workers')
        }
    }
}]);

Here is the screenshot of page when alert(sitesD); runs: enter image description here

What I understand is variable gets value after the page loads and so the editDropdownOptionsArray gets no value for dropdown.

All these are assumptions I made while looking for solution but haven't sceeded yet. Please help me. I feel I am even didn't understand where's the problem.

Feel free to ask further information if needed.

PS: While writing the question I found there is version incompatibility between my Angular and ui-grid. ui-grid 3.x is compatible with Angular's 1.4.x but I'm using ui-grid 3.x with Angular 1.5.5. Is it can be the reason?

EDIT: Here is the screenshot, showing how the dropdown looks: enter image description here

Upvotes: 1

Views: 3446

Answers (2)

Brendon Colburn
Brendon Colburn

Reputation: 1912

Harmanpreet,

Since you are bringing in dynamic content asynchronously I would recommend looking at the ui-grid "editDropdownRowEntityOptionsArrayPath" functionality instead of "editDropdownOptionsArray" as that functionality appears to be meant for static values as you are discovering now. There is information on this on the UI-grid API site: http://ui-grid.info/docs/#/api/ui.grid.edit.api:ColumnDef

If the data is a static list and won't be changing or dependent then maybe the code below would work as well, thanks for reaching out:

serverData.getData().then(function(response) {
    $scope.gridOptions.data = response.data[0];
    $scope.sitesData = response.data[1];

    // You may have to shape data in a method before doing the next line
    // ex: var sitesArray = shapeSitesData();

    $scope.gridOptions.columnDefs[13].editDropdownOptionsArray = $scope.sitesData;
});

Since Stackoverflow doesn't respect new people's opinions I cannot comment on your thread with transistor. Hopefully you see this as I believe it will help. The issue you are encountering could also be due to the fact that ui-grid doesn't do a great job of mapping ids and values. You should try my variant (which i believe improves upon @mltroutt's solution).

angular.module('app')
     .controller('yourctrl', yourFunction)
     .filter('griddropdown', function () {
    return function (input, context) {
        var fieldLevel = (context.editDropdownOptionsArray == undefined) ? context.col.colDef : context;
        var map = fieldLevel.editDropdownOptionsArray;
        var idField = fieldLevel.editDropdownIdLabel;
        var valueField = fieldLevel.editDropdownValueLabel;
        var initial = context.row.entity[context.col.field];
        if (typeof map !== "undefined") {
            for (var i = 0; i < map.length; i++) {
                if (map[i][idField] == input) {
                    return map[i][valueField];
                }
            }
        }
        else if (initial) {
            return initial;
        }
        return input;
    };

Then add this to your coldef

cellFilter: 'griddropdown:this'

Upvotes: 3

transistor1
transistor1

Reputation: 2925

It's a timing issue. At the point where you're calling alert(sitesD), your data hasn't loaded yet. Angular promises are asynchronous, which is what the then statement is for.

If you move your alert inside the then, your dropdown data should appear:

serverData.getData().then(function(response) {
        $scope.gridOptions.data = response.data[0];
        $scope.sitesData = response.data[1];
        alert($scope.sitesData);
});

If it's still undefined, either response.data[1] doesn't contain your data, or you've got a problem with your server-side logic.

If your data does appear correctly in the then alert, next try changing editDropdownOptionsArray: $scope.sitesData

Edit: in my solution, I use an angular-resource instead of $http, and it works as described above. You may want to try this, though I'd expect it to work the way you've coded it with $http as well.

angular.module('siteDataService', ['ngResource'])
.factory('siteData', function($resource) {
  return $resource('/workers', {}, {
    query: { method:'GET', isArray: true }
  }
});

Make sure you include angular-resource.js in your HTML, and take a dependency on siteDataService in your application, and add siteData in your controller.

To run the query, you'd use $scope.serverResponse = siteData.query(); in the body of your controller.

Upvotes: 0

Related Questions