tudor-malene / Easygrid

Grails plugin - simple and declarative way of defining a DataGrid
Apache License 2.0
27 stars 24 forks source link

filtering with formatName #130

Open danyyacoub opened 9 years ago

danyyacoub commented 9 years ago

Hi, I have a domain

class Recipe {
     Ingredient ingredient
}

in my grid I have

            ingredient
            {
                label "ingredient.label"
                formatName 'ingredientFormat'
            }

ingredientFormat = {"<span class='ingredientDetail showDetail' data-id='${it.id}'>${it.name}</span>";}

The idea of the formatter is to make the item clickable to show its detail.

The problem is to make this happen, i need the whole ingredient object and not just the ingredient name.

How can I make the column searchable in this case, using filterClosure to search by name.

Thanks

tudor-malene commented 9 years ago

There's multiple way you can do this: 1)

columns{
   'ingredient.name'{
       value{
               "<span class='ingredientDetail showDetail' data-id='${it.id}'>${it.name}</span>";
       }
   }
}

This will filter and sort on the ingredient name

2) If you are using jqgrid, you can use a javascript formatter see http://199.231.186.169:8080/easygrid/author/jqgrid If you do this, you will have to define a hidden ingredient id column which you will use in the javascript function:

columns{
   'ingredient.name'{ }
   'ingredient.id'{
                jqgrid {
                    hidden = true
                }
   }
} 
danyyacoub commented 9 years ago

I'm using datatables, so i'll use the value closure. thanks!

danyyacoub commented 9 years ago

using the value closure I'm getting the following error on filter : (I had to change the value from it.id, it.name to it.ingredient.id, it.ingredient.name)

Message: null
Line | Method
    ->>  286 | lastProperty         in org.grails.plugin.easygrid.GridUtils
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    359 | getCriteria          in org.grails.plugin.easygrid.datasource.GormDatasourceService
|    184 | doCall . . . . . . . in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|    339 | doCall               in     org.grails.plugin.easygrid.datasource.GormDatasourceService$_createFiltersClosure_closure11
|     28 | doCall . . . . . . . in org.grails.plugin.easygrid.Filters$_postorder_closure4
|     27 | postorder            in org.grails.plugin.easygrid.Filters
|    323 | createFiltersClosure in org.grails.plugin.easygrid.datasource.GormDatasourceService
|    184 | doCall               in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|    251 | doCall . . . . . . . in     org.grails.plugin.easygrid.datasource.GormDatasourceService$_createWhereQuery_closure9
|    242 | createWhereQuery     in org.grails.plugin.easygrid.datasource.GormDatasourceService
tudor-malene commented 9 years ago

Can you show me your entire grid?

danyyacoub commented 9 years ago
        static grids = {
            recipeGrid {
                dataSourceType 'gorm'
                    domainClass Recipe
                gridImpl 'dataTables'
                fixedColumns true
                columns {
            user
            {
                label "user.label"
                property 'user.name'
            }
          'ingredient.name'{
                    value{
                              "<span class='ingredientDetail showDetail' data-id='${it.ingredient.id}'>${it.ingredient.name}</span>";
                              }
           }
            deliveryType
            {
                label "deliveryType.label"
                value {instance -> instance.deliveryType as String}
            }
            deliveryDate
            { label "deliveryDate.label"
                enableFilter false
            }
            totalPrice
            {
                label "totalPrice.label"
            }
            dateCreated
            { label "dateCreated.label"
                enableFilter false
            }
        }
    }
}
tudor-malene commented 9 years ago

Hi , You can write your grid like this :

def recipeGrid = {
    // you can add these to settings to your EasygriConfig file in the defaults section, so you keep your grid clean
    gridImpl 'dataTables'
    labelPrefix ''

    domainClass Recipe
    fixedColumns true
    columns {
        user {
            property 'user.name'
        }
        'ingredient.name' {
            value {
                "<span class='ingredientDetail showDetail' data-id='${it.ingredient.id}'>${it.ingredient.name}</span>";
            }
        }
        deliveryType {
            formatter { it as String }
        }
        deliveryDate {
            enableFilter false
        }
        totalPrice
        dateCreated {
            enableFilter false
        }
    }
}

(you will have to remove the suffix 'Grid' from the gsp )

The grid looks good otherwise. It's one thing that I notice: does a recipe has only one ingredient?

danyyacoub commented 9 years ago

Hi, Ye the recipe has only one ingredient. it's the main ingredient. Your grid works except for the filter in both the ingredient and the delivery type :

