AngularJS smart-table strange behavior with nested objects and st-search

Joao picture Joao · Oct 17, 2014 · Viewed 9.4k times · Source

I'm trying to implement the Smart Table module in my AngularJS app. I'd prefer this over some others mainly because the others seemed require a lot of boilerplate code in my controller and I like to keep my controllers as DRY as possible. But I'm open to other modules that can accomplish the same thing without boilerplate.

It works great when dealing with a straight-up array of objects, but if some of those objects have nested objects, the filtering and sorting has strange behavior.

This will take some explaining so bear with me.

First of all, here is my array of nested objects (shortened for readability here):

$scope.products = [
    {
        'display': 'Live',
        'name': 'LC1D09',
        'category': 'Motor Control',
        'subcategory': 'Contactor',
        'manufacturer': 'Telemecanique',
        'specs': {
            'phase': 3,
            'poles': 3
        },
        'new': {
            'price': 158.95
        },
        'refurbished': {
            'price': 145
        },
        'onlineStores': {
            'amazon': true,
            'ebay': false
        },
        'isCool': true
    },
    {
        'display': 'Pending',
        'name': 'FA32020',
        'category': 'Circuit Breaker',
        'subcategory': 'Molded Case',
        'manufacturer': 'Square D',
        'specs': {
            'phase': 1,
            'poles': 2
        },
        'new': {
            'price': 217.79
        },
        'refurbished': {
            'price': 192.82
        },
        'onlineStores': {
            'amazon': true,
            'ebay': true
        },
        'isCool': false
    }
];
$scope.displayedProducts = $scope.products;

Here's my HTML:

<table st-table="displayedProducts" st-safe-src="products" class="table table-striped table-bordered table-hover">
    <thead>
        <tr>
            <th st-sort="name">Name</th>
            <th st-sort="category">Category</th>
            <th>Subcategory</th>
            <th>Manufacturer</th>
            <th>New Price</th>
            <th>Refurb. Price</th>
            <th>Display</th>
            <th>Specs</th>
            <th>Cool</th>
        </tr>
        <tr>
            <th><input st-search="'name'" placeholder="" class="input-sm form-control" type="search"/></th>
            <th><input st-search="'category'" placeholder="" class="input-sm form-control" type="search"/></th>
            <th><input st-search="'subcategory'" placeholder="" class="input-sm form-control" type="search"/></th>
            <th><input st-search="'manufacturer'" placeholder="" class="input-sm form-control" type="search"/></th>
            <th><input st-search="new.price" placeholder="" class="input-sm form-control" type="search"/></th>
            <th><input st-search="refurbished.price" placeholder="" class="input-sm form-control" type="search"/></th>
            <th><input st-search="'display'" placeholder="" class="input-sm form-control" type="search"/></th>
            <th><input st-search="'specs'" placeholder="" class="input-sm form-control" type="search"/></th>
            <th>
                <select st-search="onlineStores.ebay" class="form-control">
                    <option value=""></option>
                    <option value="true">Yes</option>
                    <option value="false">No</option>
                </select>
            </th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="product in displayedProducts">
            <td>{{product.name}}</td>
            <td>{{product.category}}</td>
            <td>{{product.subcategory}}</td>
            <td>{{product.manufacturer}}</td>
            <td>${{product.new.price | number : 0}}</td>
            <td>${{product.refurbished.price | number : 0}}</td>
            <td>{{product.display}}</td>
            <td>{{product.specs}}</td>
            <td>{{product.onlineStores.ebay}}</td>
        </tr>
    </tbody>
</table>

So this all works fine if my array doesn't have nested objects. But with the nested objects (eg st-search="new.price" I get the following issues (see the screenshot):

  1. Sometimes when I enter text in a "nested object" search field, all other fields that also have nested objects inherit the same value (but the filtering still works fine). This doesn't always do this, just sometimes...
  2. Boolean values on nested objects don't compute correctly. True will show all records, but False will show only the record whose value is False.

Screenshot of Result

Anybody else figured out how to deal with nested objects and the smart-table module?

Answer

Alan picture Alan · Feb 6, 2015

As laurent said, you need to use a custom filter

Use st-set-filter to set your filter

<table st-table="displayedProducts" st-safe-src="products" st-set-filter="customFilter" class="table table-striped table-bordered table-hover">

In your module, define a custom filter

angular.module('myModule').filter('customFilter', ['$parse', function($parse) {
    return function(items, filters) {
        var itemsLeft = items.slice();

        Object.keys(filters).forEach(function(model) {
            var value = filters[model],
                getter = $parse(model);

            itemsLeft = itemsLeft.filter(function(item) {
                return getter(item) === value;
            });
        });

        return itemsLeft;
    };
}])