Search code examples
grails

How to dynamically change a section of a view using the onChange event of a g:select tag?


I'm having a hard time figuring out how to essentially reload a section of my view with new data after a selection from a DropDownMenu(in grails 3.3.9)

I've tried using the same convention of a button in grails, which is pretty straight forward:

<g:select class="btn bg-primary" action="filterByCommittee" controller="management"
 from="${Committee.list()}" optionKey="id" optionValue="${name}" 
name="committees" value="${committees}" noSelection="${['null':'Select..']}"/>

the code above means(AFAIK) i want to trigger an action(filterByCommittee) which resides in a controller(Management), using params.committees(the name of the field). the mentioned action would filter the purchases(a list shown to the user) by the selected committee.

any help would be greatly appreciated!

some relevant code:

class ManagementController {

    PurchaseService purchaseService
    CommitteeService committeeService

    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        List<Purchase> purchaseList = Purchase.findAllByAccountantApprovalInList(Approval.findAllByApproved(true))
        }
        respond purchaseList, model:[purchaseCount: purchaseService.count()]
    }

    def filterByCommittee() {
        Committee selectedCommittee = Committee.findByName(params.committees)
        List<User> userList = User.findAllByCommittee(selectedCommittee)
        List<Purchase> purchaseList = Purchase.findAllByUserInList(userList)
        respond purchaseList, model:[purchaseCount: purchaseService.count()]
    }
}
class Committee {

    String name

    static hasMany = [users:User, summaries:Summary]

    static constraints = {
        users(nullable: true)
        summaries(nullable: true)
    }

    @Override
    public String toString() {
        return name
    }
}

<!DOCTYPE html>
<!--<%@ page import="attainrvtwo.Committee" contentType="text/html;charset=UTF-8" %>-->
<html xmlns:g="http://www.w3.org/1999/html">
<body>
<a href="#list-purchase" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content&hellip;"/></a>
<div class="nav" role="navigation">
    <ul>
        <li><g:select class="btn bg-primary" action="filterByCommittee" controller="management" from="${Committee.list()}" optionKey="id" optionValue="${name}" name="committees" value="${committees}" noSelection="${['null':'Select..']}"/></li>
    </ul>
</div>
<div id="list-purchase" 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="${purchaseList}" />

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

Solution

  • the solution i pieced together looks something like this:

    in the ManagementController

    package attainrvtwo
    
    class ManagementController {
    
        CommitteeService committeeService
        List<Purchase> purchaseList
    
        def filterByCommittee() {
            session.filterPurchases = true
            Committee selectedCommittee = committeeService.get(params.id)
            List<User> userList = User.findAllByCommittee(selectedCommittee)
            purchaseList = Purchase.findAllByUserInList(userList)
            respond purchaseList, model:[purchaseCount: purchaseService.count()]
        }
    }
    

    in the index.gsp file of management view

    <!DOCTYPE html>
    <!--<%@ page import="attainrvtwo.Committee" contentType="text/html;charset=UTF-8" %>-->
    <html xmlns:g="http://www.w3.org/1999/html">
    <head>
        <meta name="layout" content="main" />
        <g:set var="entityName" value="${message(code: 'purchase.label', default: 'Purchase')}" />
        <title></title>
    </head>
    <body>
    <a href="#list-purchase" 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: '/volunteer/index')}"><g:message code="default.home.label"/></a></li>-->
            <li><g:select class="btn bg-primary" id="commDDLid" name="committeeDDL" action="filterByCommittee" controller="management" from="${Committee.list()}" optionKey="id" optionValue="${name}" value="${committees}" noSelection="${['null':'Select..']}" onchange="goToPage(this.value)"/></li>
        </ul>
    </div>
    <div id="list-purchase" 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="${purchaseList}" />
    
        <div class="pagination">
            <g:paginate total="${purchaseCount ?: 0}" />
        </div>
    </div>
    <script type="text/javascript">
        function goToPage(requestParams) {
        window.location.href="${'/management/filterByCommittee'}" + "/" + requestParams;
        }
    </script>
    </body>
    </html>
    

    then i've also added the filterByCommitty.gsp view which is basically a copy of my index.gsp (notice the import line at the beginning and the script tag at the end)

    <!DOCTYPE html>
    <!--<%@ page import="attainrvtwo.Committee" contentType="text/html;charset=UTF-8" %>-->
    <html xmlns:g="http://www.w3.org/1999/html">
    <head>
        <meta name="layout" content="main" />
        <g:set var="entityName" value="${message(code: 'purchase.label', default: 'Purchase')}" />
        <title></title>
    </head>
    <body>
    <a href="#list-purchase" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content&hellip;"/></a>
    <div class="nav" role="navigation">
        <ul>
            <li><g:select class="btn bg-primary" id="commDDLid" name="committeeDDL" action="filterByCommittee" controller="management" from="${Committee.list()}" optionKey="id" optionValue="${name}" value="${committees}" noSelection="${['null':'Select..']}" onchange="goToPage(this.value)"/></li>
        </ul>
    </div>
    <div id="list-purchase" 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="${purchaseList}" />
    
        <div class="pagination">
            <g:paginate total="${purchaseCount ?: 0}" />
        </div>
    </div>
    <script type="text/javascript">
        function goToPage(requestParams) {
        window.location.href="${'/management/filterByCommittee'}" + "/" + requestParams;
        }
    </script>
    </body>
    </html>
    

    i hope this helps someone. if there are any improvement suggestions i'd be glad to correct them. cheers ;)