Bootstrap的下拉列表显示在表格下方

时间:2016-11-14 16:16:39

标签: css angularjs twitter-bootstrap html-table dropdown

我正在尝试在单击按钮后打开表内的Bootstrap下拉列表。但是,无论按下哪个按钮,下拉列表都会显示在表格下方,始终位于相同的位置。

有人有同样的问题吗?我缺少一些css职位吗?

我的目标是:每个下拉列表必须出现在按下的按钮下方。

这是一个演示:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.filteredList = [];
   $scope.servers = [
      {
        name: 'Server 1',
        port: 5014
      },
      {
        name: 'Server 2',
        port: 5015
      },
      {
        name: 'Server 3',
        port: 5016
      },
      {
        name: 'Server 4',
        port: 5017
      },
      {
        name: 'Server 5',
        port: 5018
      },
      {
        name: 'Server 6',
        port: 5019
      },
      {
        name: 'Server 7',
        port: 5020
      },
      {
        name: 'Server 8',
        port: 8081
      },
      {
        name: 'Server 9',
        port: 8082
      },
      {
        name: 'Server 10',
        port: 8083
      }
    ];
  
  
  $scope.orderByField = "name";
  $scope.orderByReverse = false;            
  $scope.currentPage = 1;
  $scope.itemsPerPage = 5;

  $scope.orderBy = function(field) {
      if (field == $scope.orderByField)
          $scope.orderByReverse = !$scope.orderByReverse
      else {
          $scope.orderByField = field;
          $scope.orderByReverse = false;
      }
  };

  
})

.factory('Utils', function($timeout, $window) {
    return {
        getNormalizedString: getNormalizedString,
        setFocus: setFocus
    }

    function getNormalizedString(str) {
        str = str.toLowerCase();
        str = str.replace(new RegExp("\\s", 'g'), "");
        str = str.replace(new RegExp("[àáâãäå]", 'g'), "a");
        str = str.replace(new RegExp("æ", 'g'), "ae");
        str = str.replace(new RegExp("ç", 'g'), "c");
        str = str.replace(new RegExp("[èéêë]", 'g'), "e");
        str = str.replace(new RegExp("[ìíîï]", 'g'), "i");
        str = str.replace(new RegExp("ñ", 'g'), "n");
        str = str.replace(new RegExp("[òóôõö]", 'g'), "o");
        str = str.replace(new RegExp("œ", 'g'), "oe");
        str = str.replace(new RegExp("[ùúûü]", 'g'), "u");
        str = str.replace(new RegExp("[ýÿ]", 'g'), "y");
        str = str.replace(new RegExp("\\W", 'g'), "");
        return str;
    }

    function setFocus(id) {
        $timeout(function() {
            var element = $window.document.getElementById(id);
            if (element)
                element.focus();
        });
    }
})

.filter('normalizedOrderBy', function(Utils, $filter) {
    return function(list, orderByField, orderByReverse) {
        function normalize(item) {
            var value = item[orderByField];
            if (typeof value === "string")
                value = Utils.getNormalizedString(value);

            // Forces the empty names to the end.
            if (value === null || value === "")
                return '~';

            return value;
        };

        return $filter('orderBy')(list, normalize, orderByReverse);
    }
})

.filter('normalizedFilter', function(Utils, $filter) {
    return function(list, search) {
        function comparator(actual, expected) {
            // Filtro vazio ou nulo.
            if (expected === "" || expected == null)
                return true;
            // Exatamente iguais.
            if (actual == expected)
                return true;

            if (typeof actual === "string" && typeof expected === "string") {
                actual = Utils.getNormalizedString(actual);
                expected = Utils.getNormalizedString(expected);
                return actual.indexOf(expected) > -1;
            }

            return false;
        };

        return $filter('filter')(list, search, comparator);
    }
});
.corpo {     
    margin-left: auto; 
    margin-right: auto;
    padding: 5px; 
    width: 95%;    
}

.corpo .filtros { margin-top: 50px; }    