for ingredient when filtering i get :

 | Error 2014-11-30 19:53:33,786 [http-bio-8080-exec-2] ERROR errors.GrailsExceptionResolver  -     NullPointerException occurred when processing request: [GET] /CitySweet/recipe/recipeRows - parameters:
iSortCol_0: 0
sEcho: 5
bSortable_5: true
bSortable_6: true
bRegex_0: false
bSortable_3: true
sColumns: user,ingredient.name,deliveryType,deliveryDate,totalPrice,orderStatus,dateCreated
bRegex_1: false
bSortable_4: true
bSortable_1: true
bSortable_2: true
bSortable_0: true
bRegex_6: false
iColumns: 7
bRegex_4: false
bRegex_5: false
bRegex_2: false
bRegex_3: false
_: 1417369994415
sSearch_3: 
sSearch_2: 
sSearch_1: a
mDataProp_6: 6
sSearch_0: 
mDataProp_5: 5
iSortingCols: 1
format: 
bRegex: false
iDisplayLength: 10
iDisplayStart: 0
sSearch: 
bSearchable_2: true
bSearchable_1: true
sSortDir_0: asc
bSearchable_0: true
mDataProp_0: 0
bSearchable_6: false
bSearchable_5: true
bSearchable_4: true
bSearchable_3: false
mDataProp_4: 4
mDataProp_3: 3
sSearch_6: 
mDataProp_2: 2
sSearch_5: 
mDataProp_1: 1
sSearch_4: 
Stacktrace follows:
Message: null
    Line | Method
->>  286 | lastProperty         in org.grails.plugin.easygrid.GridUtils
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    359 | getCriteria          in org.grails.plugin.easygrid.datasource.GormDatasourceService
|    184 | doCall . . . . . . . in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|    339 | doCall               in org.grails.plugin.easygrid.datasource.GormDatasourceService$_createFiltersClosure_closure11
|     28 | doCall . . . . . . . in org.grails.plugin.easygrid.Filters$_postorder_closure4
|     27 | postorder            in org.grails.plugin.easygrid.Filters
|    323 | createFiltersClosure in org.grails.plugin.easygrid.datasource.GormDatasourceService
|    184 | doCall               in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|    251 | doCall . . . . . . . in org.grails.plugin.easygrid.datasource.GormDatasourceService$_createWhereQuery_closure9
|    242 | createWhereQuery     in org.grails.plugin.easygrid.datasource.GormDatasourceService
|    196 | list . . . . . . . . in     ''
|    184 | doCall               in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|     31 | methodMissing . . .  in org.grails.plugin.easygrid.EasygridDispatchService
|    170 | doCall               in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|     66 | gridData . . . . . . in org.grails.plugin.easygrid.EasygridService
|    184 | doCall               in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|     75 | doCall . . . . . . . in org.grails.plugin.easygrid.EasygridInitService$_registerControllerMethods_closure4
|    217 | guard                in org.grails.plugin.easygrid.EasygridService
|    184 | doCall . . . . . . . in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|    110 | doCall               in org.grails.plugin.easygrid.EasygridInitService$_registerControllerMethods_closure9_closure17
|    189 | doFilter . . . . . . in grails.plugin.cache.web.filter.PageFragmentCachingFilter
|     63 | doFilter             in grails.plugin.cache.web.filter.AbstractFilter
|    150 | invoke . . . . . . . in net.bull.javamelody.JspWrapper
|    285 | invoke               in net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler
|    198 | doFilter . . . . . . in net.bull.javamelody.MonitoringFilter
|    176 | doFilter             in     ''
|     53 | doFilter . . . . . . in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
|     49 | doFilter             in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
|     82 | doFilter . . . . . . in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
|   1142 | runWorker            in java.util.concurrent.ThreadPoolExecutor
|    617 | run . . . . . . . .  in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run                  in java.lang.Thread

filtering on deliveryType i get :


| Error 2014-11-30 19:56:18,798 [http-bio-8080-exec-7] ERROR errors.GrailsExceptionResolver  - PowerAssertionError occurred when processing request: [GET] /CitySweet/recipe/recipeRows - parameters:
iSortCol_0: 0
sEcho: 7
bSortable_5: true
bSortable_6: true
bRegex_0: false
bSortable_3: true
sColumns: user,ingredient.name,deliveryType,deliveryDate,totalPrice,orderStatus,dateCreated
bRegex_1: false
bSortable_4: true
bSortable_1: true
bSortable_2: true
bSortable_0: true
bRegex_6: false
iColumns: 7
bRegex_4: false
bRegex_5: false
bRegex_2: false
bRegex_3: false
_: 1417369994417
sSearch_3: 
sSearch_2: a
sSearch_1: 
mDataProp_6: 6
sSearch_0: 
mDataProp_5: 5
iSortingCols: 1
format: 
bRegex: false
iDisplayLength: 10
iDisplayStart: 0
sSearch: 
bSearchable_2: true
bSearchable_1: true
sSortDir_0: asc
bSearchable_0: true
mDataProp_0: 0
bSearchable_6: false
bSearchable_5: true
bSearchable_4: true
bSearchable_3: false
mDataProp_4: 4
mDataProp_3: 3
sSearch_6: 
mDataProp_2: 2
sSearch_5: 
mDataProp_1: 1
sSearch_4: 
assert filter
       |
       null. Stacktrace follows:
