Friday, July 17, 2009

Using a list or a map to construct JSON dynamiclly

How do you contruct a dynamic JSON, especially when you only need to return some fields of an object not a whole object? Using a builder or constructing a string directly? Neither is my favorite.
As time playing grails goes on, I find another way to build a JSON, only two steps:
1. To fill a list or a map with your data.
2. Using "as JSON".
Here is a sample:

def toc= TutorialRepository.toc
int i=1
int j=1
def tocJson=[]
toc.each{ ch ->
def chJson= [:]
chJson['title']= ch.title
chJson['sections']= []
ch.sections.each{ se ->
def seJson= [:]
seJson['title']= se.title
seJson['pos']= "${i}:${j}"
chJson['sections'] << seJson
j++
}
tocJson << chJson
i++
j= 1
}

render tocJson as JSON

It's simple, right? And there are several advantages in this way building a JSON:
1. It makes code clean.
2. You can build more expressive JSON.
3. It is more intuitive as the structure of the list(or the map) is the structure of the final JSON.

Sunday, July 12, 2009

Enhancing your layout with YUI Layout Manager

These days, I did a little grails project. And in this project, I combined sitemesh with yui layout manager. The way is not too difficult ;)
Here is code snippet from layout gsp, eg main.gsp:

<head>
...
<script type="text/javascript">
YAHOO.util.Event.onDOMReady(function () {
var layout1 = new YAHOO.widget.Layout({
minWidth: 1000,
units: [
{ position: 'top', height: 45, body: 'top1' },
{ position: 'left', width: 190, resize: true, body: 'left1', gutter: '2px', header: leftHeader,
collapse: true, scroll: true },
{ position: 'center' }
]
});
layout1.on("render", function(){
var el = layout1.getUnitByPosition('center').get('wrap');
var layout2= new YAHOO.widget.Layout(el, {
parent: layout1,
units: [
{ position: 'top', height: 45, body: 'top2', gutter: '2px' } ,
{ position: 'center', body: 'center2', gutter: '2px' },
{ position: 'bottom', height: bottomHeight, resize: true, body: 'bottom2',
scroll: true, gutter: '2px' }
]
});
layout2.on("resize", function(){
YAHOO.util.Dom.setStyle(center2ContentId, 'height', ((layout2.getSizes().center.h - 7) + 'px'));
});
layout2.render();
});
layout1.render();
init();
});
</script>
</head>
<body class="${pageProperty(name:'body.class')}">
<div id="top1">
<div id="logo"></div>
</div>
<div id="left1">
<g:pageProperty name="page.layout1.left.content"/>
</div>
<div id="top2">
<div id="toolbar"></div>
</div>
<div id="center2">
<g:pageProperty name="page.layout2.center.content"/>
</div>
<div id="bottom2">
<g:pageProperty name="page.layout2.bottom.content"/>
</div>
<g:pageProperty name="page.other"/>
</body>

init() and <g:pageProperty> is just placeholder, you can override it in your any gsp decorated by this layout. For example:

<head>
<script type="text/javascript">
// your own js code is here
...
// define your init function
var init= function(){...};
</script>
</head>
<!-- define your page content -->
<body class="yui-skin-sam">
<content tag="layout1.left.content"></content>
<content tag="layout2.center.content">
<div id="..."></div>
</content>
<content tag="layout2.bottom.content">
<div id="...">
<div class="..."></div>
</div>
</content>
<content tag="other">
<div id="how-to" style="text-align:left;">
......
</div>
</content>
</body>

It is noted that YUI Layout manager in this sample can also be replaced with othere ajax components lib(eg extjs or dojo) without too much hard work.