web-dev-qa-db-ja.com

Angular 1つのフィールドのみのui-selectフィルタリング

状況:

angularアプリで angular ui-select を使用して、データベースから人を検索して選択します。

1つ以外は問題なく動作しています。ユーザーは、名前と電子メールという2つの基準を使用して、ユーザー間でフィルタリングできる必要があります。

通常のangularフィルターを使用すると、そのうちの1つだけをフィルターできます。両方のフィールドをフィルターしようとしても、機能しません。

1つのフィールドでの使用例:

 <ui-select multiple ng-model="database_people.selectedPeople" theme="select2" ng-disabled="disabled" style="width:100%">

    <ui-select-match placeholder="Select person...">{{$item.name}} &lt; {{$item.email}} &gt;</ui-select-match>

    <ui-select-choices repeat="person2 in list_people | filter: {name: $select.search, db_data_type_id: 5}">

            <div ng-bind-html="person2.name | highlight: $select.search"></div>

                <small>
                    email: <span ng-bind-html="''+person2.email | highlight: $select.search"></span>
               </small>

    </ui-select-choices>

 </ui-select>


フィルターの2つのフィールドで機能しない例:

 <ui-select multiple ng-model="database_people.selectedPeople" theme="select2" ng-disabled="disabled" style="width:100%">

    <ui-select-match placeholder="Select person...">{{$item.name}} &lt; {{$item.email}} &gt;</ui-select-match>

    <ui-select-choices repeat="person2 in list_people | filter: {name: $select.search, email: $select.search, db_data_type_id: 5}">

            <div ng-bind-html="person2.name | highlight: $select.search"></div>

                <small>
                    email: <span ng-bind-html="''+person2.email | highlight: $select.search"></span>
               </small>

    </ui-select-choices>

 </ui-select>

奇妙なことに、それは実際には最初の文字に対してのみ機能します。最初の文字を入力すると、名前とメールの両方のフィールドで強調表示されます。しかし、2番目の文字を入力すると、それは機能しなくなります(コンソールでエラーは発生しませんでした)。


PROTEMPFILTER FROM ANGULAR SAMPLESを使用した温度

 <ui-select multiple ng-model="database_people.selectedPeople" theme="select2" ng-disabled="disabled" style="width:100%">

    <ui-select-match placeholder="Select person...">{{$item.name}} &lt; {{$item.email}} &gt;</ui-select-match>

    <ui-select-choices repeat="person2 in list_people | propsFilter: {name: $select.search, email: $select.search, db_data_type_id: 5}">

            <div ng-bind-html="person2.name | highlight: $select.search"></div>

                <small>
                    email: <span ng-bind-html="''+person2.email | highlight: $select.search"></span>
               </small>

    </ui-select-choices>

 </ui-select>

この場合、完全に壊れ、select2にはデータがなくなり、コンソールにエラーが表示されます。

Cannot read property 'toString' of null

Cannot read property 'length' of undefined


質問(S):

複数のフィールド間でフィルタリングするにはどうすればよいですか?通常のフィルターを使用してそれを行うことはできますか?または、カスタムフィルターを使用する必要がありますか?しかし、この場合、なぜ正しく動作しないのでしょうか。

どうもありがとうございました!

17
FrancescoMussi

たぶん、同じ値($ select.search)がフィルターの電子メールと名前の両方に使用されているためです。

<ui-select-choices repeat="person2 in list_people | filter: {name: $select.search, email: $select.search, db_data_type_id: 5}">
...

これは、最初の文字でのみ機能する理由も説明します。

これを修正するには、各フィルターに個別の値を使用します。

<ui-select-choices repeat="person2 in list_people | filter: {name: $select.search.name, email: $select.search.email, db_data_type_id: 5}">
...
7
T4deu

以下のようなプロパティフィルターを使用できます。

 <ui-select   ng-model="emplyee" theme="bootstrap">
 <ui-select-match placeholder="Select ...">{{$select.selected.firstName+" "+$select.selected.lastName}}</ui-select-match>
 <ui-select-choices repeat="emp in employees | propertyFilter: {firstName:$select.search, lastName:$select.search}">
 <span ng-bind-html="emp.firstName+' '+emp.lastName | highlight: $select.search"></span>
 </ui-select-choices>

以下のようにpropertyFilterを変更する必要があります。

