Search code examples
javascriptangularjsjquery-select2

AngularJS, using ng-show breaks select2's layout


I'm creating a dynamic page that loads a lot of filters from the server. I want to show those filters only when all server side calls are done. For that, I'm using a simple true/false variable (ng-show="filtersDone", 11th row).

<div class="row">
    <div class="col-sm-11 col-sm-offset-1 table_padding_content">
        <div class="panel panel-default">
            <div class="panel-heading text-center">
                <span><strong> Planning - Details </strong></span>
                <div class="clearfix"></div>
            </div>
            <div class="panel-body">
                <div class="panel panel-default">
                    <div class="panel-body">
                        <div class="row" ng-show="filtersDone">
                            <div class="form-group col-sm-1">
                                <label for="searchFilters.year" class="control-label">Year</label>
                                <select class="form-control" ng-model="searchFilters.year" ng-options="y as y for y in yearsList"></select>
                            </div>

                            <div class="form-group col-sm-2">
                                <label for="searchFilters.dealer" class="control-label">Dealers</label>
                                <select class="form-control" ng-model="searchFilters.dealer" ng-options="dealer.ID as dealer.Name for dealer in dealers"><option></option></select>
                            </div>

                            <div class="form-group col-sm-2">
                                <label for="searchFilters.planningStatus" class="control-label">Planning Status</label>
                                <select class="form-control" ng-model="searchFilters.planningStatus">
                                    <option></option>
                                    <option value="1">Started</option>
                                    <option value="2">Compiled</option>
                                    <option value="3">Archived</option>
                                </select>
                            </div>

                            <div class="form-group col-sm-3">
                                <label for="searchFilters.buildingType" class="control-label">Building Type</label>
                                <select class="form-control" ng-model="searchFilters.buildingType" id="select2_buildingType" name="searchFilters.buildingType"
                                        multiple="multiple" ng-options="item.ID as item.Name for item in buildingTypes">
                                </select>
                            </div>

                            <div class="form-group col-sm-2">
                                <label for="searchFilters.buildingCategory" class="control-label">Building Category</label>
                                <select class="form-control" ng-model="searchFilters.buildingCategory" id="select2_buildingCategory" name="searchFilters.buildingCategory" 
                                        multiple="multiple" ng-options="item.ID as item.Category for item in buildingCategories">
                                </select>
                            </div>

                            <div class="form-group col-sm-2">
                                <div class="pull-right">
                                    <label class="control-label" style="width: 100%">&nbsp;</label>
                                    <button type="button" class="btn btn-default" ng-click="search()">Search</button>
                                    <button type="button" class="btn btn-default" ng-click="clean()">Clean</button>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

And here's the part of the controller for filters. $scope.filtersDone is setted to false at the beginning of the function, then i call all the server side functions to get all select values and then, when evertything is done, i set $scope.filtersDone to true (28th row).
I thought the problem could be that i was initializing select2 select before the $scope.filtersDone = true; but it doesn't change if I do it before or after.

$scope.init = function () {
  $scope.filtersDone = false;

  apiCustomService.defaultYear.get(function (res) {
    $scope.currentYear = res.value;

    $scope.yearsList = [];
    const currentYear = new Date().getFullYear();
    for (i = 0; i < 15; i++) {
      $scope.yearsList.push(currentYear - i);
    }

    apiCustomService.dealersGet.get(function(dealers) {
      $scope.dealers = dealers;
      apiCustomService.operaType.get(function(buildingTypes) {
        $scope.buildingTypes = buildingTypes;
        apiCustomService.operaCategory.get(function(buildingCategories) {
          $scope.buildingCategories = buildingCategories;
          apiCustomService.inspectionTypes.get(function(inspectionTypes) {
            $scope.inspectionTypes = inspectionTypes;
            apiCustomService.getListOfValues.get(function(listOfValues) {
              $scope.listOfValues = listOfValues;
              apiCustomService.getAllBuildingCodes.get(function(buildingCodes) {
                $scope.buildingCodes = buildingCodes.codes;

                $scope.searchFilters = {year: $scope.currentYear};

                $scope.filtersDone = true;

                jQuery('#select2_buildingType').select2({
                  multiple: true,
                  placeholder: " ",
                  allowClear: true,
                  language: 'it'
                });

                jQuery('#select2_buildingCategory').select2({
                  multiple: true,
                  placeholder: " ",
                  allowClear: true,
                  language: 'it'
                });
              });
            });
          });
        });
      });
    });
  });
}

$scope.init();

If i don't use ng-show="filtersDone", this is the (correct) situation:

enter image description here

But if i use it, this is the situation (layout breaks down only for select2 components):

enter image description here

Any suggestion?


Solution

  • When ng-show is set to false, the element is not available in the page to be manipulated, because angular hides it using CSS: "display: none !important"

    So instead of ng-show, you can use a class or style directive to hide the element via the usage of either CSS visibility or opacity rules.

    This ensures that the element is being rendered in the page even though it is not visible.

    basically replace this:

    <div class="row" ng-show="filtersDone">
    

    with this:

    <div class="row" ng-style="{'opacity': filtersDone ? '1' : '0' }">