larand
larand

Reputation: 831

Grails, executing a javascript by clicking on a column in a table row

I have a view consisting of two lists: products and offers. You can select several rows by checking checkboxes on them and then by clicking on a link, offer lines will be created for each selected product. Every offer line has the id of the product which I will use to list all offers created for that product in a list below the list of products.

I tried to solve that by using a javascript which should be activated when you click on a link or field in the product list. The script sends a message to the controller that creates the list of offers for this product and then render a template in this view.

I can just use a link and call the controller and the template will be rendered but of course not the rest of the view.

So I need to have line:

<td><g:link action="listOffers" id="${pb.id}">${pb.volumeOffered}</g:link></td>

replaced with something better that can call my javascript-function. I read somewhere you could put an -onclick="javascript-function" in the g:link tag but it doesn't work.

Below is the most important part of controller and gsp in this case.

In the List.gsp:

    <script type="text/javascript">
        function listOffers(id){
        $.ajax({
                url:'${g.createLink( controller:'ordersAndStore', action:'listOffers' )}',
        data: [id],
        type: 'get'
        }).success( function ( data ) { $( '#offerList' ).html( data ); });
        }
    </script>    
.....
.....
    <g:render template="ListOffers" model="[offerDetails:offerDetails]"/>

In the template _AvailableProductData.gsp:

    <g:each in="${prodBuffer}" status="i" var="pb"> 
  <tr class="${ (i % 2) == 0 ? 'even': 'odd'}">
                <td><a onclick="listOffers(${pb.id})">${pb.volumeOffered}</a></td> 

In the template _ListOffers.gsp:

<div id="offerList">
    <g:set var="entityName" value='Offers' />
    <div id="list-offers" class="content scaffold-list" role="main">
        <h1><g:message code="default.list.label" args="[entityName]" /></h1>
        <table style="width:100%">
            <thead>
                <tr>
                    <g:sortableColumn property="product" title='Product' />
                    <g:sortableColumn property="volumeOffered" title='Volume' />
                </tr>
            </thead>
            <tbody>
                <g:each in="${offerDetails}" status="i" var="od">
                    <tr class="${ (i % 2) == 0 ? 'even': 'odd'}">
                        <td><g:link class="edit" action="edit" resource="offerDetail" id="${od?.id}"> ${od.product?.encodeAsHTML()}</g:link></td>
                        <td>${od?.volumeOffered}</td>
                    </tr>
                </g:each>
            </tbody>
        </table>
        <div class="pagination">
            <g:paginate total="${offersCount ?: 0}" />
        </div>
    </div>
</div>

In the controller:

def listOffers(){
    def List<OfferDetail> offerDetails = getOfferList()
    render(template:"ListOffers", model:[offerDetails: offerDetails])
}

Added a printout to see what params contains:

def listOffers(){
    System.out.println("#--#"+params)
    def List<OfferDetail> offerDetails = getOfferList()
    render(template:"ListOffers", model:[offerDetails: offerDetails])
}

The printout is:

#--#[undefined:, controller:ordersAndStore, format:null, action:listOffers]

Following is the complete javascript section, the first one is working good but then comes the onclick version that responds and calls the controller but can not send the id. Then comes your version and another one simple but no one is working.

    <script type="text/javascript">
        function availableProducts(){
            $.ajax({
                url:'${g.createLink( controller:'ordersAndStore', action:'availableProducts' )}',
                    data: [sawMill],
                    type: 'get'
            }).success( function ( data ) { $( '#divToUpdate' ).html( data ); });
        }

        function listOffers(){
            $.ajax({
                url:'${g.createLink( controller:'ordersAndStore', action:'listOffers' )}',
                data: [],
                type: 'get'
            }).success( function ( data ) { $( '#offerList' ).html( data ); });
        }

        $( document ).ready( function() {
            $( '.offers' ).click( function ( event ){
                alert('HEJ')
                $.ajax({
                    url:'${g.createLink( controller:'ordersAndStore', action:'listOffers' )}',
                    data: [this.id],
                    type: 'get'
                }).success( function ( data ) { $( '#offerList' ).html( data ); });
            });
        });
        $( document ).ready( function() {
            $('.test1').bind('click', function (){
            alert('KLICKED');
            });
        });

    </script>    

And the gsp-part in the template:

        <g:each in="${prodBuffer}" status="i" var="pb"> 
            <tr id="{$pb.id}" class="offers" class=" ${ (i % 2) == 0 ? 'even': 'odd'}">
                <td><g:checkBox name="toOffer" value="${pb.id}" checked="false"  /></td>
                <td><g:link action="edit_prodbuffer" id="${pb.id}">${pb.id}</g:link></td>
                <td>${pb.sawMill}</td>
                <td>${pb.product}</td>
                <td>${pb.length}</td>
                <td>${pb.volumeAvailable}</td>
                <td><a  onclick='listOffers()' > ${pb.volumeOffered}</a></td>

==================================================

I have taken an old test project which I cleaned and modified to this simple example that still don't work:

