Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    TileGrid layout

    I'd like to use the TileGrid as shown in the showcase isomorphic/system/reference/SmartClient_Explorer.html#tilingBasic

    but one thing I would like to change is for the image to be on the left of the description. Is there a simple way to do this without completely overriding getTile?

    #2
    A TileGrid accepts DetailViewerFields for configuring tile rendering, so you can use the formatting APIs from DetailViewerField to place an image to the left of a field value. If what you really want is more like a larger image with multiple fields of text to the right of it, this will require a getTile() override.

    Comment


      #3
      Ok - What I need is the exact setup as the showcase except with the images being shown to the left. It would be its own column value, not part of another one.

      Comment


        #4
        I'm a little stuck on getting this to work the way I want. First thing, for some reason when I do record.picture it gives me undefined. Second, I tried adding a label in my canvas and it shows as two "test" labels overlapping.

        So question is, how do I get the record values? Is there any way to just get the elements I want from the existing canvas? I just want to rearrange what was already there.


        Code:
        isc.TileGrid.create({
            ID:"boundList",
            tileWidth:150,
            tileHeight:205,
            width: "100%",
            height:"100%",
            dataSource:"animals",
            autoFetchData:true,
            animateTileChange:true,
            fields: [
                {name:"picture"},
                {name:"commonName", cellStyle: "commonName"},
                {name:"lifeSpan", formatCellValue: "return 'Lifespan: ' + value;"},
                {   name:"status", 
                    getCellStyle: function (value, field, record, viewer) {
                        if (value == "Endangered") return "endangered";
                        else if (value == "Threatened") return "threatened";
                        else if (value == "Not Endangered") return "notEndangered";
                        else return viewer.cellStyle;
                    }
                }
            ],
        
            getTile : function (record) {
                // override getTile() and add a "Remove" button 
                var canvas = isc.Canvas.create({});
                if(record.picture!=null){
                    var img = isc.Img.create({
                        top:120, width:100, height:100, border:"1px solid gray",
                        imageType: "stretch",
                        src: "/isomorphic/system/reference/inlineExamples/tiles/images/"+record.picture
                    }) ;
                   canvas.addChild(img);
        
                }
           var label  =isc.Label.create({contents: "test"})
        canvas.addChild(label);
             return canvas;
            }
        });

        Comment


          #5
          Found that this.data.get(record).picture gets me the info I want - is this the correct approach?

          If it is, I still have some problem with the label overlapping:

          Code:
           isc.TileGrid.create({
              ID:"boundList",
              tileWidth:250,
              tileHeight:205,
              width: "100%",
              height:"100%",
              dataSource:"animals",
              autoFetchData:true,
              animateTileChange:true,
              fields: [
                  {name:"picture"},
                  {name:"commonName", cellStyle: "commonName"},
                  {name:"lifeSpan", formatCellValue: "return 'Lifespan: ' + value;"}
              ],
          
              getTile : function (record) {
                  // override getTile() and add a "Remove" button 
                  var canvas = isc.HLayout.create({});
                  var actRecord = this.data.get(record);
                  var img = isc.Img.create({
                      top:120, width:100, height:100, border:"1px solid gray",
                      imageType: "stretch",
                      src: "/isomorphic/system/reference/inlineExamples/tiles/images/"+actRecord.picture
                  }) ;
                  canvas.addMember(img);
                  var form = isc.DynamicForm.create({fields:[{type:"staticText", showTitle:false,defaultValue : actRecord.commonName}]})
          
                  canvas.addMember(form);
                  return canvas;
              }
          });
          Uploaded what I am seeing
          Attached Files
          Last edited by acarur01; 12 Mar 2012, 12:31.

          Comment


            #6
            There are a couple of issues here:
            1) You're returning a subclass of Canvas -- we'd typically recommend subclassing SimpleTile to handle normal behaviors such as selection styling on click, etc.
            2) getTile() is called internally every time the system needs to display / modify / interact with the tile component for a record -- as such it can be called many times for the same record. Your override is creating a new tile each time this method is called which would lead to multiple tiles getting created for each record (and explains the screenshot with overlapping tiles, etc).
            If you are to override this method you will need to implement a caching mechanism such that when passed a record, you check the primary key value of the record and, if a tile has already been created, return it, rather than always creating new tiles.

            We'll make this clearer in the documentation.

            However you could also handle this by changing the tileConstructor, and allowing the standard framework logic to handle the lifecycle of individual tiles, which may be easier.
            Essentially this means:
            - You can define a subclass of SimpleTile which as part of initWidget() creates the child components you want. Use this.getRecord() to pick up the record associated with the tile as needed. Note that you can perform any other customizations you want on this class.
            - Set the 'tileContructor' on the TileGrid to point to this class.

            Let us know if you can't get this working

            Comment


              #7
              To make this a speedy process could you provide a sample on how to "define a subclass of SimpleTile which as part of initWidget() creates the child components you want"?

              Comment


                #8
                This is starting to get into consulting type stuff but here's an example you can use as a jumping off point. You can drop this into the TileGrid Filter & Sort example in the feature explorer.
                Code:
                isc.defineClass("CustomTile", "SimpleTile");
                isc.CustomTile.addProperties({
                    
                    // suppress standard display (retrieved via getInnerHTML)
                    // We'll use children instead
                    getInnerHTML : function () {
                        return null;
                    },
                    
                    // imageAlign - let's support left/top/right/bottom    
                    imageAlign:"left",
                    
                    // Use the autoChild subsystem to create children for simplicity
                    
                    baseLayoutDefaults:{
                        width:"100%", height:"100%",
                        defaultLayoutAlign:"center",
                        membersMargin:2
                    },
                    
                    imgConstructor:"Img",
                    imgDefaults:{
                        autoParent:"baseLayout",
                        width:100, height:100, border:"1px solid gray",
                        top:120, imgType:"stretch"
                    },
                    imgProperty:"picture",
                    imgBaseURL:"/isomorphic/system/reference/inlineExamples/tiles/images/",
                    
                    detailConstructor:"DetailViewer",
                    detailDefaults:{
                        autoParent:"baseLayout",
                        showTitles:false,
                        height:100
                    },
                    
                    initWidget : function () {
                        var imageAlign = this.imageAlign,
                            baseLayoutConstructor = (imageAlign == "left" || imageAlign == "right") 
                                                    ? isc.HLayout : isc.VLayout;
                        var reverseOrder = imageAlign == "right" || imageAlign == "bottom";
                        
                        this.addAutoChild("baseLayout", {_constructor:baseLayoutConstructor, reverseOrder:reverseOrder});
                
                        // Image
                        var record = this.getRecord(),
                            imgURL = record == null ? null : this.imgBaseURL + record[this.imgProperty];
                        this.addAutoChild("img", {src:imgURL});
                        
                        // Detail
                        var dvFields = this.creator.getFields().duplicate();
                        var pictureFieldIndex = dvFields.findIndex("name", this.imgProperty);
                        dvFields.removeAt(pictureFieldIndex);
                        
                        this.addAutoChild("detail", {
                            fields:dvFields,
                            data:record
                        });
                        
                    }
                })
                
                isc.VStack.create({
                    width:"100%",
                    membersMargin:20,
                    members:[
                
                        isc.TileGrid.create({
                            autoDraw:false,
                            tileConstructor:"CustomTile",
                            ID:"boundList",
                            // Note that these custom tiles aren't going to look right tall and thin!
                            tileWidth:300,
                            tileHeight:150,
                            
                            height:400,
                            showAllRecords:true,
                            dataSource:"animals",
                            autoFetchData:true,
                            animateTileChange:true,
                            fields: [
                                {name:"picture"},
                                {name:"commonName", cellStyle: "commonName"},
                                {name:"lifeSpan", formatCellValue: "return 'Lifespan: ' + value;"},
                                {   name:"status", 
                                    getCellStyle: function (value, field, record, viewer) {
                                        if (value == "Endangered") return "endangered";
                                        else if (value == "Threatened") return "threatened";
                                        else if (value == "Not Endangered") return "notEndangered";
                                        else return viewer.cellStyle;
                                    }
                                }
                                
                            ]            
                        }),
                
                        isc.DynamicForm.create({
                            autoDraw:false,
                            isGroup:true,
                            groupTitle:"Search",
                            ID:"boundForm",
                            numCols:"6",
                            dataSource:"animals",
                            autoFocus:false,
                            fields: [  
                                {name:"commonName"},
                                {name:"lifeSpan" , title: "Max Life Span", editorType: "slider",
                                    minValue:1, maxValue:60, defaultValue:60, height:50,
                                    operator: "lessThan"
                                },
                                {name:"status", operator: "equals", allowEmptyValue: true, emptyDisplayValue: "(Any)"}
                
                            ],
                            itemChanged: "boundList.fetchData(this.getValuesAsCriteria());"
                                      
                            
                        }),
                
                        isc.DynamicForm.create({
                            autoDraw:false,
                            ID:"sortForm",
                            isGroup:true,
                            groupTitle:"Sort",
                            numCols:"6",
                            autoFocus:false,
                            itemChanged: function(item, newValue, oldValue) {
                                var sortVal = this.getValue("sortBy");
                                var sortDir = this.getValue("chkSortDir");
                                if (sortVal) boundList.data.sortByProperty(sortVal, sortDir); 
                            },
                            fields: [  
                                {
                                    name:"sortBy", title:"Sort by", type:"select",
                                    valueMap: {
                                        "commonName" : "Animal",
                                        "lifeSpan" : "Life Span",
                                        "status" : "Endangered Status"  
                                    }
                                },
                                
                                {name:"chkSortDir", title:"Ascending", type:"checkbox"}
                            ]
                        }),
                
                        isc.HLayout.create({
                            autoDraw:false,
                            membersMargin:10,
                            height: 22,                               
                            members:[
                                isc.IButton.create(
                                    {
                                        title:"Filter", 
                                        click:"boundList.fetchData(boundForm.getValuesAsCriteria());", 
                                        autoFit:true
                                    }
                                ),
                                isc.IButton.create(
                                    {
                                        title:"Clear", 
                                        click:"boundList.fetchData();boundForm.clearValues();sortForm.clearValues();", 
                                        autoFit:true
                                    }
                                )
                            ]
                        })
                        
                       
                    ]
                });
                This example uses and Img and a DetailViewer to render out the data. You don't have to do it this way, it just seemed a neat way to demo the concept. For more flexibility, you could have the detail label simply be a Canvas rather than a DetailViewer, and have getInnerHTML() overridden on that canvas to write out whatever formatted content you want.

                Also note: We've taken this approach of adding children to the tiles to get custom appearance. Another option would be to generate the entire HTML for the tile yourself. This would not need any subclassing at all but would be a simple override to 'getTileHTML()' on the tileGrid instance.
                You could use the canvas.imgHTML helper to generate your image source.
                Here's a slightly cruder example which demonstrates this approach. You would of course want to expand it generate more attractive HTML / be able to be used with multiple dataSources rather than having hardcoded fields in place, etc - this is just to get the concept:

                Code:
                
                isc.VStack.create({
                    width:"100%",
                    membersMargin:20,
                    members:[
                
                        isc.TileGrid.create({
                            autoDraw:false,
                            
                            ID:"boundList",
                            // Note that these custom tiles aren't going to look right tall and thin!
                            tileWidth:300,
                            tileHeight:150,
                            
                            height:400,
                            showAllRecords:true,
                            dataSource:"animals",
                            autoFetchData:true,
                            animateTileChange:true,
                            fields: [
                                {name:"picture"},
                                {name:"commonName", cellStyle: "commonName"},
                                {name:"lifeSpan", formatCellValue: "return 'Lifespan: ' + value;"},
                                {   name:"status", 
                                    getCellStyle: function (value, field, record, viewer) {
                                        if (value == "Endangered") return "endangered";
                                        else if (value == "Threatened") return "threatened";
                                        else if (value == "Not Endangered") return "notEndangered";
                                        else return viewer.cellStyle;
                                    }
                                }
                                
                            ],
                            
                            getTileHTML : function (record) {
                                var src = record.picture,
                                    HTML = "<table><tr>";
                                if (src != null) {
                                    HTML += "<td>";
                                    HTML += isc.Canvas.imgHTML("/isomorphic/system/reference/inlineExamples/tiles/images/" + src);
                                    HTML + "</td>";
                                }
                                HTML += "<td>" + record.commonName + "<br>" + record.lifeSpan + "<br>" + record.status + "</td>"
                                HTML += "</tr></table>";
                                return HTML;
                            }
                        }),
                
                        isc.DynamicForm.create({
                            autoDraw:false,
                            isGroup:true,
                            groupTitle:"Search",
                            ID:"boundForm",
                            numCols:"6",
                            dataSource:"animals",
                            autoFocus:false,
                            fields: [  
                                {name:"commonName"},
                                {name:"lifeSpan" , title: "Max Life Span", editorType: "slider",
                                    minValue:1, maxValue:60, defaultValue:60, height:50,
                                    operator: "lessThan"
                                },
                                {name:"status", operator: "equals", allowEmptyValue: true, emptyDisplayValue: "(Any)"}
                
                            ],
                            itemChanged: "boundList.fetchData(this.getValuesAsCriteria());"
                                      
                            
                        }),
                
                        isc.DynamicForm.create({
                            autoDraw:false,
                            ID:"sortForm",
                            isGroup:true,
                            groupTitle:"Sort",
                            numCols:"6",
                            autoFocus:false,
                            itemChanged: function(item, newValue, oldValue) {
                                var sortVal = this.getValue("sortBy");
                                var sortDir = this.getValue("chkSortDir");
                                if (sortVal) boundList.data.sortByProperty(sortVal, sortDir); 
                            },
                            fields: [  
                                {
                                    name:"sortBy", title:"Sort by", type:"select",
                                    valueMap: {
                                        "commonName" : "Animal",
                                        "lifeSpan" : "Life Span",
                                        "status" : "Endangered Status"  
                                    }
                                },
                                
                                {name:"chkSortDir", title:"Ascending", type:"checkbox"}
                            ]
                        }),
                
                        isc.HLayout.create({
                            autoDraw:false,
                            membersMargin:10,
                            height: 22,                               
                            members:[
                                isc.IButton.create(
                                    {
                                        title:"Filter", 
                                        click:"boundList.fetchData(boundForm.getValuesAsCriteria());", 
                                        autoFit:true
                                    }
                                ),
                                isc.IButton.create(
                                    {
                                        title:"Clear", 
                                        click:"boundList.fetchData();boundForm.clearValues();sortForm.clearValues();", 
                                        autoFit:true
                                    }
                                )
                            ]
                        })
                        
                       
                    ]
                });

                Comment


                  #9
                  Thanks a lot! This really does help my implementation

                  Comment


                    #10
                    Is it possible to get the tile grid to behave the way a listgrid would when autoFitData is set to true? What I basically want to do is eliminate the scrollbar
                    Last edited by acarur01; 22 Oct 2012, 04:58. Reason: more info

                    Comment


                      #11
                      Not as a matter of just enabling a property, no. But you could hook various events to detect when rendering has completed (eg dataArrived) and setHeight() on the TileGrid to match the result of getScrollHeight() (plus padding and margins).

                      Comment


                        #12
                        You could probably set overflow to "visible" as you would with any other widget.

                        Comment


                          #13
                          Thanks - I think this is good enough

                          Comment


                            #14
                            I'm trying to get two images to overlay by setting tileProperties: style with a background image then I set tileValueStyle with a separate style that also contains an image. But I only see the tileValueStyle image. Is this possible? If so, what I am doing wrong?
                            Attached Files

                            Comment


                              #15
                              There are a couple of problems with your code as posted:

                              1) You're setting both style's to the same thing
                              2) tileProperties is an object attribute, not an array of objects

                              Changing both of those things should fix it for you.

                              Comment

                              Working...
                              X