0

I have a grid provided by the struts2-jquery-grid-3.7.0 plugin as follows.

<s:url id="remoteurl" action="ProductGrid" namespace="/admin_side"/>
<s:url id="editurl" action="ProductCRUD"/>

<sjg:grid
    id="gridmultitable"
    caption="Product"
    dataType="json"
    href="%{remoteurl}"
    pager="true"
    navigator="true"
    navigatorSearchOptions="{sopt:['eq','ne','lt','gt']}"
    navigatorEdit="false"
    navigatorView="false"
    navigatorAddOptions="{height:280, width:500, reloadAfterSubmit:true}"
    navigatorEditOptions="{height:280, width:500, reloadAfterSubmit:false}"
    navigatorViewOptions="{height:280, width:500}"
    navigatorDelete="true"
    navigatorDeleteOptions="{height:280, width:500,reloadAfterSubmit:true}"
    gridModel="gridModel"
    rowList="5,10,15"
    rowNum="5"
    rownumbers="true"
    editurl="%{editurl}"
    editinline="true"
    multiselect="true"
    onSelectRowTopics="rowselect"
    onEditInlineSuccessTopics="oneditsuccess"
    viewrecords="true"
    shrinkToFit="false"
    width="1045"
    >

    <sjg:gridColumn name="prodId" index="prodId" title="Id" key="true" frozen="true" width="200" formatter="integer" editable="false" dataType="Long" sortable="true" search="true" sorttype="integer" searchoptions="{sopt:['eq','ne','lt','gt']}"/>
    <sjg:gridColumn name="prodName" index="prodName" title="Product Name" width="200" editable="true" sortable="true" search="true" sorttype="text"/>
    <sjg:gridColumn name="prodCode" index="prodCode" title="Product Code" width="200" sortable="true" search="true" editable="true" sorttype="text"/>

    <!--Start nested properties-->

    <sjg:gridColumn name="subCategory.category.catName" index="subCategory.category.catName" title="Category" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="subCategory.subCatName" index="subCategory.subCatName" title="SubCategory" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="brand.brandName" index="brand.brandName" title="Brand" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="fabric.fabricName" index="fabric.fabricName" title="Fabric" width="200" sortable="true" search="true" editable="true" sorttype="text"/>

    <!--End nested properties-->

    <sjg:gridColumn name="marketPrice" index="marketPrice" title="Market Price" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="salePrice" index="salePrice" title="Sale Price" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="featured" index="featured" title="Featured" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="expressDelivery" index="expressDelivery" title="Express Delivery" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="weight" index="weight" title="Weight" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="quantity" index="quantity" title="Quantity" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="visible" index="visible" title="Visible" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="latest" index="latest" title="Latest" width="200" sortable="true" search="true" editable="true" sorttype="text"/>
    <sjg:gridColumn name="prodDesc" index="prodDesc" title="Description" width="200" sortable="true" search="true" editable="true" sorttype="text"/>

</sjg:grid>

As can be seen, there are some nested properties in a few columns. They are not listed (displayed) in the given grid. The associated columns are simply left blank. The rest of the fields are displayed as usual.

I have also tried enclosing them within %{...} but to no avail.

How to display such nested properties in a grid? Is there any special treatment for them?

It was verified that these nested properties were fetched from the database and the model was initialized correctly.


Edit:

The action class:

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value="json-default")
@InterceptorRefs({@InterceptorRef(value="store", params={"operationMode", "AUTOMATIC"})})
public final class ProductAction extends ActionSupport implements Serializable, ModelDriven<Product>
{
    @Autowired
    private final transient ProductService productService=null;
    private static final long serialVersionUID = 1L;

    private Product entity=new Product();
    private List<Product>gridModel=new ArrayList<Product>();

    private String id;
    // Get how many rows we want to have into the grid - rowNum attribute in the grid
    private Integer rows=5;
    // Get the requested page. By default grid sets this to 1.
    private Long page=1L;
    // sorting order - asc or desc
    private String sord;
    // get index row - i.e. user click to sord.
    private String sidx;
    // Search Field
    private String searchField;
    // The Search String
    private String searchString;
    // The Search Operation ['eq','ne','lt','le','gt','ge','bw','bn','in','ni','ew','en','cn','nc']
    private String searchOper;
    // Your Total Pages
    private Long total;
    // All Records
    private Long records;
    private String oper;

    @Override
    public Product getModel() {
        return entity;
    }