.corpo .area-grid { padding: 30px 0px; background-color: #ededee; }
    .corpo .area-grid .container{ margin-left: 5px; margin-right: 10px; width: 100%; }
    .corpo .area-grid .container table { border-collapse: separate; border-spacing: 0 0px; margin-top: -10px; }

        .corpo .grid .grid-header th { color: #999; cursor:pointer; font-family: "RobotoLight", Roboto-Light, sans-serif; padding: 2px 12px; text-align: left; text-decoration: none; }            

        .corpo .grid .linhas-grid.linha-par { background-color: #f8f8f8; }
        .corpo .grid .linhas-grid td { border: 1px solid #ededee; border-style: solid solid; color: #333; font-size: 0.88em; line-height:0.8; padding: 2px 12px; }
        .corpo .grid .linhas-grid td+td { border-left: 2px  #ddd; }
        .corpo .grid .linhas-grid td img { height: 35px; width: 35px; }
        .corpo .grid .linhas-grid td:first-child{ border-left-style: solid; border-top-left-radius: 10px; border-bottom-left-radius: 10px; }
        .corpo .grid .linhas-grid td:last-child { background-color: #ededee; }
        
        .corpo .grid .linhas-grid .icone-grid { background-color: #f5f5f5; box-shadow: 1px 1px 1px #c9c8c9;}
        .corpo .grid .linhas-grid .icone-grid i { color: #999;}
                     
        .corpo .grid .checkbox { height: 17px; width: 17px; margin: 1px; }        
        
        .container .largura100 { width: 98%;}

        .container .largura80 { width: 78%; }
        .container .largura60 { width: 58%; }
        .container .largura40 { width: 38%; }
        .container .largura35 { width: 33%; }
        .container .largura30 { width: 28%; }
        .container .largura20 { width: 18%; }
        .container .largura15 { width: 13%; }
        .container .largura10 { width: 8%; }
        .container .largura5  { width: 3%; }

        .container .largura75 { width: 73%; }
        .container .largura50 { width: 48%; }
        .container .largura25 { width: 23%; }

        .container .largura66 { width: 64%; }
        .container .largura33 { width: 31%; }

        .container .largura100, 
        .container .largura80,
        .container .largura60,
        .container .largura40,
        .container .largura35,
        .container .largura30,
        .container .largura20,
        .container .largura15,
        .container .largura10,
        .container .largura5, 
        .container .largura75,
        .container .largura50,
        .container .largura25,
        .container .largura66,
        .container .largura33        
         {
	        padding-right:1% !important;
	        padding-left:1% !important;
	        margin:8px 0px 8px 0px !important;
        }
<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script data-require="jquery@2.2.4" data-semver="2.2.4" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/cosmo/bootstrap.min.css" />
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />
    <link data-require="font-awesome@4.5.0" data-semver="4.5.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.css" />
    <script data-require="bootstrap@3.3.5" data-semver="3.3.5" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
    
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl" class="corpo">
    <div class="filtros" ng-init="selectedTab='access'">
      <div class="row">
        <div class="col-xs-12">
          <div class="campo-pesquisa">
            <div class="input-group margin-bottom-sm">
              <input ng-model="search.$" class="form-control" type="text" placeholder="Pesquisar" />
              <span class="input-group-addon">
                <i class="fa fa-search fa-fw"></i>
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="area-grid">
      <div class="container">
        <table class="grid">
          <tbody>
            <tr class="grid-header">
              <th ng-click="orderBy('name')" class="largura20 sort">Nome                                                 <span ng-show="orderByField == 'name'" class="fa fa-sort-{{ orderByReverse ? 'desc' : 'asc' }}" aria-hidden="true"></span>
              </th>
              <th ng-click="orderBy('port')" class="largura10 sort">Porta                                                 <span ng-show="orderByField == 'port'" class="fa fa-sort-{{ orderByReverse ? 'desc' : 'asc' }}" aria-hidden="true"></span>
              </th>
              <th class="col largura15"></th>
            </tr>
            <tr class="linhas-grid" ng-class-odd="'linha-par'" ng-class-even="'linha-impar'" ng-repeat="item in servers | normalizedFilter:search |  normalizedOrderBy:orderByField:orderByReverse as filteredList">
              <td>{{ :: item.name }}</td>
              <td>{{ :: item.port }}</td>
              <td>
                <button class="btn btn-default dropdown-togle icone-grid" data-toggle="dropdown">
                  <i class="fa fa-gears"></i>
                </button>
                <ul class="dropdown-menu" role="menu">
                  <li>
                    <a class="dropdown-item" href="#">Atualizar</a>
                  </li>
                  <li>
                    <a class="dropdown-item" href="#">Reiniciar</a>
                  </li>
                  <li role="separator" class="divider"></li>
                  <li>
                    <a class="dropdown-item" href="#">Modificar IP</a>
                  </li>
                  <li>
                    <a class="dropdown-item active" href="#">Avançado</a>
                  </li>
                  <li role="separator" class="divider"></li>
                  <li>
                    <a class="dropdown-item" href="#">Importar</a>
                  </li>
                  <li>
                    <a class="dropdown-item" href="#">Exportar</a>
                  </li>
                </ul>
              </td>
            </tr>
          </tbody>
          <tfoot>
            <tr>
              <td colspan="8" class="text-center">
                <span ng-show="servers == null">Carregando...</span>
                <span ng-show="filteredList.length === 0">Nenhum registro encontrado.</span>
                <uib-pagination ng-show="filteredList.length > 0" ng-model="currentPage" total-items="filteredList.length" items-per-page="itemsPerPage" max-size="10" num-pages="numPages" boundary-links="true" previous-text="‹" next-text="›" first-text="«" last-text="»" class="pagination-sm" style="margin: 0px; margin-bottom: -5px"></uib-pagination>
              </td>
            </tr>
          </tfoot>
        </table>
      </div>
      <!-- fim do container -->
    </div>
    <!-- fim da área do grid -->
  </body>

</html>

2 个答案:

答案 0 :(得分:2)

您应该将dropdown类添加到dropdown-menu元素的父级(在您的情况下是td元素)。

<td class="dropdown">
  <button class="btn btn-default dropdown-togle icone-grid" data-toggle="dropdown">
    <i class="fa fa-gears"></i>
  </button>
  <ul class="dropdown-menu" role="menu">
    <li>
      <a class="dropdown-item" href="#">Atualizar</a>
    </li>
      ...

答案 1 :(得分:0)

position: relative添加.corpo .grid .linhas-grid td即可。

目前,您的下拉菜单中有position: absolute属性,但父容器没有设置position: relative,因此它会占用下一个父级,直到找到相对位置,并将0px放在此容器的左侧(因为下拉菜单中有left: 0)。

将相对位置添加到td父级会使其根据td的位置进行定位。

但正如@makshh所回答的那样,在td中添加一个.dropdown类也会起到作用,并且会更清洁&#34;因为它是Bootstrap方式来进行下拉列表。

但基本上两者都可以,因为dropdown类会将position: relative属性添加到元素中。

&#13;
&#13;
var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.filteredList = [];
   $scope.servers = [
      {
        name: 'Server 1',
        port: 5014
      },
      {
        name: 'Server 2',
        port: 5015
      },
      {
        name: 'Server 3',
        port: 5016
      },
      {
        name: 'Server 4',
        port: 5017
      },
      {
        name: 'Server 5',
        port: 5018
      },
      {
        name: 'Server 6',
        port: 5019
      },
      {
        name: 'Server 7',
        port: 5020
      },
      {
        name: 'Server 8',
        port: 8081
      },
      {
        name: 'Server 9',
        port: 8082
      },
      {
        name: 'Server 10',
        port: 8083
      }
    ];
  
  
  $scope.orderByField = "name";
  $scope.orderByReverse = false;            
  $scope.currentPage = 1;
  $scope.itemsPerPage = 5;

  $scope.orderBy = function(field) {
      if (field == $scope.orderByField)
          $scope.orderByReverse = !$scope.orderByReverse
      else {
          $scope.orderByField = field;
          $scope.orderByReverse = false;
      }
  };

  
})

.factory('Utils', function($timeout, $window) {
    return {
        getNormalizedString: getNormalizedString,
        setFocus: setFocus
    }

    function getNormalizedString(str) {
        str = str.toLowerCase();
        str = str.replace(new RegExp("\\s", 'g'), "");
        str = str.replace(new RegExp("[àáâãäå]", 'g'), "a");
        str = str.replace(new RegExp("æ", 'g'), "ae");
        str = str.replace(new RegExp("ç", 'g'), "c");
        str = str.replace(new RegExp("[èéêë]", 'g'), "e");
        str = str.replace(new RegExp("[ìíîï]", 'g'), "i");
        str = str.replace(new RegExp("ñ", 'g'), "n");
        str = str.replace(new RegExp("[òóôõö]", 'g'), "o");
        str = str.replace(new RegExp("œ", 'g'), "oe");
        str = str.replace(new RegExp("[ùúûü]", 'g'), "u");
        str = str.replace(new RegExp("[ýÿ]", 'g'), "y");
        str = str.replace(new RegExp("\\W", 'g'), "");
        return str;
    }

    function setFocus(id) {
        $timeout(function() {
            var element = $window.document.getElementById(id);
            if (element)
                element.focus();
        });
    }
})

.filter('normalizedOrderBy', function(Utils, $filter) {
    return function(list, orderByField, orderByReverse) {
        function normalize(item) {
            var value = item[orderByField];
            if (typeof value === "string")
                value = Utils.getNormalizedString(value);

            // Forces the empty names to the end.
            if (value === null || value === "")
                return '~';

            return value;
        };

        return $filter('orderBy')(list, normalize, orderByReverse);
    }
})

.filter('normalizedFilter', function(Utils, $filter) {
    return function(list, search) {
        function comparator(actual, expected) {
            // Filtro vazio ou nulo.
            if (expected === "" || expected == null)
                return true;
            // Exatamente iguais.
            if (actual == expected)
                return true;

            if (typeof actual === "string" && typeof expected === "string") {
                actual = Utils.getNormalizedString(actual);
                expected = Utils.getNormalizedString(expected);
                return actual.indexOf(expected) > -1;
            }

            return false;
        };

        return $filter('filter')(list, search, comparator);
    }
});
&#13;
.corpo {     
    margin-left: auto; 
    margin-right: auto;
    padding: 5px; 
    width: 95%;    
}

.corpo .filtros { margin-top: 50px; }    

.corpo .area-grid { padding: 30px 0px; background-color: #ededee; }
    .corpo .area-grid .container{ margin-left: 5px; margin-right: 10px; width: 100%; }
    .corpo .area-grid .container table { border-collapse: separate; border-spacing: 0 0px; margin-top: -10px; }

        .corpo .grid .grid-header th { color: #999; cursor:pointer; font-family: "RobotoLight", Roboto-Light, sans-serif; padding: 2px 12px; text-align: left; text-decoration: none; }            

        .corpo .grid .linhas-grid.linha-par { background-color: #f8f8f8; }
        .corpo .grid .linhas-grid td { border: 1px solid #ededee; border-style: solid solid; color: #333; font-size: 0.88em; line-height:0.8; padding: 2px 12px;position: relative; }
        .corpo .grid .linhas-grid td+td { border-left: 2px  #ddd; }
        .corpo .grid .linhas-grid td img { height: 35px; width: 35px; }
        .corpo .grid .linhas-grid td:first-child{ border-left-style: solid; border-top-left-radius: 10px; border-bottom-left-radius: 10px; }
        .corpo .grid .linhas-grid td:last-child { background-color: #ededee; }
        
        .corpo .grid .linhas-grid .icone-grid { background-color: #f5f5f5; box-shadow: 1px 1px 1px #c9c8c9;}
        .corpo .grid .linhas-grid .icone-grid i { color: #999;}
                     
        .corpo .grid .checkbox { height: 17px; width: 17px; margin: 1px; }        
        
        .container .largura100 { width: 98%;}

        .container .largura80 { width: 78%; }
        .container .largura60 { width: 58%; }
        .container .largura40 { width: 38%; }
        .container .largura35 { width: 33%; }
        .container .largura30 { width: 28%; }
        .container .largura20 { width: 18%; }
        .container .largura15 { width: 13%; }
        .container .largura10 { width: 8%; }
        .container .largura5  { width: 3%; }

        .container .largura75 { width: 73%; }
        .container .largura50 { width: 48%; }
        .container .largura25 { width: 23%; }

        .container .largura66 { width: 64%; }
        .container .largura33 { width: 31%; }

        .container .largura100, 
        .container .largura80,
        .container .largura60,
        .container .largura40,
        .container .largura35,
        .container .largura30,
        .container .largura20,
        .container .largura15,
        .container .largura10,
        .container .largura5, 
        .container .largura75,
        .container .largura50,
        .container .largura25,
        .container .largura66,
        .container .largura33        
         {
	        padding-right:1% !important;
	        padding-left:1% !important;
	        margin:8px 0px 8px 0px !important;
        }
&#13;
<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script data-require="jquery@2.2.4" data-semver="2.2.4" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/cosmo/bootstrap.min.css" />
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />
    <link data-require="font-awesome@4.5.0" data-semver="4.5.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.css" />
    <script data-require="bootstrap@3.3.5" data-semver="3.3.5" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
    
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl" class="corpo">
    <div class="filtros" ng-init="selectedTab='access'">
      <div class="row">
        <div class="col-xs-12">
          <div class="campo-pesquisa">
            <div class="input-group margin-bottom-sm">
              <input ng-model="search.$" class="form-control" type="text" placeholder="Pesquisar" />
              <span class="input-group-addon">
                <i class="fa fa-search fa-fw"></i>
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="area-grid">
      <div class="container">
        <table class="grid">
          <tbody>
            <tr class="grid-header">
              <th ng-click="orderBy('name')" class="largura20 sort">Nome                                                 <span ng-show="orderByField == 'name'" class="fa fa-sort-{{ orderByReverse ? 'desc' : 'asc' }}" aria-hidden="true"></span>
              </th>
              <th ng-click="orderBy('port')" class="largura10 sort">Porta                                                 <span ng-show="orderByField == 'port'" class="fa fa-sort-{{ orderByReverse ? 'desc' : 'asc' }}" aria-hidden="true"></span>
              </th>
              <th class="col largura15"></th>
            </tr>
            <tr class="linhas-grid" ng-class-odd="'linha-par'" ng-class-even="'linha-impar'" ng-repeat="item in servers | normalizedFilter:search |  normalizedOrderBy:orderByField:orderByReverse as filteredList">
              <td>{{ :: item.name }}</td>
              <td>{{ :: item.port }}</td>
              <td>
                <button class="btn btn-default dropdown-togle icone-grid" data-toggle="dropdown">
                  <i class="fa fa-gears"></i>
                </button>
                <ul class="dropdown-menu" role="menu">
                  <li>
                    <a class="dropdown-item" href="#">Atualizar</a>
                  </li>
                  <li>
                    <a class="dropdown-item" href="#">Reiniciar</a>
                  </li>
                  <li role="separator" class="divider"></li>
                  <li>
                    <a class="dropdown-item" href="#">Modificar IP</a>
                  </li>
                  <li>
                    <a class="dropdown-item active" href="#">Avançado</a>
                  </li>
                  <li role="separator" class="divider"></li>
                  <li>
                    <a class="dropdown-item" href="#">Importar</a>
                  </li>
                  <li>
                    <a class="dropdown-item" href="#">Exportar</a>
                  </li>
                </ul>
              </td>
            </tr>
          </tbody>
          <tfoot>
            <tr>
              <td colspan="8" class="text-center">
                <span ng-show="servers == null">Carregando...</span>
                <span ng-show="filteredList.length === 0">Nenhum registro encontrado.</span>
                <uib-pagination ng-show="filteredList.length > 0" ng-model="currentPage" total-items="filteredList.length" items-per-page="itemsPerPage" max-size="10" num-pages="numPages" boundary-links="true" previous-text="‹" next-text="›" first-text="«" last-text="»" class="pagination-sm" style="margin: 0px; margin-bottom: -5px"></uib-pagination>
              </td>
            </tr>
          </tfoot>
        </table>
      </div>
      <!-- fim do container -->
    </div>
    <!-- fim da área do grid -->
  </body>

</html>
&#13;
&#13;
&#13;