Friday, 12 February 2016

The GRAILS WELT (WORLD) - GRAILS AUTOBINDING

In this post we will be going on with the GRAILS AUTOBINDING feature during form submission.

Now, GRAILS documentation provides a comprehensive guide to Autobinding request to Domain or Command Objects.
So this post is not about all those features.

My objective is to bind list of objects from Front end (.gsp) to the underlying Domain or Command Object in Controller and then access them there.
I first started modelling following the Spring approach using the index (subscript) pattern (i.e. CommandObj[i]), but somehow it was failing to bind the values from the Request map to Domain or Command Object in Controller.

Below code excerpts provides the approach that I followed for the above mentioned problem.
I am dividing the post in to parts:

1. Part -1: Autobinding request to Command Object
2. Part -2: Autobinding request to Domain Object
Part -1

The View:





 <g:form  controller="book" action="submitBook" method="POST" name="BookRegistrationForm" >
    Title0:<gg:textField name="items[0].title"></g:textField> <br/>
    Author0:<gg:textField name="items[0].author"></g:textField> <br/>

    Title1:<gg:textField name="items[1].title"></g:textField> <br/>
    Author1:<gg:textField name="items[1].author"></g:textField> <br/>

    Title2:<gg:textField name="items[2].title"></g:textField> <br/>
    Author2:<gg:textField name="items[2].author"></g:textField> <br/>

    <gg:submitButton name="register" type="submit" value="Submit/Register"></g:submitButton>


<g/g:form>




The Corresponding Command Object is:



class BookCommand implements Validateable{

    List items = [].withLazyDefault {new Book() as Factory}

    static constraints = {}
}

Now, we have made the Command Object to implement Validateable just like Domain objects to so that we can put constraints/validation on the properties of the Command Object from within static constraint closure.

Within Commad Object we have instantiated a List of type Book lazily initialized and the elements of this list we are using in the View using the index subscript.

and the Controller where we are accessing the Command Object is:


class BookController {
   def index() {
  render( view:"registerBook")
 }
 
 def submitBook(BookCommand bookCommand)
 {
  bookCommand.items.each {Book book ->

   25.times {
    print "*"
   }

   println "Author:$book.author \n Title:$book.title"

   25.times {
    print "*"
   }

   println ""

  }
 }
 
 }

Part -2

The View:



<g:form  controller="hospital" action="createHospital" method="POST" name="HospitalRegistrationForm" >

    Name:  <g:textField name="name"></g:textField> <br/>
    Doctor Name:  <g:textField name="doctors[0].name"></g:textField> <br/>
    Doctor Reg No:  <g:textField name="doctors[0].regNo"></g:textField> <br/>
    Doctor Specialization:  <g:textField name="doctors[0].spec"></g:textField> <br/><br/><br/>

    Doctor Name:  <g:textField name="doctors[1].name"></g:textField> <br/>
    Doctor Reg No:  <g:textField name="doctors[1].regNo"></g:textField> <br/>
    Doctor Specialization:  <g:textField name="doctors[1].spec"></g:textField> <br/>

    <br/><br/>
    <g:submitButton name="register" type="submit" value="Submit/Register"></g:submitButton>



</g:form>



The Corresponding Domain Object is:


class Hospital {

    String name
    //Doctor doctor
    static hasMany = [doctors: Doctor]

    //List doctors

    static constraints = {
    }
}

Here, we can see that how we have bound the property name and doctors with the Form. Another important thing to notice out here is the doctors property which we has no explicit declaration on the Domain object but is being configured as List of type Doctor within the Domain Object by Grails (All the credits goes to GORM) and hence we can access this property just like other List Properties.

The Corresponding Controller is:

class HospitalController extends RestfulController {

    static responseFormats = ['xml','json']
 
 Environment environment

    @Value('${dataSource.driverClassName}')
    def driverClassName

    HospitalController(Class resource) {
        super(resource)
    }

    HospitalController()
    {
        this(Hospital.class)
    }

    def index() {

        println "The Environment is: $environment \n\n ${environment.getProperty('application.profile')} \n" +
                " ${environment.getProperty('hibernate.cache.use_second_level_cache')} \n" +
                "${environment.getProperty('dataSource.driverClassName')} \n\n Done Done-- $driverClassName"

        render(view:"registerHospital")

    }

    def createHospital(Hospital hospital)
    {
        def hospital2
        try {
            println "No of Doctors: ${hospital.doctors.size()}"
            hospital.save()

            hospital2 = new Hospital(name:'okkkiea')
            hospital2.addToDoctors(new Doctor(name:'bnm',regNo:'yhj',spec:'zzz'))
                    .addToDoctors(new Doctor(name:'fff',regNo:'ggg',spec:'mmm'))
                    .addToDoctors(new Doctor(name:'fff7',regNo:'ggg7',spec:'mmm7'))

            hospital2.save()

            println "No of Doctors2: ${hospital2.doctors.size()}"
        }
        catch(e)
        {
            e.printStackTrace()
        }
        println "The saved Hospital is:$hospital \n\n $hospital2"
    }
 
 }

So this is in short about Autobinding Collection Form Data with the Command and Domain Object.

Along with Auto Binding, if you take close look at the bove controller, there has also been demonstrated ways to access properties from the configuartion files using both @Value injection and also using Spring Environment.

Please feel free to add your comments and and feedback.
View Subhankar Paul's profile on LinkedIn

No comments:

Post a Comment