    @Action(value = "ProductCRUD",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Product.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Product.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "defaultStack", params = {"validation.validateAnnotatedMethodOnly", "true", "validation.excludeMethods", "load"})})
    public String edit() throws Exception {

        if(oper.equalsIgnoreCase("add")) {
            // Add a row.
        }
        else if(oper.equalsIgnoreCase("edit")) {
            // Update a row.
        }
        else if(oper.equalsIgnoreCase("del")) {
            // Delete a row.
        }
        return ActionSupport.SUCCESS;
    }

    @Action(value = "ProductGrid",
    results = {
        @Result(name = ActionSupport.SUCCESS, type = "json", params = {"includeProperties", "gridModel\\[\\d+\\]\\.prodId, gridModel\\[\\d+\\]\\.prodName, gridModel\\[\\d+\\]\\.prodCode, gridModel\\[\\d+\\]\\.prodDesc, gridModel\\[\\d+\\]\\.marketPrice, gridModel\\[\\d+\\]\\.salePrice, gridModel\\[\\d+\\]\\.featured, gridModel\\[\\d+\\]\\.expressDelivery, gridModel\\[\\d+\\]\\.weight, gridModel\\[\\d+\\]\\.occassion, gridModel\\[\\d+\\]\\.quantity, gridModel\\[\\d+\\]\\.visible, gridModel\\[\\d+\\]\\.latest, gridModel\\[\\d+\\]\\.subCategory, gridModel\\[\\d+\\]\\.fabric, gridModel\\[\\d+\\]\\.brand, gridModel\\[\\d+\\]\\.subCategory\\[\\d+\\]\\.category, total, records, rows, page, sord, sidx, searchField, searchString, searchOper", "excludeNullProperties", "true"})},
    interceptorRefs = {
        @InterceptorRef("params")})
    public String executeAction() {
        records=productService.rowCount().longValue();
        total=new BigDecimal(records).divide(new BigDecimal(rows), 0, BigDecimal.ROUND_CEILING).longValue();

        gridModel=productService.getList((int)(page-1)*rows, rows, new HashMap<String, String>(){{put(sidx, sord);}}, null);
        return SUCCESS;
    }

    public String getJSON() {
        return executeAction();
    }

    public List<Product> getGridModel() {
        return gridModel;
    }

    public void setGridModel(List<Product> gridModel) {
        this.gridModel = gridModel;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Integer getRows() {
        return rows;
    }

    public void setRows(Integer rows) {
        this.rows = rows;
    }

    public Long getPage() {
        return page;
    }

    public void setPage(Long page) {
        this.page = page;
    }

    public String getSord() {
        return sord;
    }

    public void setSord(String sord) {
        this.sord = sord;
    }

    public String getSidx() {
        return sidx;
    }

    public void setSidx(String sidx) {
        this.sidx = sidx;
    }

    public String getSearchField() {
        return searchField;
    }

    public void setSearchField(String searchField) {
        this.searchField = searchField;
    }

    public String getSearchString() {
        return searchString;
    }

    public void setSearchString(String searchString) {
        this.searchString = searchString;
    }

    public String getSearchOper() {
        return searchOper;
    }

    public void setSearchOper(String searchOper) {
        this.searchOper = searchOper;
    }

    public Long getTotal() {
        return total;
    }

    public void setTotal(Long total) {
        this.total = total;
    }

    public Long getRecords() {
        return records;
    }

    public void setRecords(Long records) {
        this.records = records;
    }

    public String getOper() {
        return oper;
    }

    public void setOper(String oper) {
        this.oper = oper;
    }

    @Action(value = "Product",
        results = {
            @Result(name=ActionSupport.SUCCESS, location="Product.jsp"),
            @Result(name = ActionSupport.INPUT, location = "Product.jsp")},
        interceptorRefs={
            @InterceptorRef(value = "defaultStack", params = {"validation.validateAnnotatedMethodOnly", "true", "validation.excludeMethods", "load"})})
    public String load() throws Exception {
        // This method is only needed to return an initial view on page load. Nothing to see here. Leave it empty.
        return ActionSupport.SUCCESS;
    }
}

In response, those all nested properties are empty. The JSON response for a single row is as follows.

