Background
I am doing a custom autoplete with Angular Material and I would like to set the height of the autoplete dropdown results box to something bigger.
Research
To achieve this, I made a research and concluded that Angular Material does not support this, and that this issue will only be addressed in Angular Material 2 (to be released for AngularJS2):
- (possible fix 1)
- (possible fix 2)
- (last post explains that this problem wont be fixed)
- !topic/ngmaterial/4ActiQp3nA0 (explains about Angular Material 2 and the deprecation of Angular Material)
After reading, I realized that some people found a way around this limitation forcing the CSS (Angular Material Design Layout custom sizes), but not matter what I try I can't see to make any of their suggestions work.
Code
My sample app is posed of an index.html
, an autoplete.js
file, and the server.js
file with a mockData.json file.
Following are the index.html
, autoplete.js
and style.css
files. Since I am hosting this example in Cloud9 if the server is ON you can see it run live !
/*global angular*/
"use strict";
angular.module('MyApp', ['ngMaterial', 'ngMessages', 'material.svgAssetsCache', 'ngMdIcons']).controller('DemoCtrl', DemoCtrl);
function DemoCtrl($q, $log, $http) {
this.searchText = null;
this.querySearch = function(query) {
let serverUrl = '//custom-material-autoplete-fl4m3ph03n1x.c9users.io/getClients';
let deferred = $q.defer();
$http({
method: 'GET',
url: serverUrl,
params: {
word: query
}
}).then(function successCallback(response) {
deferred.resolve(response.data);
}, function errorCallback(response) {
$log.error(response);
});
return deferred.promise;
};
this.searchTextChange = function(text) {
$log.info('Text changed to ' + text);
}
this.selectedItemChange = function(item) {
$log.info('Item changed to ' + JSON.stringify(item));
}
}
.autopletedemoCustomTemplate .autoplete-custom-template li {
border-bottom: 1px solid #ccc;
height: auto;
padding-top: 8px;
padding-bottom: 8px;
white-space: normal;
}
.autopletedemoCustomTemplate .autoplete-custom-template li:last-child {
border-bottom-width: 0;
}
.autopletedemoCustomTemplate .autoplete-custom-template .item-title,
.autopletedemoCustomTemplate .autoplete-custom-template .item-metadata {
display: block;
line-height: 2;
}
.autopletedemoCustomTemplate .autoplete-custom-template .item-title md-icon {
height: 18px;
width: 18px;
}
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body ng-app="MyApp" ng-cloak>
<div ng-controller="DemoCtrl as ctrl" layout="column" ng-cloak="" class="autopletedemoCustomTemplate" ng-app="MyApp">
<md-content layout-padding="" layout="column">
<form ng-submit="$event.preventDefault()">
<md-autoplete md-selected-item="ctrl.selectedItem" md-search-text-change="ctrl.searchTextChange(ctrl.searchText)" md-search-text="ctrl.searchText" md-selected-item-change="ctrl.selectedItemChange(item)" md-items="item in ctrl.querySearch(ctrl.searchText)"
md-item-text="item.name" md-min-length="0" placeholder="Pick an Angular repository" md-menu-class="autoplete-custom-template">
<md-item-template>
<span class="item-title">
<strong>Company name:</strong> {{item.Company_Name}}
</span>
<strong>Client Ids:</strong>
<span ng-repeat="clientId in item.Assets">
<span class="item-metadata">
<span class="item-metastat">
 <ng-md-icon icon="subdirectory_arrow_right" style="fill: gray" size="24"></ng-md-icon>
{{clientId}}
</span>
</span>
</span>
</md-item-template>
</md-autoplete>
</form>
</md-content>
</div>
<!--CSS files-->
<link rel="stylesheet" href=".1.0-rc4/angular-material.min.css">
<link rel="stylesheet" href=".1.0-rc4/docs.css">
<link rel="stylesheet" href=":300,400,500,700,400italic">
<link rel="stylesheet" href="/css/style.css">
<!-- Angular Material requires Angular.js Libraries -->
<script src=".3.15/angular.js"></script>
<script src=".3.15/angular-animate.min.js"></script>
<script src=".3.15/angular-route.min.js"></script>
<script src=".3.15/angular-aria.min.js"></script>
<script src=".3.15/angular-messages.min.js"></script>
<script src=".cdpn.io/t-114/svg-assets-cache.js"></script>
<script src=".1.0-rc4/angular-material.min.js"></script>
<script src="//cdnjs.cloudflare/ajax/libs/angular-material-icons/0.7.0/angular-material-icons.min.js"></script>
<!-- Your application bootstrap -->
<script type="text/javascript" src="js/autoplete.js"></script>
</body>
</html>
Background
I am doing a custom autoplete with Angular Material and I would like to set the height of the autoplete dropdown results box to something bigger.
Research
To achieve this, I made a research and concluded that Angular Material does not support this, and that this issue will only be addressed in Angular Material 2 (to be released for AngularJS2):
- https://github./angular/material/issues/5132 (possible fix 1)
- https://github./angular/material/issues/4772 (possible fix 2)
- https://github./angular/material/pull/8397 (last post explains that this problem wont be fixed)
- https://groups.google./forum/#!topic/ngmaterial/4ActiQp3nA0 (explains about Angular Material 2 and the deprecation of Angular Material)
After reading, I realized that some people found a way around this limitation forcing the CSS (Angular Material Design Layout custom sizes), but not matter what I try I can't see to make any of their suggestions work.
Code
My sample app is posed of an index.html
, an autoplete.js
file, and the server.js
file with a mockData.json file.
Following are the index.html
, autoplete.js
and style.css
files. Since I am hosting this example in Cloud9 if the server is ON you can see it run live !
/*global angular*/
"use strict";
angular.module('MyApp', ['ngMaterial', 'ngMessages', 'material.svgAssetsCache', 'ngMdIcons']).controller('DemoCtrl', DemoCtrl);
function DemoCtrl($q, $log, $http) {
this.searchText = null;
this.querySearch = function(query) {
let serverUrl = '//custom-material-autoplete-fl4m3ph03n1x.c9users.io/getClients';
let deferred = $q.defer();
$http({
method: 'GET',
url: serverUrl,
params: {
word: query
}
}).then(function successCallback(response) {
deferred.resolve(response.data);
}, function errorCallback(response) {
$log.error(response);
});
return deferred.promise;
};
this.searchTextChange = function(text) {
$log.info('Text changed to ' + text);
}
this.selectedItemChange = function(item) {
$log.info('Item changed to ' + JSON.stringify(item));
}
}
.autopletedemoCustomTemplate .autoplete-custom-template li {
border-bottom: 1px solid #ccc;
height: auto;
padding-top: 8px;
padding-bottom: 8px;
white-space: normal;
}
.autopletedemoCustomTemplate .autoplete-custom-template li:last-child {
border-bottom-width: 0;
}
.autopletedemoCustomTemplate .autoplete-custom-template .item-title,
.autopletedemoCustomTemplate .autoplete-custom-template .item-metadata {
display: block;
line-height: 2;
}
.autopletedemoCustomTemplate .autoplete-custom-template .item-title md-icon {
height: 18px;
width: 18px;
}
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body ng-app="MyApp" ng-cloak>
<div ng-controller="DemoCtrl as ctrl" layout="column" ng-cloak="" class="autopletedemoCustomTemplate" ng-app="MyApp">
<md-content layout-padding="" layout="column">
<form ng-submit="$event.preventDefault()">
<md-autoplete md-selected-item="ctrl.selectedItem" md-search-text-change="ctrl.searchTextChange(ctrl.searchText)" md-search-text="ctrl.searchText" md-selected-item-change="ctrl.selectedItemChange(item)" md-items="item in ctrl.querySearch(ctrl.searchText)"
md-item-text="item.name" md-min-length="0" placeholder="Pick an Angular repository" md-menu-class="autoplete-custom-template">
<md-item-template>
<span class="item-title">
<strong>Company name:</strong> {{item.Company_Name}}
</span>
<strong>Client Ids:</strong>
<span ng-repeat="clientId in item.Assets">
<span class="item-metadata">
<span class="item-metastat">
 <ng-md-icon icon="subdirectory_arrow_right" style="fill: gray" size="24"></ng-md-icon>
{{clientId}}
</span>
</span>
</span>
</md-item-template>
</md-autoplete>
</form>
</md-content>
</div>
<!--CSS files-->
<link rel="stylesheet" href="https://ajax.googleapis./ajax/libs/angular_material/1.1.0-rc4/angular-material.min.css">
<link rel="stylesheet" href="https://material.angularjs/1.1.0-rc4/docs.css">
<link rel="stylesheet" href="https://fonts.googleapis./css?family=Roboto:300,400,500,700,400italic">
<link rel="stylesheet" href="/css/style.css">
<!-- Angular Material requires Angular.js Libraries -->
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.3.15/angular.js"></script>
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.3.15/angular-animate.min.js"></script>
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.3.15/angular-route.min.js"></script>
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.3.15/angular-aria.min.js"></script>
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.3.15/angular-messages.min.js"></script>
<script src="https://s3-us-west-2.amazonaws./s.cdpn.io/t-114/svg-assets-cache.js"></script>
<script src="https://ajax.googleapis./ajax/libs/angular_material/1.1.0-rc4/angular-material.min.js"></script>
<script src="//cdnjs.cloudflare./ajax/libs/angular-material-icons/0.7.0/angular-material-icons.min.js"></script>
<!-- Your application bootstrap -->
<script type="text/javascript" src="js/autoplete.js"></script>
</body>
</html>
Here are the server.js
file and the mockData.json file.
"use strict";
//Lets define a port we want to listen to
const PORT = 8080;
//Init Vars
var express = require('express');
var fs = require('fs');
var app = express();
//Init Functions
//we allow CORS: http://enable-cors/server_expressjs.html
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.listen(PORT, function() {
console.log('Example app listening on port ' + PORT + '!');
});
//GET methods
app.get('/getClients', function(req, res, next) {
let assetsQuery = function(array, word) {
let result = false;
array.forEach(function(element, index, array) {
if (element.toLowerCase().trim().includes(word))
result = true;
});
return result;
};
//get parameters from GET: https://scotch.io/tutorials/use-expressjs-to-get-url-and-post-parameters
var query = req.param('word');
let dbQuery = JSON.parse(fs.readFileSync('mockData.json', 'utf8'));
let result = [];
if (query == null || query == "" || typeof query == 'undefined')
result = dbQuery.mockupData;
else {
query = query.toLowerCase().trim();
dbQuery.mockupData.forEach(function(element, index, array) {
if (element.Company_Name.toLowerCase().trim().includes(query) || assetsQuery(element.Assets, query))
result.push(element);
});
}
res.send(result);
});
Fake Data file:
{
"mockupData": [{
"AccountID": "cweu4xy733z06mqv96",
"Company_Name": "Wal - Mart Stores, Inc",
"Assets": ["gme-wal1", "gme-wal2"]
}, {
"AccountID": "3tvjnjzud1jz2xy6ug",
"Company_Name": "Volkswagen Automotive",
"Assets": ["gme-vol1", "gme-aut2"]
}, {
"AccountID": "ht019dupmtb4jinzpo",
"Company_Name": "Vitol Commodities",
"Assets": ["gme-vit1", "gme-2"]
}, {
"AccountID": "l2fd73rbpc48d1hvua",
"Company_Name": "Verizon Telemunications",
"Assets": ["gme-ver1", "gme-tel2"]
}, {
"AccountID": "2iygtyj2do2pi8e4dv",
"Company_Name": "Valero",
"Assets": ["gme-vale1", "gme-valoil2"]
}, {
"AccountID": "1ojav89f9qka85vpwb",
"Company_Name": "United Health Health care",
"Assets": ["gme-usahc1", "gme-uhhc2"]
}, {
"AccountID": "y9ikfaj2qgf18d0vsw",
"Company_Name": "Trafigura Commodities",
"Assets": ["gme-traf1", "gme-traf2"]
}, {
"AccountID": "nxhpt5unxsjedui5sk",
"Company_Name": "Toyota Automotive",
"Assets": ["gme-toy1", "gme-oyota2"]
}, {
"AccountID": "hqu18f8wy43oc5kfde",
"Company_Name": "Total",
"Assets": ["gme-total1", "gme-tot2"]
}, {
"AccountID": "tsc9aures3yjpy2nrr",
"Company_Name": "Tata Group Conglomerate",
"Assets": ["gme-tata1", "gme-grcon2"]
}, {
"AccountID": "paoxb086omzi1uu5zr",
"Company_Name": "State Grid Electric utility",
"Assets": ["gme-sgeu1", "gme-elecs2"]
}, {
"AccountID": "7u2fhcatofgqjzv2tf",
"Company_Name": "Sinopec Group",
"Assets": ["gme-sin1", "gme-sinoil2"]
}, {
"AccountID": "hbg285h3nk206zmdqb",
"Company_Name": "Saudi Aramco",
"Assets": ["gme-sau1", "gme-aram2"]
}, {
"AccountID": "xyg1n25grvl74f69l6",
"Company_Name": "Samsung Conglomerate",
"Assets": ["gme-sam1", "gme-sag2"]
}, {
"AccountID": "aaoexfcqln8peec4dv",
"Company_Name": "Royal Dutch Shell",
"Assets": ["gme-royal1", "gme-forthequeen"]
}, {
"AccountID": "rubvrmy2ucrvh3elrj",
"Company_Name": "Phillips 66",
"Assets": ["gme-phil1", "gme-ips2"]
}, {
"AccountID": "5gmxscwazuokverzbd",
"Company_Name": "Petrobras",
"Assets": ["gme-pedro1", "gme-petro2"]
}, {
"AccountID": "nsx4y558obp62dwn47",
"Company_Name": "PDVSA",
"Assets": ["gme-pdvsa1", "gme-pgas"]
}, {
"AccountID": "80o7d5p4wrx1ueygmx",
"Company_Name": "Microsoft Conglomerate",
"Assets": ["gme-microsoft1", "gme-evil2"]
}, {
"AccountID": "1v14j9i5w8sy4iipuv",
"Company_Name": "McKesson Pharmaceuticals",
"Assets": ["gme-mckesson1", "gme-mckeuticals2"]
}, {
"AccountID": "92ac8fl1dk1nh5v408",
"Company_Name": "Lukoil",
"Assets": ["gme-luko1", "gme-loil2"]
}, {
"AccountID": "pn3w8dxqrzytlmanhe",
"Company_Name": "Kuwait Petroleum Corporation",
"Assets": ["gme-kuwait1", "gme-war2"]
}, {
"AccountID": "35mtlyc6bnbxhuav1d",
"Company_Name": "Koch Industries Conglomerate",
"Assets": ["gme-koch1", "gme-kindus2"]
}, {
"AccountID": "n4gu863njqnndvmk3d",
"Company_Name": "Japan Post Conglomerate",
"Assets": ["gme-jap1", "gme-konichiwa2"]
}, {
"AccountID": "gkrllbxd56r9gi4q7t",
"Company_Name": "Industrial and Commercial Bank of China Financial services",
"Assets": ["gme-china1", "gme-LongLiveTsungLee2"]
}, {
"AccountID": "qgb1gudy460seqgzo3",
"Company_Name": "Honda Automotive",
"Assets": ["gme-honhon1", "gme-autohon2"]
}]
}
Problem
How can I make my dropdown box for the results bigger?
Share Improve this question edited May 23, 2017 at 10:29 CommunityBot 11 silver badge asked Jun 6, 2016 at 15:39 Flame_PhoenixFlame_Phoenix 17.6k40 gold badges144 silver badges284 bronze badges2 Answers
Reset to default 5You could use the non-documented parameter md-dropdown-items
:
<md-autoplete
md-selected-item="selectedItem"
md-search-text="searchText"
md-items="item in getMatches(searchText)"
md-item-text="item.display"
md-dropdown-items="10">
<span md-highlight-text="searchText">{{item.display}}</span>
</md-autoplete>
The default value is 5 (as of version angular-material#ad0581ddd3).
You might also want to adjust this value according to height of the window:
<md-autoplete
md-selected-item="selectedItem"
md-search-text="searchText"
md-items="item in getMatches(searchText)"
md-item-text="item.display"
md-dropdown-items="nbItems">
<span md-highlight-text="searchText">{{item.display}}</span>
</md-autoplete>
and then set nbItems
in your controller. For example:
$scope.nbItems = 5 + $mdMedia('(min-height: 400px)') * 5 + $mdMedia('(min-height: 600px)') * 10;
Thus you will have 5 items if height is lower than 400px, 10 items if less than 600px, and 20 items shown above 600px.
Hope it helps
Note: the md-dropdown-items
parameter does not exist for md-select
, only for md-autoplete
.
Too bad ;)
Background
After much experimentation and reading, I finally found a workaround on how to do it.
My solution is not really a solution to the problem, but more of a hack. The truth is that there is no official support for this, and there will never be, at least in Angular Material 1, which has now been deprecated in order to make Angular Material 2, and has lost official support.
Workaround
Thus my workaround focuses on one suggestion found in github, and it effectively overrides the default CSS:
.md-virtual-repeat-container.md-autoplete-suggestions-container {
height: 24vh;
min-height: 12vh;
max-height: 24vh !important;
}
Explanation & Analysis
This code overrides the default CSS by using !important
and setting custom heights. In this case I am using the vh
measurement, but you can use the px
or any other.
This workaround will work fine if you only have one autoplete with a dropdownbox, or if all the autoplete with dropdownboxes you have are equal.
If however, you have two autopletes different from each other, you will start fighting with your own code because of the override (which will affect all autopletes).
Conclusion
This is, in the end, not a perfect solution, but as long as you don't go too much into autoplete, it should be fine.
I hope this can help someone in the future!