Felipe Liberal Felipe Liberal - 20 days ago 4
AngularJS Question

Bootstrap's Dropdown appears below the table

I'm trying to open a Bootstrap dropdown inside a table, after a button click. But the dropdown appears below the table, always in the same position, no matter which button is pressed.

Does someone had the same problem? Is it some css position that I am missing?

My goal is: each dropdown must appear just below the button that was press.

Here is a Demo:



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>




Answer

You should add dropdown class to the parent of the dropdown-menu element (in your case it is td element).

<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>
      ...
Comments