{
  "gridModel": [
    {
      "brand": {

      },
      "expressDelivery": false,
      "fabric": {

      },
      "featured": true,
      "latest": false,
      "marketPrice": 12.00,
      "occassion": "222",
      "prodCode": "aaa",
      "prodDesc": "xxx",
      "prodId": 5,
      "prodName": "ddd",
      "quantity": 1,
      "salePrice": 12.00,
      "subCategory": {

      },
      "visible": true,
      "weight": 22.00
    }    
  ],
  "page": 1,
  "records": 5,
  "rows": 5,
  "sidx": "",
  "sord": "asc",
  "total": 1
}
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
Tiny
  • 27,221
  • 105
  • 339
  • 599
  • What do you mean of Nested properties ? how does this `subCategory.category.catName` exists in your model I mean in which form i.e bean object are you want them from Value Stack ? – Rookie007 Feb 24 '14 at 02:38
  • There is a list of products in the associated action class, `List gridModel` which is populated from the database, when a request to the action `ProductGrid` is made as shown in the grid. Each `Product` in the list contains a `subCategory` object which in turn, contains a `category` object. Dereferencing all of them with a `dot`, `catName` possessed by `category` should be accessed. – Tiny Feb 24 '14 at 02:46
  • Okay .. did you try giving that direct name of the sub category object instead of giving `dot` and sub category ? – Rookie007 Feb 24 '14 at 03:01
  • How? That cannot be given. If only `subCategory` was given, for example, it would display, `[object Object]`. – Tiny Feb 24 '14 at 03:04
  • If that is the case I would suggest you to go for Custom format options create a Javascript method to populate properties of what you want. Because that list contains not any more JAVA object That list will be in JSON format So i think it would be possible to get those values something like this `rowObject["subCatName"]`.you try in this way May be you will get IDea. In `formart="suboptions"` like that – Rookie007 Feb 24 '14 at 03:16
  • can you trace the `json` object that is received in response when grid is loaded? please check if that `json` object contains proper `hierarchical` structure of subCategory! – Yogesh Feb 24 '14 at 08:32
  • @Barewithme : JSON in this case is associated with the grid. Is is handled by the plugin. How can I trace it? I don't know. – Tiny Feb 24 '14 at 08:38
  • If you are using google chrome, press `F12` go to `Network` tab and click black dot for `Record Network Log` you can then load your page and check all request generated! one of them will be for jquery grid! containing json response! like objects like `gridModel`, `row`, `page`, `count` etc. – Yogesh Feb 24 '14 at 08:42
  • copy that json response and backtrack it on sites like http://jsonviewer.stack.hu – Yogesh Feb 24 '14 at 08:44
  • 1
    @Barewithme : The developer tool shows all of those properties empty like `subCategory": {}`. Hence the expression like `subCategory.category.catName` is not evaluated. – Tiny Feb 24 '14 at 08:51
  • please update your question with struts configuration for action `ProductGrid` and plugin details for json, also make sure that these properties are being loaded from database for action `ProductGrid` – Yogesh Feb 24 '14 at 08:53
  • @Tiny : are you sure the culprit is not: `{"includeProperties", "gridModel\\[\\d+\\]\\.prodId, [...] gridModel\\[\\d+\\]\\.subCategory, gridModel\\[\\d+\\]\\.fabric, gridModel\\[\\d+\\]\\.brand, gridModel\\[\\d+\\]\\.subCategory\\[\\d+\\]\\.category, total, records, rows, page, sord, sidx, searchField, searchString, searchOper", "excludeNullProperties", "true"})},` ? Try 1: to remove this stuff and/or 2: to include subproperties as well – Andrea Ligios Feb 24 '14 at 09:39
  • @AndreaLigios : This indeed causes the problem. If I remove `includeProperties` in its entirely, then these nested properties are displayed in the grid but doing so executes hundreds of queries on all the associated tables quite unnecessarily. I have tried to change, for example, `gridModel\\[\\d+\\]\\.subCategory\\[\\d+\\]\\.category` to `gridModel\\[\\d+\\]\\.subCategory\\[\\d+\\]\\.category[\\d+\\]\\.catName` but that didn't make a difference either. – Tiny Feb 24 '14 at 09:46
  • 1
    Escape the dot: `gridModel\\[\\d+\\]\\.subCategory\\.category\\.catName` (or `gridModel\\[\\d+\\]\\.subCategory\\[\\d+\\]\\.category\\.catName` if you have several subcategories for each row) – Andrea Ligios Feb 24 '14 at 09:57
  • @AndreaLigios : This `gridModel\\[\\d+\\]\\.subCategory\\.category\\.catName` worked finally. You may please post an answer. Thank you very much :) – Tiny Feb 24 '14 at 10:12

1 Answers1

2

In the includePproperties param, you need to

  • specify the full path to the inner properties
  • escape the dots
  • remove the second \[\d\] notation when applied to objects that are not collections

An example:

wrong : gridModel\\[\\d+\\]\\.subCategory\\[\\d+\\]\\.category

right : gridModel\\[\\d+\\]\\.subCategory\\.category\\.catName

Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243