user3348410
user3348410

Reputation: 2833

How to create dynamic button in grails

i'm trying to create some app with this logic;

I have the entries with cars, i want to add (rent) button to each entry at list of my cars, when will click to button someone, button will open some form for entry contact informations and this form should get car id number automatically

here is my domain class with cars. I don't understand how to add the button to my index.gsp where listed my entries about cars and how get the id number of selected car from list and send to the form

How to do this? how is working this logic?

package rentme

class Car {

    String brand
    String model
    String fuelType
    BigDecimal pricePerDay
    String busy

    static constraints = {
        brand(inList:["AUDI", "BMW", "MERCEDES", "NISSAN", "HONDA", "FORD"])
        fuelType(inList:["FUEL", "DIESEL", "AUTOGAS"])
        pricePerDay(min:0.0, max:1000.0)
        busy(inList:["YES", "NO"])
    }
}

Here is what i tried;

Here is my Car/index.gsp in view files. - here i get car id's and tried to put button to each id. I want to do this; button will go to another page where will be registration page for rent this car, and in this registration page user will see the id number of the car which one selected.

  <g:each in="${carList}" var="car">
                    <p>${car.id} </p>
                    <g:link action="registration" controller="registration" params="[carId : ${car.id} ]">
                        Rent Car
                    </g:link>

                </g:each>

And here is domain-class of my Registration Class

package rentme

class Registration {

    String yourName

    static constraints = {
        yourName()
    }
}

And here is my Registration Controller , i created it with generate-all command

package rentme

import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional

@Transactional(readOnly = true)
class RegistrationController {

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]

    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond Registration.list(params), model:[registrationCount: Registration.count()]
    }

    def show(Registration registration) {
        respond registration
        println params
        Car b = Car.get(params.id)
    }

    def create() {
        respond new Registration(params)
    }

    @Transactional
    def save(Registration registration) {
        if (registration == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        if (registration.hasErrors()) {
            transactionStatus.setRollbackOnly()
            respond registration.errors, view:'create'
            return
        }

        registration.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.created.message', args: [message(code: 'registration.label', default: 'Registration'), registration.id])
                redirect registration
            }
            '*' { respond registration, [status: CREATED] }
        }
    }

    def edit(Registration registration) {
        respond registration
    }

    @Transactional
    def update(Registration registration) {
        if (registration == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        if (registration.hasErrors()) {
            transactionStatus.setRollbackOnly()
            respond registration.errors, view:'edit'
            return
        }

        registration.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [message(code: 'registration.label', default: 'Registration'), registration.id])
                redirect registration
            }
            '*'{ respond registration, [status: OK] }
        }
    }

    @Transactional
    def delete(Registration registration) {

        if (registration == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        registration.delete flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.deleted.message', args: [message(code: 'registration.label', default: 'Registration'), registration.id])
                redirect action:"index", method:"GET"
            }
            '*'{ render status: NO_CONTENT }
        }
    }

    protected void notFound() {
        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.not.found.message', args: [message(code: 'registration.label', default: 'Registration'), params.id])
                redirect action: "index", method: "GET"
            }
            '*'{ render status: NOT_FOUND }
        }
    }
}

I added to there in def show() method this lines of code for get car.id

 def show(Registration registration) {
        respond registration
        println params
        Car b = Car.get(params.id)
    }

and here is my registration page in views registration/index.gsp

<!DOCTYPE html>
<html>
    <head>
        <meta name="layout" content="main" />
        <g:set var="entityName" value="${message(code: 'registration.label', default: 'Registration')}" />
        <title><g:message code="default.list.label" args="[entityName]" /></title>
    </head>
    <body>
        <a href="#list-registration" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content&hellip;"/></a>
        <div class="nav" role="navigation">
            <ul>
                <li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
                <li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
            </ul>
        </div>
        <div id="list-registration" class="content scaffold-list" role="main">
            <h1><g:message code="default.list.label" args="[entityName]" /></h1>
            <g:if test="${flash.message}">
                <div class="message" role="status">${flash.message}</div>
            </g:if>
            <f:table collection="${registrationList}" />

            <div class="pagination">
                <g:paginate total="${registrationCount ?: 0}" />
            </div>


            <div><p>${car.id} </p></div>
        </div>
    </body>
</html>

i added to this code here for get car.id

 <div><p>${car.id} </p></div>


Error 500: Internal Server Error
URI
/car/index
Class
org.grails.taglib.GrailsTagException
Message
Request processing failed; nested exception is java.lang.RuntimeException: Error initializing GroovyPageView
Caused by
[views/car/index.gsp:32] Attribute value quote wasn't closed (action="registration" controller="registration" params="[carId : ${car.id} ]").

I don't know this method is good or not but i get this error when i open on browser my registration index page 

    Line | Method
