私の目標は、ループされたオブジェクトのプロパティとして設定されるフォーマットフィルターを適用することです。
このオブジェクトの配列を取得する:
[
{
"value": "test value with null formatter",
"formatter": null,
},
{
"value": "uppercase text",
"formatter": "uppercase",
},
{
"value": "2014-01-01",
"formatter": "date",
}
]
私が書いているテンプレートコードはこれです:
<div ng-repeat="row in list">
{{ row.value | row.formatter }}
</div>
そして、私はこの結果を期待しています:
test value with null formatter
UPPERCASE TEXT
Jan 1, 2014
しかし、おそらくこのコードはエラーをスローします:
Unknown provider: row.formatterFilterProvider <- row.formatterFilter
{{}}内の「フォーマッター」パラメーターを解析する方法を想像することはできません。誰も私を助けることができますか?
Plunkrを参照してください http://plnkr.co/edit/YnCR123dRQRqm3owQLcs?p=preview
|
はangularコンストラクトで、その名前の定義済みフィルターを見つけて左側の値に適用します。必要なのは、フィルターnameを引数として使用し、適切なフィルターを呼び出します (fiddle) (M59のコードから適応):
HTML:
<div ng-repeat="row in list">
{{ row.value | picker:row.formatter }}
</div>
Javascript:
app.filter('picker', function($filter) {
return function(value, filterName) {
return $filter(filterName)(value);
};
});
@karlgoldのコメントのおかげで、ここに引数をサポートするバージョンがあります。最初の例ではadd
フィルターを直接使用して既存の番号に数字を追加し、2番目の例ではuseFilter
フィルターを使用して文字列でadd
フィルターを選択し、引数を渡します- (フィドル) :
HTML:
<p>2 + 3 + 5 = {{ 2 | add:3:5 }}</p>
<p>7 + 9 + 11 = {{ 7 | useFilter:'add':9:11 }}</p>
Javascript:
app.filter('useFilter', function($filter) {
return function() {
var filterName = [].splice.call(arguments, 1, 1)[0];
return $filter(filterName).apply(null, arguments);
};
});
私はこれらの答えの背後にある概念が好きですが、それらが最も柔軟な可能な解決策を提供するとは思わない。
私が本当にやりたかったこと、そして一部の読者が同じことを感じると確信しているのは、フィルター式を動的に渡して、適切な結果を評価して返すことです。
したがって、1つのカスタムフィルターで次のすべてを処理できます。
{{ammount | picker:'currency:"$":0'}}
{{date | picker:'date:"yyyy-MM-dd HH:mm:ss Z"'}}
{{name | picker:'salutation:"Hello"'}}
//別のカスタムフィルターを適用する
$interpolate
サービスをカスタムフィルターに利用する次のコードを思い付きました。 jsfiddle を参照してください:
Javascript
myApp.filter('picker', function($interpolate ){
return function(item,name){
var result = $interpolate('{{value | ' + arguments[1] + '}}');
return result({value:arguments[0]});
};
});
動作させる1つの方法は、バインディングに関数を使用し、その関数内でフィルタリングを行うことです。これは最良のアプローチではないかもしれません:ライブデモ(クリック)
<div ng-repeat="row in list">
{{ foo(row.value, row.filter) }}
</div>
JavaScript:
$scope.list = [
{"value": "uppercase text", "filter": "uppercase"}
];
$scope.foo = function(value, filter) {
return $filter(filter)(value);
};
私はやや粗雑な何かをすることになりましたが、あまり関与していません:
HTML:
三項演算子を使用して、行にフィルターが定義されているかどうかを確認します。
ng-bind="::data {{row.filter ? '|' + row.filter : ''}}"
JS:
Javascriptのデータ配列にフィルターを追加します。
, {
data: 10,
rowName: "Price",
months: [],
tooltip: "Price in DKK",
filter: "currency:undefined:0"
}, {
これは私が使用するものです(Angular Version 1.3.0-beta.8 accidental-haiku)。
このフィルターを使用すると、フィルターオプションの有無にかかわらずフィルターを使用できます。
applyFilterは、Angularにフィルターが存在するかどうかを確認します。フィルターが存在しない場合は、ブラウザーコンソールにフィルター名を含むエラーメッセージが表示されます...
次のフィルターは存在しません:greenBananas
ng-repeatを使用すると、一部の値が未定義になります。 applyFilterは、ソフトフェールでこれらの問題を処理します。
app.filter( 'applyFilter', ['$filter', '$injector', function($filter, $injector){
var filterError = "The following filter does not exist: ";
return function(value, filterName, options){
if(noFilterProvided(filterName)){ return value; }
if(filterDoesNotExistInAngular(filterName)){ console.error(filterError + "\"" + filterName + "\""); return value; }
return $filter(filterName)(value, applyOptions(options));
};
function noFilterProvided(filterName){
return !filterName || typeof filterName !== "string" || !filterName.trim();
}
function filterDoesNotExistInAngular(filterName){
return !$injector.has(filterName + "Filter");
}
function applyOptions(options){
if(!options){ return undefined; }
return options;
}
}]);
次に、必要なフィルターを使用します。これにはオプションがある場合とない場合があります。
// Where, item => { name: "Jello", filter: {name: "capitalize", options: null }};
<div ng-repeat="item in items">
{{ item.name | applyFilter:item.filter.name:item.filter.options }}
</div>
または、テーブルを構築するときに、個別のデータ構造で使用できます。
// Where row => { color: "blue" };
// column => { name: "color", filter: { name: "capitalize", options: "whatever filter accepts"}};
<tr ng-repeat="row in rows">
<td ng-repeat="column in columns">
{{ row[column.name] | applyFilter:column.filter.name:column.filter.options }}
</td>
</tr>
より具体的な値を渡す必要がある場合は、このような引数を追加できます...
// In applyFilter, replace this line
return function(value, filterName, options){
// with this line
return function(value, filterName, options, newData){
// and also replace this line
return $filter(filterName)(value, applyOptions(options));
// with this line
return $filter(filterName)(value, applyOptions(options), newData);
次に、HTMLでフィルターにrowオブジェクトのキーも必要になる場合があります
// Where row => { color: "blue", addThisToo: "My Favorite Color" };
// column => { name: "color", filter: { name: "capitalize", options: "whatever filter accepts"}};
<tr ng-repeat="row in rows">
<td ng-repeat="column in columns">
{{ row[column.name] | applyFilter:column.filter.name:column.filter.options:row.addThisToo }}
</td>
</tr>
Ng-tableの新しいバージョンでは、列構成に基づいた動的なテーブル作成(ng-dynamic-table)が可能です。日付フィールドの書式設定は、列配列のフィールド値に書式を追加するのと同じくらい簡単です。
与えられた
{
"name": "Test code",
"dateInfo": {
"createDate": 1453480399313
"updateDate": 1453480399313
}
}
columns = [
{field: 'object.name', title: 'Name', sortable: 'name', filter: {name: 'text'}, show: true},
{field: "object.dateInfo.createDate | date :'MMM dd yyyy - HH:mm:ss a'", title: 'Create Date', sortable: 'object.dateInfo.createDate', show: true}
]
<table ng-table-dynamic="controller.ngTableObject with controller.columns" show-filter="true" class="table table-condensed table-bordered table-striped">
<tr ng-repeat="row in $data">
<td ng-repeat="column in $columns">{{ $eval(column.field, { object: row }) }}</td>
</tr>
</table>
この投稿のクレジットはJason Goemaatにあります。
使用方法は次のとおりです。
$scope.table.columns = [{ name: "June 1 2015", filter: "date" },
{ name: "Name", filter: null },
] etc...
<td class="table-row" ng-repeat="column in table.columns">
{{ column.name | applyFilter:column.filter }}
</td>
app.filter('applyFilter', [ '$filter', function( $filter ) {
return function ( value, filterName ) {
if( !filterName ){ return value; } // In case no filter, as in NULL.
return $filter( filterName )( value );
};
}]);
私は少し異なるニーズを持っていたので、上記の答えを少し変更しました($interpolate
ソリューションは同じ目標を達成しますが、まだ制限されています):
angular.module("myApp").filter("meta", function($filter)
{
return function()
{
var filterName = [].splice.call(arguments, 1, 1)[0] || "filter";
var filter = filterName.split(":");
if (filter.length > 1)
{
filterName = filter[0];
for (var i = 1, k = filter.length; i < k; i++)
{
[].Push.call(arguments, filter[i]);
}
}
return $filter(filterName).apply(null, arguments);
};
});
使用法:
<td ng-repeat="column in columns">{{ column.fakeData | meta:column.filter }}</td>
データ:
{
label:"Column head",
description:"The label used for a column",
filter:"percentage:2:true",
fakeData:-4.769796600014472
}
(percentage
はnumber
から構築されるカスタムフィルターです)
フィルタが存在するかどうかのチェックを追加し、デフォルトでは最初の引数を返さない場合、@ Jason Goemaatの回答を少し改善しました。
.filter('useFilter', function ($filter, $injector) {
return function () {
var filterName = [].splice.call(arguments, 1, 1)[0];
return $injector.has(filterName + 'Filter') ? $filter(filterName).apply(null, arguments) : arguments[0];
};
});