0

When my scope has two properties that each contain an array retrieved asynchronously from the database, I cannot elegantly access the one from the other. I'm sure I must be missing something because my current solution feels like a hack.

I have an Angular CRUD page that contains a table and a form which contains a dropdown select control. When I click on a row in the table and want to update it, I need to populate the dropdown with the current value. In order to get this right, I'm currently declaring a global variable and assign the array used to populate the dropdown to that variable once it is retrieved from the database.

var columnHeaderArray;

var app = angular.module('myApp', []);
app.controller('ColumnHeadingController',
    function ($scope, $http) {
        $scope.GetAllData = function () {
            $http({
                method: "get",
                url: "/api/Staat8Maintenance/GetAllColumnHeadings"
            }).then(function (response) {
                $scope.columnheaders = response.data;
                $scope.GetGroupHeaderData();
            },
                function () { alert("Error Occured"); });
        };
        $scope.GetGroupHeaderData = function () {
            $http({
                method: "get",
                url: "/api/Staat8Maintenance/GetGroupHeadingsForCombo"
            }).then(function (response) {
                $scope.groupheaders = response.data;
                columnHeaderArray = response.data;
            },
                function () { alert("Error Occured"); });
        };
        $scope.UpdateColumnHeading = function (cho) {
            document.getElementById("OriginalOrder").innerHTML = cho.ColumnOrder;
            document.getElementById("OriginalColumnHeading").innerHTML = cho.ColumnHeading;
            $scope.ColumnHeading = cho.ColumnHeading;
            $scope.ColumnOrder = cho.ColumnOrder;
            $scope.SelectedOption = columnHeaderArray[columnHeaderArray.findIndex(x => x.GroupingHeaderId == cho.GroupingHeaderId)];
            document.getElementById("btnSave").setAttribute("value", "Update");
            document.getElementById("btnSave").style.backgroundColor = "Yellow";
            document.getElementById("formColumnHeading").style.display = "block";
        };
    }
);

        <div id="SubAccountGrouping" class="tabcontent" 
             ng-controller="ColumnHeadingController"
             ng-init="GetAllData()">
            <h2>Column Headings</h2>
            <h5>This is where the column headings will be maintained.</h5>
            <div id="formColumnHeading" class="form" role="form">
                <div class="container">
                    <div class="row">
                        <div class="form-horizontal">
                            <div class="form-group">
                                <label class="col-sm-1 edittextwide">Heading:</label>
                                <div class="col-sm-6">
                                    <input type="text" class="form-control edittextwide"
                                           id="inputColumnHeading"
                                           placeholder="Column Heading"
                                           ng-model="ColumnHeading" />
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-1">Order:</label>
                                <div class="col-sm-6">
                                    <input type="number" class="form-control"
                                           id="inputColumnOrder" 
                                           placeholder="Order"
                                           ng-model="ColumnOrder" />
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-1 edittextwide">Group Heading:</label>
                                <div class="col-sm-6">
                                    <select class="form-control edittextwide"
                                            name="groupHeadings"
                                            id="selectGroupHeadings"
                                            ng-model="SelectedOption"
                     ng-options="gh as gh.HeadingName for gh in groupheaders track by gh.GroupingHeaderId">
                                    </select>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div>
                            <input type="button" id="btnSave" class="form-control btn-default"
                                   value="Submit" ng-click="InsertData()" />
                        </div>
                    </div>
                </div>
                <div class="hiddenlabel">
                    <label id="OriginalOrder">0</label>
                    <label id="OriginalColumnHeading">ABC</label>
                </div>
            </div>
            <div class="scrolldiv">
                <table class="table">
                    <thead>
                        <tr>
                            <th>Heading</th>
                            <th>No of Sub-Accounts</th>
                            <th>Column Order</th>
                            <th>Group Heading</th>
                            <th>Parent Group Heading</th>
                            <th>Include in Staat 8</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tr ng-repeat="cho in columnheaders">
                        <td>{{cho.ColumnHeading}}
                        </td>
                        <td>{{cho.NumberOfEntries}}
                        </td>
                        <td>{{cho.ColumnOrder}}
                        </td>
                        <td>{{cho.GroupHeading}}
                        </td>
                        <td>{{cho.ParentGroupHeading}}
                        </td>
                        <td>{{cho.IncludeInStaat8?'Yes':'No'}}
                        </td>
                        <td>
                            <input type="button" class="btn btn-warning" 
                                   value="Update"
                                   ng-click="UpdateColumnHeading(cho)" />
                        </td>
                    </tr>
                </table>
            </div>
        </div>

When I try to set $scope.SelectedOption using $scope.groupheaders directly, it bombs out. I realise this is because of the asynchronous nature, but I suspect there must be a more elegant way to achieve this?

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Nel Prinsloo
  • 81
  • 2
  • 6
  • The title of the question talks about problems accessing asynchronous data but the final paragraph talks about problems setting the model of the ` – georgeawg Jun 05 '19 at 19:37
  • I need to set the model of a select input via an asynchronous SQL method. – Nel Prinsloo Jun 06 '19 at 05:59

1 Answers1

-1
// include $q to use promises
function ($scope, $http, $q) {
   // create a deferred promise
   var q = q.defer();

   // call the first $http method and store the promise
   var promise1 = $http(config1);

   // call the second $http method and store the promise
   var promise2 = $http(config2);

   // handle when the first promise resolves
   promise1
   .then( (data) => {
       $scope.columnheaders = response.data;
   })
   .catch( (errors) => q.reject(errors));

   // handle when the second promise resolves
   promise2
   .then( (data) => {
       $scope.groupheaders = response.data;
   })
   .catch( (errors) => q.reject(errors));

   // wait for both promises to resolve then do final actions
   $q.all([promise1, promise2])
   .then( () => {
       columnHeaderArray = response.data;
       q.resolve();
   });
   // return the promise for calling methods to wait until this resolves
   return q.promise;
}

Reference for using $q Reference for using $http

You can streamline the above code to make it more condensed, but I've broken it out some to be a little easier to follow.

Dan Obregon
  • 941
  • 9
  • 22
  • Avoid the [deferred anti-pattern](https://stackoverflow.com/questions/30750207/is-this-a-deferred-antipattern). The `$q,all` automatically returns a rejected promise if either of the XHRs reject. The `$q.all` auutomatically return a fullfilled promise if both XHRs resolve fulfilled. The is no need to use `$q.defer()`. – georgeawg Jun 05 '19 at 18:54
  • Thank you very much for this pointer. I'm currently busy trying it out. – Nel Prinsloo Jun 06 '19 at 06:00