Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7968573
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 4, 20262026-06-04T07:05:54+00:00 2026-06-04T07:05:54+00:00

I have altered the src/templates/scaffolding/renderEditor.template file in a grails project, in order to insert,

  • 0

I have altered the src/templates/scaffolding/renderEditor.template file in a grails project, in order to insert, the necessary html field boxes (and javascript code) to configure and use jquery autocomplete, in all the relationships “many-to-one”. (The code is shown below)

The autogenerated autocomplete (_form.gsp) works correctly … but I need to show the correct values (code and description) into the autocomplete textbox when a user edit a record using the scaffolding.

To do that, I need to identify two fields inside the domain: one for code and the other for the description.

To face this problem, I have tried to create two dummies constraints, using the plugin “constraints”, the first one used like code, the second one used like a description. I don’t like this solution, because the contrainsts could be used several times into the domain.

The code altered into the src/templates/scaffolding/renderEditor.template file is the following: (Note the two input boxes and Javascript code used for autocomplete):

private renderManyToOne(domainClass, property) {
    if (property.association) {


        /*  ORIGINAL CODE inside comments
            def sb = new StringBuilder()
        sb << '<g:select'
            // id is "x" and name is "x.id" as the label will have for="x" and "." in an id will confuse CSS
            sb << ' id="' << property.name << '"'
            sb << ' name="' << property.name << '.id"'
            sb << ' from="${' << property.type.name << '.list()}"'
            sb << ' optionKey="id"'
            if (isRequired()) sb << ' required=""'
            sb << ' value="${' << "${domainInstance}?.${property.name}" << '?.id}"'
            sb << ' class="many-to-one"'
            sb << renderNoSelection(property)
            sb << '/>'
            sb as String

            */


        def sb = new StringBuilder()

        // hidden field for domain.id

        sb << '<input type=\"hidden\" '
        sb << ' id="' << property.name << '.id"'
        sb << ' name="' << property.name  << '.id"'
        sb << ' value="${' << "${domainInstance}" << '?.id}" '
        sb << '/>\n'

        // Text field to show the description generated by autocomplete
        sb << '\t<input type=\"text\" '
        sb << ' id="' << property.name << '"'
        sb << ' name="' << property.name  << '"'
        if (isRequired()) sb << ' required="" '
        sb << 'style=\"width: 600px;\" '
        sb << ' value="${' << "${domainInstance}?.${property.name}" << '?.id}"'
        // sb << '${' << "${property.name}" << '"'
        sb << '/>'

        def js = new StringBuilder()
        js << '''
        <script type="text/javascript">

            /*
             * Remember include jquery and jquery-ui libraries into head section of edit.gsp file
             *   < g:javascript library="jquery"/>
             *   < g:javascript library="jquery-ui"/>
             */

            \$(document).ready(function() {
        '''
           js << '\t\$("#' << property.name << '").focus(function(){this.select(); });\n'

           js << '\t\t$("#' << property.name << '").autocomplete({\n'

           js << '''
                      source: function(request, response){
                          \$.ajax({
                              // Define Remote datasource into the controller
           '''
           js << '            \t\t url: "'
           js << '/' << grails.util.Metadata.current.'app.name' << '/' << property.name << '/' << 'autoCompleteList",'

           js << '''
                              data: request,
                              success: function(data){
                                  // Get the response (JSON format)
                                  response(data);
                              },
                              error: function(){
                                  // Handle server errors
                                  response("Error after search records. Try Again.")
                              }
                          });
                      },
                      // General options: Triggered only after minimum 2 characters have been entered and others
                      minLength: 2,
                      delay: 1,
                      autoFocus: true,
                      // Event handler when user selects a Loinc from the list.
                      select: function(event, ui) {
                          // update the hidden field.
           '''
           js <<  '\t\t\t\t  \$("#' << property.name << '\\.id").val(ui.item.id);'
           js << '''
                      }
                });
           });
        </script>
        '''
        sb << js
        sb as String


    }

The domain using the dummy contraints (autoid and autodesc):

class LOINC {

    static searchable = {
        only = ["code", "shortName", "longName", "property", "system", "scale", "method", "time"]
    }

    String code         // LOINC_NUM         * 0
    String shortName    // SHORTNAME         * 29
    String longName     // LONG_COMMON_NAME  * 35
    String name         // BASE_NAME         * 21
    String component    // COMPONENT         * 1
    String property     // PROPERTY          * 2
    String time         // TIME_ASPCT        * 3
    String system       // SYSTEM            * 4
    String scale        // SCALE_TYP         * 5
    String method       // METHOD_TYP        * 6

    static constraints = {
        code(nullable: false, unique: true, blank: false, maxSize: 100, autoid: true)
        shortName(nullable: false)
        longName(nullable: false, autodesc: true)
        name(nullable: false, maxSize: 100)
        component(nullable: false)
        property(nullable: false)
        time(nullable: false)
        system(nullable: false)
        scale(nullable: false)
        method(nullable: false)
    }

    String toString(){
        "${code} ${longName}"
    }
}

The code inside the controler:

 def autoCompleteList = {
        def loincAutoCompleteService = new LOINCAutoCompleteService()
        render loincAutoCompleteService.loincList(params) as JSON
 }

The service:

class LOINCAutoCompleteService {

    def loincList(params) {

        // Creates a new query Object
        def query = {
            or {
                like("code", "${params.term}%") // term is the parameter send by jQuery autocomplete
                like("longName", "${params.term}%")
                like("shortName", "${params.term}%")
            }
            projections { // good to select only the required columns.
                property("id")
                property("code")
                property("longName")
            }
        }

        def loincSelectList = [] // aArray List to add each Loinc details
        def clist = LOINC.createCriteria().list(query)


        clist.each {
            // Add to map. jQuery autocomplete expects the JSON object to be with id/label/value
            def loincMap = [:]

            loincMap.put("id", it[0])

            // Label is text showed int he drop-down list
            loincMap.put("label", it[1] + " : " + it[2])

            // Values is the code to be returned when the user select an item from drop-down list
            loincMap.put("value", it[1] + " : " + it[2])

            // Add the row to the array list
            loincSelectList.add(loincMap)
        }


        return loincSelectList

    }
}

I want something like that inside the domain class:

<code>
static autocompleteAble = {
        fields = ["code", "longName"]
}
</code>

Then access this array from the src/templates/scaffolding/renderEditor.template in order to get the field names (code and longName) and generate the correct html code in _forms.gsp and fix the problem.

Other solution? Any Ideas?

Many Thanks in Advance. … and excuse my bad English.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-04T07:05:55+00:00Added an answer on June 4, 2026 at 7:05 am

    Reading and testing and testing again … I have found the answer, follow the steps:

    1. Add the following code to the Domain class:

      class DomainClass {
      String codeField;
      String descriptionField;
      static autoCompleteConfig = [“codeField”, “descriptionField”]
      }

    2. Change the src/templates/scaffolding/renderEditor.template (only the renderManyToOne method):

      private renderManyToOne(domainClass, property) {

          def AUTOCOMPLETE_PROPERTY = "autoCompleteConfig"
          def className = property.type.name
      
          def autoCompleteProperty = org.codehaus.groovy.grails.commons.GrailsClassUtils.getStaticPropertyValue(property.referencedDomainClass.clazz, AUTOCOMPLETE_PROPERTY)
          def sb = new StringBuilder()
          // sb << "\n<!-- getFullName(): " <<   domainClass.getFullName() << " property.type.name: " << property.type.name << " property.referencedDomainClass.propertyName: " << property.referencedDomainClass.propertyName <<  "     property.referencedDomainClass: " << property.referencedDomainClass <<  " -->\n"
          if (autoCompleteProperty != null) {
      
              if (autoCompleteProperty[0] ) {
                  if (property.association) {
      
                      // hidden field for domain.id
      
                      sb << '<input type=\"hidden\" '
                      sb << ' id=  "' << property.name << '.id"'
                      sb << ' name="' << property.name << '.id"'
                      sb << ' value="${' << "${domainInstance}" << '?.id}" '
                      sb << '/>\n'
      
                      // Text field to show the description generated by autocomplete
                      sb << '\t<input type=\"text\" '
                      sb << ' id=  "' << property.name  << '_' << (autoCompleteProperty[1]? autoCompleteProperty[1]:'Description')  << '\" '
                      sb << ' name="' << property.name  << '_' << (autoCompleteProperty[1]? autoCompleteProperty[1]:'Description')  << '\" '
                      if (isRequired()) sb << ' required="" '
                      sb << 'style=\"width: 600px;\" '
      
                      sb << ' value="${'
                      sb << "${domainInstance}?.${property.name}" << '?.' << autoCompleteProperty[0] << '}' << (autoCompleteProperty[1]? '' : '"' )
      
                      if (autoCompleteProperty[1]) {
                          sb << ': ${' << "${domainInstance}?.${property.name}" << '?.' << autoCompleteProperty[1] << (autoCompleteProperty[2]? '}' : '}"' )
                      }
      
                      if (autoCompleteProperty[2]) {
                          sb << ': ${' << "${domainInstance}?.${property.name}" << '?.' << autoCompleteProperty[2] << '}"'
                      }
      
      
                      sb << ' />'
      
                      def js = new StringBuilder()
                      js << '''
                      <script type="text/javascript">
      
                          /*
                           * Remember include jquery and jquery-ui libraries into head section of edit.gsp file
                           *   < g:javascript library="jquery"/>
                           *   < g:javascript library="jquery-ui"/>
                           *
                           */
      
                          \$(document).ready(function() {
                      '''
                         js << '\t\$("#' << property.name << '").focus(function(){this.select(); });\n'
      
                         js << '\t\t\t\t\t\t' // Tabs to sort the output
                         js << '\$("#' << property.name  << '_' << (autoCompleteProperty[1]? autoCompleteProperty[1]:'Description')  << '").autocomplete({\n'
      
                         js << '''
                                    source: function(request, response){
                                        \$.ajax({
                                            // Define Remote datasource into the controller
                         '''
                         js << '            \t\t url: "'
                         js << '/' << grails.util.Metadata.current.'app.name' << '/' << property.name << '/' << 'autoCompleteList",'
      
                         js << '''
                                            data: request,
                                            success: function(data){
                                                // Get the response (JSON format)
                                                response(data);
                                            },
                                            error: function(){
                                                // Handle server errors
                                                response("Error after search records. Try Again.")
                                            }
                                        });
                                    },
                                    // General options: Triggered only after minimum 2 characters have been entered and others
                                    minLength: 2,
                                    delay: 1,
                                    autoFocus: true,
                                    // Event handler when user choose un item from the list.
                                    select: function(event, ui) {
                                        // update the hidden field.
                         '''
                         js <<  '\t\t\t\t  '
                         js << '\$("#' << property.name << '\\\\.id").val(ui.item.id);'
      
                         js << '''
      
                                    }
                              });
                         });
                      </script>
                      '''
                      sb << js
                      sb as String
      
      
                  }
              }
          } else {
      
      
              sb << '<g:select'
              // id is "x" and name is "x.id" as the label will have for="x" and "." in an id will confuse CSS
              sb << ' id="' << property.name << '"'
              sb << ' name="' << property.name << '.id"'
              sb << ' from="${' << property.type.name << '.list()}"'
              sb << ' optionKey="id"'
              if (isRequired()) sb << ' required=""'
              sb << ' value="${' << "${domainInstance}?.${property.name}" << '?.id}"'
              sb << ' class="many-to-one"'
              sb << renderNoSelection(property)
              sb << '/>'
              sb as String
      
      
          }
      
      }
      
    3. Add the jquery libraries to src/templates/scaffolding/edit.gsp. Remember to install the jquery plugin:

    4. Write your own autoCompleteRoutine inside the Domain controller, something like:

      def autoCompleteList = {
      def domainAutoCompleteService = new DomainAutoCompleteService()
      render domainAutoCompleteService.domainList(params) as JSON
      }

    5. Write your own domainAutoCompleteService, something like:

      package packageName

      // Change the words "Domain" and "domain" with your own Domain class name
      class DomainAutoCompleteService {
      
          def domainList(params) {
      
              // Creates a new query Object
              def query = {
                  or {
                      // term is the parameter send by jQuery autocomplete
                      like("codeField", "${params.term}%") 
                      like("descriptionField", "${params.term}%")
                      like("otherField", "${params.term}%")
                  }
                  projections { // good to select only the required columns.
                      property("id")
                      property("codeField")
                      property("descriptionField")
                  }
              }
      
              def domainSelectList = [] 
              // Replace the word "Domain" by your own domain Name
              def clist = Domain.createCriteria().list(query)
      
      
              clist.each {
                  // Add to map. jQuery autocomplete expects the JSON object to be with id/label/value
                  def map = [:]
      
                  map.put("id", it[0])
      
                  // Label is text showed int he drop-down list
                  map.put("label", it[1] + " : " + it[2])
      
                  // Values is the code to be returned when the user select an item from drop-down list
                  map.put("value", it[1] + " : " + it[2])
      
                  // Add the row to the array list
                  domainSelectList.add(map)
              }
      
      
              return domainSelectList
      
          }
      }
      
    6. Generate the views …. and voila! All is working.

    Any Comments? I think can be more elegant but is the first step …

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have an altered Java Launcher exe file written in NSIS that launches a
I have slightly altered the architecture of our application, and IWindsorContainer is no longer
I have a PHP search script which I've altered slightly and works well for
have a problem. At first look at this HTML <div id=map style=background-image: url(map.png); width:
Names of entities have been altered to protect their identities... I've created a class
I have a several XIB files in my iOS project for various custom table
There are tons of questions about this topic, but I have a slightly altered
EDIT : I have altered the NSPredicate as recommended so that my fetch code
I have just been altered to the fact that a user of my website
I'd like to have variable defined in the nesting function to be altered in

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.