Closed craggsi closed 9 years ago
I have a same problem. Filter doesn't work for nested property.
I'm also having the same problem. This is the workaround (it only handles the case 'a.b') that I'm using:
getData: function($defer, params) {
var filters = {};
angular.forEach(params.filter(), function(value, key) {
var splitedKey = key.match(/^([a-zA-Z]+)\.([a-zA-Z]+)$/);
if(!splitedKey) {
filters[key] = value;
return;
}
splitedKey = splitedKey.splice(1);
var father = splitedKey[0],
son = splitedKey[1];
filters[father] = {};
filters[father][son] = value;
});
// use build-in angular filter
var filteredData = params.filter() ? $filter('filter')(data, filters) : data;
}
@assisrafael thanks for the idea. I extended it to go multiple levels deep.
getData: function($defer, params) {
var filters = {};
angular.forEach(params.filter(), function(value, key) {
if (key.indexOf('.') === -1) {
filters[key] = value;
return;
}
var createObjectTree = function (tree, properties, value) {
if (!properties.length) {
return value;
}
var prop = properties.shift();
if (!prop || !/^[a-zA-Z]/.test(prop)) {
throw new Error('invalid nested property name for filter');
}
tree[prop] = createObjectTree({}, properties, value);
return tree;
};
var filter = createObjectTree({}, key.split('.'), value);
angular.extend(filters, filter);
});
var filteredData = params.filter() ? $filter('filter')(data, filters) : data;
}
Thanks for sharing.
Just to let you guys know: if you tried to filter on two nested properties at the same time it does not work. I explained the problem here: https://github.com/angular/angular.js/issues/9698.
The solution is to both use a custom comparator function and redefine the filters as explained here (by the way I don't think going deeper than one level is any use when redefining the filter, at least in my solution as I use eval) :
compareForNestedFiltering = function (actual, expected) {
function contains (actualVal, expectedVal) {
return actualVal.toString().toLowerCase().indexOf(expectedVal.toString().trim().toLowerCase()) !== -1;
}
if(typeof expected !== 'object') return contains(actual, expected);
var result = Object.keys(expected).every(function (key) {
return contains(eval('actual.'+key), eval('expected.'+key));
});
return result;
};
formatNestedFilters = function (filters) {
var reformattedFilters = {};
angular.forEach(filters, function(value, key) {
var firstDotPos = key.indexOf('.');
if(firstDotPos == -1) return reformattedFilters[key] = value;
var firstKey = key.slice(0, firstDotPos);
var remainingKey = key.slice(firstDotPos+1);
if (!reformattedFilters.hasOwnProperty(firstKey)) reformattedFilters[firstKey] = {};
reformattedFilters[firstKey][remainingKey] = value;
});
return reformattedFilters;
};
var filteredData = $filter('filter')(data, formatNestedFilters(params.filter()), compareForNestedFiltering )
Thanks for all your posts! Back when I posted the issue, time was against me, so I created a flat view model and mapped my nested object hierarchy to it. I suppose it all depends on your situation whether this or one of the above approaches is needed.
Regards Simon
Thank you, craggsi and barroudjo for bringing up this problem and sharing the workaround.
@barroudjo thanks that worked.
Another workaround that is a bit of hack but I like it. Only works in newer browsers that support javascript setters though:
Object.defineProperties(this.prototype, {
vesselCode: {
get: function() {
if (!this.vessel) {
return;
}
return this.vessel.code;
}
}
});
In this case in the UI you can just use something like this:
<td data-title="'Vessel'" sortable="'vesselCode'" filter="{ 'vesselCode': 'text' }">
{{project.vessel.code }}
</td>
@iyel fixed this in master?
@hendricius I was closing issues just to understand which of them are still relevant. Please read https://github.com/esvit/ng-table#submitting-an-issue
Here's how to reproduce:-
Edit the Demo 4 example (Table with filters). Add an additional 'Status' property to each data row. Note this is a complex object property:-
var data = [{name: "Moroni", age: 50, Status: { Id:1, Description: 'AVAILABLE' }}, {name: "Tiancum", age: 43, Status: { Id:1, Description: 'AVAILABLE' }}, {name: "Jacob", age: 27, Status: { Id:1, Description: 'AVAILABLE' }}, {name: "Nephi", age: 29, Status: { Id:1, Description: 'AVAILABLE' }}];
Finally, edit the HTML table to include an additional column as shown below:-
"< td data-title="'Status'" filter="{ 'Status.Description' : 'text' }" > {{user.Status.Description}} < /td >"
When using AngularJS v1.2.0-rc.2, the filter works for both the simple property (name) and the complex property, however when you reference AngularJS v1.2.21, the filter dismisses valid Status Description entries and so all rows are filtered out.
For example, the filter { "Status.Description": "av" } should return all data rows, but instead all rows are filtered out.
No errors are shown in the browser console.