->>  223 | createGroovyPageView  in org.grails.web.servlet.view.GroovyPageViewResolver
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    200 | createGrailsView      in     ''
|     99 | loadView . . . . . .  in     ''
|     36 | loadView              in grails.plugin.scaffolding.ScaffoldingViewResolver
|    244 | createView . . . . .  in org.springframework.web.servlet.view.AbstractCachingViewResolver
|    472 | createView            in org.springframework.web.servlet.view.UrlBasedViewResolver
|    146 | resolveViewName . . . in org.springframework.web.servlet.view.AbstractCachingViewResolver
|     88 | resolveViewName       in org.grails.web.servlet.view.GroovyPageViewResolver
|     57 | resolveViewName . . . in org.grails.web.servlet.view.GrailsLayoutViewResolver
|   1296 | resolveViewName       in org.springframework.web.servlet.DispatcherServlet
|   1234 | render . . . . . . .  in     ''
|   1037 | processDispatchResult in     ''
|    980 | doDispatch . . . . .  in     ''
|    897 | doService             in     ''
|    970 | processRequest . . .  in org.springframework.web.servlet.FrameworkServlet
|    861 | doGet                 in     ''
|    622 | service . . . . . . . in javax.servlet.http.HttpServlet
|    846 | service               in org.springframework.web.servlet.FrameworkServlet
|    729 | service . . . . . . . in javax.servlet.http.HttpServlet
|    230 | internalDoFilter      in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter . . . . . .  in     ''
|     52 | doFilter              in org.apache.tomcat.websocket.server.WsFilter
|    192 | internalDoFilter . .  in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter              in     ''
|     55 | doFilterInternal . .  in org.springframework.boot.web.filter.ApplicationContextHeaderFilter
|    107 | doFilter              in org.springframework.web.filter.OncePerRequestFilter
|    192 | internalDoFilter . .  in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter              in     ''
|    105 | doFilterInternal . .  in org.springframework.boot.actuate.trace.WebRequestTraceFilter
|    107 | doFilter              in org.springframework.web.filter.OncePerRequestFilter
|    192 | internalDoFilter . .  in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter              in     ''
|     77 | doFilterInternal . .  in org.grails.web.servlet.mvc.GrailsWebRequestFilter
|    107 | doFilter              in org.springframework.web.filter.OncePerRequestFilter
|    192 | internalDoFilter . .  in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter              in     ''
|     67 | doFilterInternal . .  in org.grails.web.filters.HiddenHttpMethodFilter
|    107 | doFilter              in org.springframework.web.filter.OncePerRequestFilter
|    192 | internalDoFilter . .  in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter              in     ''
|    197 | doFilterInternal . .  in org.springframework.web.filter.CharacterEncodingFilter
|    107 | doFilter              in org.springframework.web.filter.OncePerRequestFilter
|    192 | internalDoFilter . .  in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter              in     ''
|     96 | doFilterInternal . .  in org.springframework.web.filter.CorsFilter
|    107 | doFilter              in org.springframework.web.filter.OncePerRequestFilter
|    192 | internalDoFilter . .  in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter              in     ''
|    107 | doFilterInternal . .  in org.springframework.boot.actuate.autoconfigure.MetricsFilter
|    192 | internalDoFilter      in org.apache.catalina.core.ApplicationFilterChain
|    165 | doFilter . . . . . .  in     ''
|    198 | invoke                in org.apache.catalina.core.StandardWrapperValve
|    108 | invoke . . . . . . .  in org.apache.catalina.core.StandardContextValve
|    472 | invoke                in org.apache.catalina.authenticator.AuthenticatorBase
|    140 | invoke . . . . . . .  in org.apache.catalina.core.StandardHostValve
|     79 | invoke                in org.apache.catalina.valves.ErrorReportValve
|     87 | invoke . . . . . . .  in org.apache.catalina.core.StandardEngineValve
|    349 | service               in org.apache.catalina.connector.CoyoteAdapter
|    784 | service . . . . . . . in org.apache.coyote.http11.Http11Processor
|     66 | process               in org.apache.coyote.AbstractProcessorLight
|    802 | process . . . . . . . in org.apache.coyote.AbstractProtocol$ConnectionHandler
|   1410 | doRun                 in org.apache.tomcat.util.net.NioEndpoint$SocketProcessor
|     49 | run . . . . . . . . . in org.apache.tomcat.util.net.SocketProcessorBase
|   1142 | runWorker             in java.util.concurrent.ThreadPoolExecutor
|    617 | run . . . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
|     61 | run                   in org.apache.tomcat.util.threads.TaskThread$WrappingRunnable
^    745 | run . . . . . . . . . in java.lang.Thread

Caused by GrailsTagException: [views/car/index.gsp:32] Attribute value quote wasn't closed (action="registration" controller="registration" params="[carId : ${car.id} ]").
->>   32 | populateMapWithAttributes in views/car/index.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Upvotes: 0

Views: 885

Answers (1)

Piyush
Piyush

Reputation: 1162

By default, an id is assigned to a domain class. So, in the index.gsp you can simple iterate over the list of cars and create a Rent button for each one of them. You can use g:each for that like below.

<g:each var="car" in="${cars}"> // cars is a list of cars
  <p>Brand: ${car.brand}</p>
  <p>Model: ${car.model}</p>
  <p><button name="rentCar${car.id}" onclick="rentCar(this, ${car.id})">Rent Car</button</p>
</g:each>

Hope this helps.

Also, if you want a link created for some other page per car, you can do

<g:each var="car" in="${cars}"> // cars is a list of cars
  <p>Brand: ${car.brand}</p>
  <p>Model: ${car.model}</p>
  <p><g:link action="rent" controller="order" params="[car: ${car}, carId : ${car.id} ]">
    Rent Car
  </g:link></p>
</g:each>

The g:link tag will create a link to the order controller's rent action. The car information can then be accessed there from the params.


New changes

Try the changes below. Let me know if they work.

1) Registration Controller

def index(Integer max) {

        params.max = Math.min(max ?: 10, 100)

        Car car;
        if(params.carId){
            car = Car.get(params.carId) // fetch the car using the id passed in params
        }

        respond Registration.list(params), model:[registrationCount: Registration.count(), car: car]
    }

Comment these lines in the show action like below

def show(Registration registration) {
        respond registration
   //     println params
   //    Car b = Car.get(params.id)
    }

2) Car/index.gsp

<g:link action="index" controller="registration" params="[carId : ${car.id} ]">
Rent Car
</g:link>

3) registration/index.gsp

<div><p>Car ID : ${car.id} </p></div>

Upvotes: 1

Related Questions