设置自定义高度角度材质自动完成下拉列表

时间:2016-06-06 15:39:26

标签: javascript css angularjs autocomplete angular-material

背景

我正在使用Angular Material进行自定义自动完成,我想将自动完成下拉结果框的高度设置为更大的值。

研究

为了达到这个目的,我做了一个研究并得出结论,Angular Material不支持这个,并且这个问题只会在Angular Material 2中解决(将发布给AngularJS2):

阅读后,我意识到有些人找到了解决这个限制的方法(Angular Material Design Layout custom sizes),但无论我尝试什么,我都可以看到他们的任何建议都有效。< / p>

代码

我的示例应用程序由index.htmlautocomplete.js文件和带有mockData.json文件的server.js文件组成。

以下是index.htmlautocomplete.jsstyle.css个文件。由于我在Cloud9中托管此示例,如果服务器处于开启状态,您可以看到它正在运行!

&#13;
&#13;
/*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-autocomplete-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));
    }
}
&#13;
.autocompletedemoCustomTemplate .autocomplete-custom-template li {
    border-bottom: 1px solid #ccc;
    height: auto;
    padding-top: 8px;
    padding-bottom: 8px;
    white-space: normal;
}

.autocompletedemoCustomTemplate .autocomplete-custom-template li:last-child {
    border-bottom-width: 0;
}

.autocompletedemoCustomTemplate .autocomplete-custom-template .item-title,
.autocompletedemoCustomTemplate .autocomplete-custom-template .item-metadata {
    display: block;
    line-height: 2;
}

.autocompletedemoCustomTemplate .autocomplete-custom-template .item-title md-icon {
    height: 18px;
    width: 18px;
}
&#13;
<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="autocompletedemoCustomTemplate" ng-app="MyApp">
        <md-content layout-padding="" layout="column">
            <form ng-submit="$event.preventDefault()">

                <md-autocomplete 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="autocomplete-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">
                                    &emsp;<ng-md-icon icon="subdirectory_arrow_right" style="fill: gray" size="24"></ng-md-icon>
                                    {{clientId}}
                                </span>
                            </span>
                        </span>

                    </md-item-template>
                </md-autocomplete>
            </form>
        </md-content>
    </div>



    <!--CSS files-->
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0-rc4/angular-material.min.css">
    <link rel="stylesheet" href="https://material.angularjs.org/1.1.0-rc4/docs.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/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.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-animate.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-route.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-aria.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-messages.min.js"></script>
    <script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-114/svg-assets-cache.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0-rc4/angular-material.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular-material-icons/0.7.0/angular-material-icons.min.js"></script>

    <!-- Your application bootstrap  -->
    <script type="text/javascript" src="js/autocomplete.js"></script>
</body>

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

以下是server.js文件和mockData.json文件。

"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.org/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);
});

虚假数据文件:

{
    "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-com2"]
    }, {
        "AccountID": "l2fd73rbpc48d1hvua",
        "Company_Name": "Verizon Telecommunications",
        "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-trafcom2"]
    }, {
        "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-sacomg2"]
    }, {
        "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"]
    }]
}

问题

如何让我的下拉框更大?

2 个答案:

答案 0 :(得分:4)

您可以使用未记录的参数md-dropdown-items

<md-autocomplete 
    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-autocomplete>

默认值为5(版本为angular-material#ad0581ddd3)。

您可能还想根据窗口的高度调整此值:

<md-autocomplete
    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-autocomplete>

然后在控制器中设置nbItems。例如:

$scope.nbItems = 5 + $mdMedia('(min-height: 400px)') * 5 + $mdMedia('(min-height: 600px)') * 10;

因此,如果高度低于400px,则将有5个项目,如果低于600px,则将有10个项目,如果高于600px,则将有20个项目。

希望有所帮助

注意:md-dropdown-items的{​​{1}}参数不存在,仅适用于md-select

太糟糕了;)

答案 1 :(得分:3)

背景

经过多次实验和阅读,我终于找到了解决方法。

我的解决方案并不是解决问题的方法,而是更多的黑客攻击。事实上,没有官方的支持,至少在Angular Material 1中,永远不会有为了制作Angular Material 2而被弃用的东西,并且已经失去官方支持。

解决方法

因此,我的解决方法集中在github中找到的一个建议,它有效地覆盖了默认的CSS:

.md-virtual-repeat-container.md-autocomplete-suggestions-container {
    height: 24vh;
    min-height: 12vh;
    max-height: 24vh !important;
}

解释&amp;分析

此代码使用!important覆盖默认CSS并设置自定义高度。在这种情况下,我使用vh测量,但您可以使用px或任何其他。

如果您只有一个带下拉框的自动填充功能,或者所有带有下拉框的自动填充功能相同,则此变通方法可以正常工作。

但是,如果您有两个彼此不同的自动填充,则由于覆盖(将影响所有自动填充),您将开始使用自己的代码。

结论

最后,这不是一个完美的解决方案,但只要你不做太多的自动完成,它应该没问题。

我希望这可以帮助将来的某个人!