Message: Executing action [recipeRows] of controller [com.acme.citysweet.entities.RecipeController]  caused exception: assert filter
       |
       null
    Line | Method
->>  189 | doFilter  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     63 | doFilter  in grails.plugin.cache.web.filter.AbstractFilter
|    150 | invoke .  in net.bull.javamelody.JspWrapper
|    285 | invoke    in net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler
|    198 | doFilter  in net.bull.javamelody.MonitoringFilter
|    176 | doFilter  in     ''
|     53 | doFilter  in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
|     49 | doFilter  in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
|     82 | doFilter  in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
|   1142 | runWorker in java.util.concurrent.ThreadPoolExecutor
|    617 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run       in java.lang.Thread
Caused by PowerAssertionError: assert filter
       |
       null
->>  352 | getCriteria in org.grails.plugin.easygrid.datasource.GormDatasourceService
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    184 | doCall    in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|    339 | doCall .  in org.grails.plugin.easygrid.datasource.GormDatasourceService$_createFiltersClosure_closure11
|     28 | doCall    in org.grails.plugin.easygrid.Filters$_postorder_closure4
|     27 | postorder in org.grails.plugin.easygrid.Filters
|    323 | createFiltersClosure in org.grails.plugin.easygrid.datasource.GormDatasourceService
|    184 | doCall .  in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|    251 | doCall    in org.grails.plugin.easygrid.datasource.GormDatasourceService$_createWhereQuery_closure9
|    242 | createWhereQuery in org.grails.plugin.easygrid.datasource.GormDatasourceService
|    196 | list      in     ''
|    184 | doCall .  in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|     31 | methodMissing in org.grails.plugin.easygrid.EasygridDispatchService
|    170 | doCall .  in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|     66 | gridData  in org.grails.plugin.easygrid.EasygridService
|    184 | doCall .  in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|     75 | doCall    in org.grails.plugin.easygrid.EasygridInitService$_registerControllerMethods_closure4
|    217 | guard . . in org.grails.plugin.easygrid.EasygridService
|    184 | doCall    in GrailsMelodyGrailsPlugin$_closure4_closure16_closure17
|    110 | doCall .  in org.grails.plugin.easygrid.EasygridInitService$_registerControllerMethods_closure9_closure17
|    189 | doFilter  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
|     63 | doFilter  in grails.plugin.cache.web.filter.AbstractFilter
|    150 | invoke    in net.bull.javamelody.JspWrapper
|    285 | invoke .  in net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler
|    198 | doFilter  in net.bull.javamelody.MonitoringFilter
|    176 | doFilter  in     ''
|     53 | doFilter  in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
|     49 | doFilter  in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
|     82 | doFilter  in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
|   1142 | runWorker in java.util.concurrent.ThreadPoolExecutor
|    617 | run       in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run . . . in java.lang.Thread

Any idea what could be the problem ? or what am I getting wrong ?

tudor-malene commented 9 years ago

Try this:

            'ingredient.name' {
                filterProperty 'ingredient.name'
                value {
                    "<span class='ingredientDetail showDetail' data-id='${it.ingredient.id}'>${it.ingredient.name}</span>";
                }

You have to add the filterProperty manually .This seems to be a bug - the filterProperty is not set to the column name when the value closure is used.

For the deliveryType

            deliveryType {
                formatter { it as String }
                filterConverter { val ->
                    DeliveryType.values().find { it.name().toLowerCase().contains(val.toLowerCase()) }
                }
            }

That is an enum I assume, so you have to somehow transform the value input in the search field to something gorm can use . For that you can use the filterConverter setting, which receives the value input by the user .

(update to version 1.6.9 of the plugin)

danyyacoub commented 9 years ago

Thanks this works, it even works with 'formatName' when i add filterProperty.

one thing for the deliveryType

filterConverter { val ->
                    DeliveryType.values().find { it.name().toLowerCase().contains(val.toLowerCase()) }
                }

returns all the records if no records match.

tudor-malene commented 9 years ago

Did you make this work properly, eventually?