<!DOCTYPE html>
<html>
    <head>
        <meta name="layout" content="main" />
        <g:set var="entityName" value="${message(code: 'author.label', default: 'Author')}" />
        <title><g:message code="default.list.label" args="[entityName]" /></title>
        <script type="text/javascript">
            $( document ).ready( function() {
                $( '.off1' ).click( function ( event ){
                    alert('HEJ');
                });
            });
        </script>    
    </head>
    <body>
        <a href="#list-author" 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-author" 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>
            <table>
                <th></th>
                <tbody
                    <g:each in="${authorList}" status='i' var='a'>
                        <tr id="${a.id}" class="off1">
                            <td><g:field  type="text" name="author" value="${a?.name}"/> </td>
                        </tr>
                    </g:each>
            <div class="pagination">
                <g:paginate total="${authorCount ?: 0}" />
            </div>
        </div>
    </body>
</html>

I begin to be desperate, can't make this work but I must :( I'll list the code again with some different settings and the output. Sure something must be wrong with my code as others can make it work but what is wrong?

Part of the GSP-file where things start, there is two alternative lines one is commented here.

                <g:each in="${authorList}" status='i' var='a'>
                    <tr id="${a.id}" onclick="listOffers(6)">
<!--   This line uses script B ------ <tr id="${a.id}" class="off1">-->
                        <td><g:field  type="text" name="author" value="${a?.name}"/> </td>
                    </tr>
                </g:each>

-- Controller:

def listOffers() {
    System.out.println("### --- HEJ --- ### "+params)
}

-- Script A:

    function listOffers(id){
            alert('HEJ<<<<<<<<<<<<<<'+ id);
            $.ajax({
                url:'${g.createLink( controller:'author', action:'listOffers', id:"${id}" )}',
                data: [id],
                type: 'get'
            }).success( function ( data ) { $( '#offerList' ).html( data ); });
        }

-- Script B:

        $( document ).ready( function() {
            $(".off1").click( function(event){
                alert('HEJ');
            });
        });

Script B: never respond - WHY?

Output from controller using script A:

### --- HEJ --- ### [undefined:, controller:author, format:null, action:listOffers, id:null]

Modified script A -- data is empty:

        function listOffers(id){
            alert('HEJ<<<<<<<<<<<<<<'+ id);
            $.ajax({
                url:'${g.createLink( controller:'author', action:'listOffers', id:"${id}" )}',
                data: [],
                type: 'get'
            }).success( function ( data ) { $( '#offerList' ).html( data ); });
        }

Output from controller using modified version of script A:

### --- HEJ --- ### [controller:author, format:null, action:listOffers, id:null]

The alert call works ok and I get the correct value of id there. As yo can see from the controller printout id is null and if data contains id I also get 'undefined:' as a parameter. If I remove id from data, now data[], this 'undefined:' disappear

Upvotes: 1

Views: 1301

Answers (3)

larand
larand

Reputation: 831

The problem was in 2 points. First: In main.gsp I moved the string:

<asset:javascript src="application.js"/>

from the end of the file up to the head close to the css-loading. This made the script to respond.

But then I couldn't get the data from "id" go in to params. but by rewriting the row:

data:[this.id] to data:{id: this.id}

it worked.

Upvotes: 0

Mike W
Mike W

Reputation: 3932

You could give each table row the ID then respond to events when the row is clicked:

Breaking this down to a simple example with JUST the parts to show how it works.

OrdersAndStoreController

class OrdersAndStoreController {

    def index() {
        [prodBuffer: [new ProdBuffer(id: 1, volumeOffered: 100), new ProdBuffer(id: 2, volumeOffered: 200)]]
    }

    def listOffers() {
        render(template:"ListOffers", model:[offerDetails: [offer1: 'offer1', offer2: 'offer2']])
    }
}

class ProdBuffer{
    Integer id
    Integer volumeOffered
}

index.gsp

<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />

<script type="text/javascript">
    $( document ).ready( function() {
        $( '.offers' ).click( function ( event ){
            $.ajax({
                url:'${g.createLink( controller:'ordersAndStore', action:'listOffers' )}',
                data: [this.id],
                type: 'get'
            }).success( function ( data ) { $( '#offerList' ).html( data );     });
        });
    });
</script>
</head>
<body>


<table>
    <thead>
    <th>Volume offered</th>
    </thead>
    <g:each in="${prodBuffer}" status="i" var="pb">
        <tr id="${pb.id}" class="offers">
            <td>${pb.volumeOffered}</td>
        </tr>
    </g:each>
</table>

<div id="offerList"></div>

</body>
</html>

_ListOffers.gsp

${offerDetails}

Upvotes: 1

Tinku Saini
Tinku Saini

Reputation: 460

You need to change your element like this

<td><a onclick="listOffers(${pb.id})>${pb.volumeOffered}</a></td>

and Jquery function which accept id.

<script type="text/javascript">
    function listOffers(id){
    $.ajax({
            url:'${g.createLink( controller:'ordersAndStore', action:'listOffers' )}',
    data: [id],
    type: 'get'
    }).success( function ( data ) { $( '#offerList' ).html( data ); });
    }
</script> 

Upvotes: 1

Related Questions