.filter('propertyFilter', function($log) {
 return function(items, props) {
    var out = [];
    if (angular.isArray(items)) {
    items.forEach(function(item) {
        var itemMatches = false;
        var keys = Object.keys(props);
        var optionValue = '';
        for (var i = 0; i < keys.length; i++) {
             optionValue = item[keys[i]] ? optionValue + item[keys[i]].toString().toLowerCase().replace(/ /g, '') : '';
        }
        for (var j = 0; j < keys.length; j++) {
            var text = props[keys[j]].toLowerCase().replace(/ /g, '');
            if (optionValue.indexOf(text) !== -1) {
               itemMatches = true;
               break;
            }
        }
        if (itemMatches) {
            out.Push(item);
        }
        });
        } else {
            // Let the output be the input untouched
            out = items;
        }

        return out;
    };
})

オプション値全体で検索を実行できます。たとえば、オプションに「peter parker」がある場合、「peter」、「parker」、「peter parker」、「peterparker」で検索したり、peter parkerの任意の文字の間に複数のスペースを置いて検索したりすることもできます。

10
kunsingh

Kunsinghからの回答のように、いくつかの問題が浮かんでいるのを見て、同じような問題を解決し始めました。私の場合、複数のオブジェクトを検索していましたが、論理的に削除されたレコードをクライアントに送信し、オプションでリストでそれらをフィルター処理します。ドロップダウンについては、APIを変更する必要なく、常に削除する必要がありました。

これは、オブジェクトの検索を含む私の変更されたバージョンです。明らかにこれは、すべてのテーブルにDeletedという名前のint列があり(私にとっては一意のキーの一部であり、削除時にID値に設定されている)、クライアントに渡した場合にのみ機能します。

後で、オブジェクトを再帰的に検索できるようにさらに変更する予定です。

App.filter('dropdownFilter', function () {
    return function (items, props: Object, keyvalue?) {
    var out = [];

        if (angular.isArray(items)) {
            items.forEach(function (item) {
                var itemMatches = false;
                var canbreak = false;

                // Filter out logically deleted records
                if (item.Deleted != 0)
                    itemMatches = false;
                else {
                    var keys = Object.keys(props);

                    for (var i = 0; i < keys.length; i++) {
                        var prop: string = keys[i];
                        var text = "";
                        // If an object, e.g. searching deep, such as Project: {ProjectName: $select.search}
                        // Then iterate through the object to find values.  
                        // NOTE: This one searches one deep from each object,
                        // e.g. Project.ProjectName
                        //      Project.User.LastName WILL NOT WORK.
                        if (angular.isObject(props[prop])) {
                            angular.forEach(props[prop], function (value, key) {
                                text = value.toLowerCase();
                                if (item[prop][key].toLowerCase().indexOf(text) !== -1) {
                                    itemMatches = true;
                                    canbreak = true;
                                }
                            });
                            if (canbreak)
                                break;
                        }
                        // If it's a simple array, then woo!
                        else {
                            text = props[prop].toLowerCase();
                            if (item[prop] != undefined && item[prop].toString().toLowerCase().indexOf(text) !== -1) {
                                itemMatches = true;
                                break;
                            }
                        }
                    }
                }

                if (itemMatches) {
                    out.Push(item);
                }
            });
        }
        else {
            // Let the output be the input untouched
            out = items;
        }

    return out;
    }
});

使用中のサンプル(angularにselect2を使用)。これは、国/州のドロップダウンであり、国のサブオブジェクトとして国が含まれています。

<ui-select ng-model="personneladdress.StateID" theme="select2" class="select2">
    <ui-select-match placeholder="{{language.State}}">{{$select.selected.StateName}}</ui-select-match>
    <ui-select-choices repeat="item.StateID as item in State | dropdownFilter: {StateName: $select.search, Country: {CountryName: $select.search}}">
        <span ng-bind-html="item.StateName | highlight: $select.search"></span><br />
        <small>
            <span ng-bind-html="''+item.Country.CountryName | highlight: $select.search"></span>
        </small>
    </ui-select-choices>
</ui-select>
2
dbmuller

私はこのコードを使用してこの問題を解決しました:

<ui-select-choices repeat="person2 in list_people | filter: $select.search" >

Ui-select-matchでは、2つのフィールドを使用します。

<ui-select-match placeholder="select One...">
   {{$item.field1}} - {{$item.field2}}
</ui-select-match>
0
Pasha Gharibi