in the Grails application i need to add Extend button when a condition is true ,
Here is my GSP :
<table class="table table-hover table-bordered table-striped">
<thead>
<tr>
<g:sortableColumn property="adTitle"
title="${message(code: 'ads.adTitle.label', default: 'Ad Title')}" />
<g:sortableColumn property="adDetails"
title="${message(code: 'ads.adDetails.label', default: 'Ad Details')}" />
<g:sortableColumn property="duration"
title="${message(code: 'ads.duration.label', default: 'Duration')}" />
<g:sortableColumn property="dateCreated"
title="${message(code: 'ads.dateCreated.label', default: 'Creation Date')}" />
<g:sortableColumn property="durationDate"
title="${message(code: 'ads.durationDate.label', default: 'End Date')}" />
</tr>
</thead>
<tbody>
<g:each in="${adsInstanceList}" status="i" var="adsInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}" >
<td><g:link action="show" id="${adsInstance.id}">
${fieldValue(bean: adsInstance, field: "adTitle")}
</g:link></td>
<td>
${fieldValue(bean: adsInstance, field: "adDetails")}
</td>
<td>
${fieldValue(bean: adsInstance, field: "duration")}
</td>
<td><g:formatDate date="${adsInstance.dateCreated}" formatName='date.humanView' /></td>
<td><g:formatDate date="${adsInstance.durationDate}" formatName='date.humanView' /></td>
<td id="test"> </td>
</tr>
<g:if
test="${formatDate(formatName:'date.humanView',date:adsInstance.durationDate) == formatDate(formatName:'date.humanView',date:new Date()+1)}">
<script type="text/javascript">
$(document).ready(
function() {
var add = $('<g:submitButton name="extendAd" value="Extend" />')
$('#test').append(add)
-
});
</script>
</g:if>
</g:each>
</tbody>
</table>
</div>
as the below screenshot shows when the Ad End date is 12-9-2016 the Extend button should appears , but as you can see it is showing 3 times in the first row only although it supposed to be shown in first,second and third rows.
Am i missing something in my GSP code?
You should do this without javascript:
<td id="test">
<g:if test="${formatDate(formatName:'date.humanView',date:adsInstance.durationDate) == formatDate(formatName:'date.humanView',date:new Date()+1)}">
<g:submitButton name="extendAd" value="Extend" />
</g:if>
</td>
If you want to do this with javascript, you cannot use an id (because id has to be unique) but a class:
<td class="test"></td>
...
<script type="text/javascript">
$(document).ready(
function() {
var add = $('<g:submitButton name="extendAd" value="Extend" />')
$('.test').append(add)
});
</script>
Related
I am using grails 2.4.2. I have a form from where I can add , edit or delete any data or row. But from index I want to delete a single row on demand. For that I have added a link in my table cell for each row. But it is giving error no 405 which is The specified HTTP method is not allowed for the requested resource. Can anyone please help me on this ? Here are my index page below :
My index.gsp >>>
<table>
<thead>
<tr>
<g:sortableColumn property="address" title="${message(code: 'userInfo.address.label', default: 'Address')}" />
<g:sortableColumn property="name" title="${message(code: 'userInfo.name.label', default: 'Name')}" />
<g:sortableColumn property="name" title="${message(code: 'userInfo.name.label', default: 'Action')}" />
</tr>
</thead>
<tbody>
<g:each in="${userInfoInstanceList}" status="i" var="userInfoInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${userInfoInstance.id}">${fieldValue(bean: userInfoInstance, field: "address")}</g:link></td>
<td>${fieldValue(bean: userInfoInstance, field: "name")}</td>
<td><g:link action="delete" id="${userInfoInstance.id}">Delete</g:link></td>
</tr>
</g:each>
</tbody>
</table>
I think that you are using "allowedMethods" inside your controller , like this
static allowedMethods = [delete: "POST"]
http://grails.github.io/grails-doc/2.4.2/ref/Controllers/allowedMethods.html
but when you use the link taglib you are making a GET request instead of POST
In my program, which is a project tracker, I have a table with rows corresponding to the projects, and columns corresponding to the different information about the project (name, due date, status etc.). The last column should be 'More' column, that should display a dropdown list of additional attributes of the project whenever you press it. How do I do that in Grails?
Below is my list.gsp:
<calendar:resources lang="en"/>
<!doctype html>
<html>
<head>
<meta name="layout" content="layoutMain"/>
<g:set var="entityName" value="${message(code: 'project.label', default: 'Project')}" />
<title><g:message code="default.list.label" args="[entityName]" /></title>
</head>
<body>
<div class="nav" role="navigation">
<ul>
<li><g:link class="create" action="create"><button>New Project</button></g:link></li>
</ul>
</div>
<div id="list-project" 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>
<thead>
<tr>
<g:sortableColumn property="name" title="${message(code: 'project.name.label', default: 'Name')}" />
<g:sortableColumn property="dueDate" title="${message(code: 'project.dueDate.label', default: 'Due Date')}" />
<g:sortableColumn property="startDate" title="${message(code: 'project.startDate.label', default: 'Start Date')}" />
<g:sortableColumn property="status" title="${message(code: 'project.name.label', default: 'Status')}" />
<g:sortableColumn property="requirements" title="${message(code: 'project.name.label', default: 'Requirements')}" />
<g:sortableColumn property="design" title="${message(code: 'project.name.label', default: 'Design')}" />
<g:sortableColumn property="development" title="${message(code: 'project.name.label', default: 'Development')}" />
<g:sortableColumn property="qa" title="${message(code: 'project.name.label', default: 'QA')}" />
<g:sortableColumn property="ua" title="${message(code: 'project.name.label', default: 'UA')}" />
<g:sortableColumn property="delivery" title="${message(code: 'project.name.label', default: 'Delivery')}" />
<g:sortableColumn property="more" title="${message(code: 'project.name.label', default: 'More')}" />
</tr>
</thead>
<tbody>
<g:each in="${projectInstanceList}" status="i" var="projectInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "name")}</g:link></td>
<td><g:formatDate date="${projectInstance.dueDate}" /></td>
<td><g:formatDate date="${projectInstance.startDate}" /></td>
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "status.name")}</g:link></td>
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "requirements.name")}</g:link></td>
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "design.name")}</g:link></td>
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "development.name")}</g:link></td>
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "qa.name")}</g:link></td>
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "ua.name")}</g:link></td>
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "delivery.name")}</g:link></td>
<td><g:link action="show" id="${projectInstance.id}">${fieldValue(bean: projectInstance, field: "delivery.name")}</g:link></td>
</tr>
</g:each>
</tbody>
</table>
<div class="pagination">
<g:paginate total="${projectInstanceTotal}" />
</div>
</div>
</body>
</html>
If you want to use standard Grails you can create a dropdown in Grails using a g:select tag. A prettier solution might be to use jQuery (or similar) to show hide a block of HTML.
If your project domain looks something like:
class Project {
String name
...
// more info
String attr1
int attr2
boolean isAttr3
}
You can add a convenience method to your domain to aggregate the fields into a list (or possibly another object) that can be used for a drop down box. E.g.
// utility getter to aggregate the fields into an array
def getMoreInfo() {
[attr1, attr2, isAttr3]
}
Then you can use the following in your GSP:
<td><g:select name="more" from="${projectInstance.moreInfo}" /></td>
On the click of more column you can send an Ajax request to some action which can bring you JSON of two arrays:
{extraColumns:{c1,c2}, columnValues:{{v11,v12}, {v21,v22}}}
In the response of Ajax you can parse the JSON and create additional columns for headers and additional column values for rows.
I have a table that has columns in a template:
<div id="petDiv">
<table>
<thead>
<tr>
<g:sortableColumn property="breed" title="${message(code: 'contact.breed.label', default: 'Breed')}" />
<g:sortableColumn property="age" title="${message(code: 'contact.age.label', default: 'Age')}" />
</tr>
</thead>
<tbody>
<g:each in="${availablePets}" status="i" var="pet">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${pet.id}">${fieldValue(bean: pet, field: "Breed")}</g:link></td>
<td>${fieldValue(bean: pet, field: "Age")}</g:link></td>
<td>
<g:form>
<fieldset class="pDivB">
<g:remoteLink action="updatePet" update="another template here??" params: [] >Update</g:remoteLink>
</fieldset>
</g:form>
</td>
</tr>
</g:each>
</tbody>
</table>
</div>
I want:
Hit link
Go to updatePet method in Controller with the ID of that pet
Update my <td> tags for breed and age for that row only
I tried using a jQuery/Javascript combination I read online, but it updates the first row only.
I have some sample code that does something similar - https://github.com/aldrinm/grails-sample-code
Hope that helps.
I am trying to upload a picture, and save it in database.
If I do the following I get this error:
Failed to convert property value of type
org.springframework.web.multipart.commons.CommonsMultipartFile to
required type java.lang.Byte[] for property picture1; nested exception
is java.lang.IllegalArgumentException: Cannot convert value of type
[org.springframework.web.multipart.commons.CommonsMultipartFile] to
required type [java.lang.Byte] for property picture1[0]:
PropertyEditor
[org.springframework.beans.propertyeditors.CustomNumberEditor]
returned inappropriate value
If i do it this way:
if(request instanceof MultipartHttpServletRequest){
MultipartHttpServletRequest mpr = (MultipartHttpServletRequest)request;
CommonsMultipartFile f = (CommonsMultipartFile) mpr.getFile("picture1");
}
I get this error:
Executing action [save] of controller [com.testapp.RequestController]
caused exception: Cannot cast object '
org.springframework.web.multipart.commons.CommonsMultipartFile#34ae1f02'
with class
'org.springframework.web.multipart.commons.CommonsMultipartFile' to
class 'java.lang.Byte'
What should I do to make this work?
Domain
package com.testapp
class Request{
String requestID
Date dateCreated
String subject
String startedBy
String description
String status
String priority
Productline productline
Topic topic
Subtopic subtopic
String company
Byte [] picture1
Byte [] picture2
Byte [] picture3
String acceptedBy
static constraints = {
requestID(blank:true,nullable:true)
dateCreated(blank:true,nullable:true)
subject()
description(maxSize:5000)
status (blank:true,nullable:true)
priority(inList:["Normal","Urgent","Not urgent"])
productline(blank:true,nullable:true)
topic(blank:true,nullable:true)
subtopic(blank:true,nullable:true)
company(blank:true,nullable:true)
startedBy(blank:true,nullable:true)
acceptedBy(blank:true,nullable:true)
picture1(blank:true,nullable:true)
picture2(blank:true,nullable:true)
picture3(blank:true,nullable:true)
}
}
GSP:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'request.label', default: 'Request')}" />
<title><g:message code="New request" args="[entityName]" /></title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLink(uri: '/')}"><g:message `code="default.home.label"/></a></span>`
<span class="menuButton"><g:link class="list" action="userList"><g:message code="Lista zahteva" `args="[entityName]" /></g:link></span>`
</div>
<div class="body">
<h1><g:message code="New request" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${requestInstance}">
<div class="errors">
<g:renderErrors bean="${requestInstance}" as="list" />
</div>
</g:hasErrors>
<g:form action="save" method="post" enctype="multipart/form-data">
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="subject"><g:message code="request.subject.label" default="Subject" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'subject', 'errors')}">
<g:textField name="subject" value="${requestInstance?.subject}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="description"><g:message code="request.description.label" default="Opis" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'description', 'errors')}">
<g:textArea name="description" cols="40" rows="5" value="${requestInstance?.description}" />
</td>
</tr>
<tr>
<td valign="top" class="name">
<label for="picture1"><g:message code="request.picture1.label" default="Printscreen" /></label>
</td>
<td valign="top" class="value">
<input type="file" id="picture1" name="picture1"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="priority"><g:message code="request.priority.label" default="Priority" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'status', 'errors')}">
<g:select name="priority" from="${requestInstance.constraints.priority.inList}" value="${requestInstance?.priority}" valueMessagePrefix="request.priority" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="productline"><g:message code="request.productline.label" default="Productline" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'productline', 'errors')}">
<g:select name="productline.id" from="${com.testapp.Productline.list()}" optionKey="id" value="${requestInstance?.productline?.id}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="topic"><g:message code="request.topic.label" default="Topic" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'topic', 'errors')}">
<g:select name="topic.id" from="${com.testapp.Topic.list()}" optionKey="id" value="${requestInstance?.topic?.id}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="subtopic"><g:message code="request.subtopic.label" default="Subtopic" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'subtopic', 'errors')}">
<g:select name="subtopic.id" from="${com.testapp.Subtopic.list()}" optionKey="id" value="${requestInstance?.subtopic?.id}" />
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" /></span>
</div>
</g:form>
</div>
</body>
Controller:
def save = {
def requestInstance = new Request(params)
def requestNumberInstance = new RequestNumber()
def upPic1 = request.getFile('picture1')
def lastReqNum = RequestNumber.find("from RequestNumber ORDER BY requestNumber desc")
if(lastReqNum){
requestNumberInstance.requestNumber = lastReqNum.requestNumber + 1
}
else{
requestNumberInstance.requestNumber = 110000
}
requestInstance.requestID = "CSC" + requestNumberInstance.requestNumber
def currentUserContact = Contact.findByUser(springSecurityService.getCurrentUser())
requestInstance.startedBy = currentUserContact.realname
requestInstance.company = currentUserContact.company
requestInstance.status = "Opened"
requestInstance.acceptedBy = "Not yet accepted"
requestInstance.picture1 = upPic1
if(requestNumberInstance.save()){
if (requestInstance.save()) {
flash.message = "${message(code: 'default.created.message', args: [message(code: 'request.label', default: 'Request'), requestInstance.id])}"
redirect(action: "show", id: requestInstance.id)
}
else {
render(view: "create", model: [requestInstance: requestInstance])
}
}
else{
render(view: "create", model: [requestInstance: requestInstance])
}
}
Please dont mind the spaghetti code. I'm just trying to get some basic concepts. I will clear it later.
Simplified example:
def save = {
def requestInstance = new Request(params)
def requestNumberInstance = new RequestNumber()
if(requestInstance.validate() && requestInstance.save(flush: true)){
println "Saved successfully with ${requestInstance.picture1.length} bytes"
}
else {
println "Save failed"
}
Update after question edit
The error is probably caused by this:
def upPic1 = request.getFile('picture1')
...
requestInstance.picture1 = upPic1
request.getFile() is returning a MultipartFile, and you're trying to assign it to a Byte[] field. Considering my small example (below), you shouldn't even need to try to make this assignment. The def requestInstance = new Request(params) will bind the byte[] automatically.
Uploaded files bind automatically to byte[] fields. Here's a working example:
Domain: grails-app/domain/my/Example.groovy
package my
class Example {
byte[] file
}
Controller: grails-app/controllers/my/ExampleController.groovy
package my
class ExampleController {
def create = { }
def save = {
def example = new Example(params)
if(example.validate() && example.save(flush: true)) {
println "Saved successfully with ${example.file.length} bytes"
} else {
println "Save failed"
}
redirect(action: 'create')
}
}
GSP: grails-app/views/example/create.gsp
<!DOCTYPE html>
<html>
<body>
<g:uploadForm action="save">
<input type="file" name="file"/>
<g:submitButton name="submit"/>
</g:uploadForm>
</body>
</html>
When I upload a small file using the GSP form, I see the following console output:
Saved successfully with 23 bytes
Suggestions
Try using Grails data binding to save your file contents.
Make sure your form is a <g:uploadForm> or has an enctype="multipart/form-data" if you're using a vanilla`.
Make sure you're binding the params using the domain constructor, domain.properties, or bindData().
I am guessing your typing is messed up.
What happens if you simply do:
def f = request.getFile('myFile')
as described in the manual. If you want strong typing it should be MultiPartfile, not CommonsMultiPartFile, as far as I remember (and you get it right from the request object).
This is the interface you're working on: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/multipart/MultipartFile.html
The relevant method for you, should be getBytes().
Edit for edited question:
As I said, you want getBytes(), you are trying to shove a MultiPartFile into a byte array, thats not going to work.
requestInstance.picture = upPic.getBytes() and you should be allright.
It only worked when I changed my domain properties picture1,picture2,picture3 to:
byte [] picture1
byte [] picture2
byte [] picture3
and added those mappings:
static mapping = {
picture1 column:"picture1", sqlType: "blob"
picture2 column:"picture2", sqlType: "blob"
picture3 column:"picture3", sqlType: "blob"
}
I want to create a gsp page that contains several tables.
Note that with the term "tables" I mean graphical tables ( tag) not database tables.
The tables shall have sortable headers
If a gsp page contains only one table it is easy to use the existing sortableColumn and paginate tags.
They insert relevant entries to the "params" map (e.g. "sort=column4711").
However if several graphical tables are involved on the page this does not work that easy.
The problem is that the associated controller does not know which table the params are associated with
(i.e. if there is a map entry "sort=column4711" the controller does not know to which table it belongs).
I am currently thinking of the following solution that I consider quite ugly:
<div class="list">
<table>
<thead>
<tr>
<g:sortableColumn property="id" title="${message(code: 'user.id.label', default: 'Id')}" />
<g:sortableColumn property="password" title="${message(code: 'user.password.label', default: 'Password')}" />
<g:sortableColumn property="userId" title="${message(code: 'user.userId.label', default: 'User Id')}" />
<g:sortableColumn property="userName" title="${message(code: 'user.userName.label', default: 'User Name')}" />
<g:sortableColumn property="id" title="${message(code: 'bookDetails.id.label', default: 'Id')}" />
<th><g:message code="bookDetails.bookId.label" default="Book Id" /></th>
<g:sortableColumn property="pages" title="${message(code: 'bookDetails.pages.label', default: 'Pages')}" />
<g:sortableColumn property="price" title="${message(code: 'bookDetails.price.label', default: 'Price')}" />
<g:sortableColumn property="id" title="${message(code: 'book.id.label', default: 'Id')}" />
<g:sortableColumn property="author" title="${message(code: 'book.author.label', default: 'Author')}" />
<g:sortableColumn property="bookId" title="${message(code: 'book.bookId.label', default: 'Book Id')}" />
<g:sortableColumn property="bookName" title="${message(code: 'book.bookName.label', default: 'Book Name')}" />
<g:sortableColumn property="category" title="${message(code: 'book.category.label', default: 'Category')}" />
</tr>
</thead>
<tbody>
<g:each in="${userInstanceList}" status="i" var="userInstance">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td><g:link action="show" id="${userInstance.id}">${fieldValue(bean: userInstance, field: "id")}</g:link></td>
<td>${fieldValue(bean: userInstance, field: "password")}</td>
<td>${fieldValue(bean: userInstance, field: "userId")}</td>
<td>${fieldValue(bean: userInstance, field: "userName")}</td>
</tr>
</g:each>
<g:each in="${bookDetailsInstanceList}" status="i" var="bookDetailsInstance">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td><g:link action="show" id="${bookDetailsInstance.id}">${fieldValue(bean: bookDetailsInstance, field: "id")}</g:link></td>
<td>${fieldValue(bean: bookDetailsInstance, field: "bookId")}</td>
<td>${fieldValue(bean: bookDetailsInstance, field: "pages")}</td>
<td>${fieldValue(bean: bookDetailsInstance, field: "price")}</td>
</tr>
</g:each>
<g:each in="${bookInstanceList}" status="i" var="bookInstance">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td><g:link action="show" id="${bookInstance.id}">${fieldValue(bean: bookInstance, field: "id")}</g:link></td>
<td>${fieldValue(bean: bookInstance, field: "author")}</td>
<td>${fieldValue(bean: bookInstance, field: "bookId")}</td>
<td>${fieldValue(bean: bookInstance, field: "bookName")}</td>
<td>${fieldValue(bean: bookInstance, field: "category")}</td>
</tr>
</g:each>
</tbody>
</table>
</div>
</div>
<body>
so please guide us to solve the problem
There's a remote pagination plugin. It had some issues that I had to fix, but I don't have my modified version of it (and it's been a while since I used it). Basically it makes Ajax calls instead of rendering the entire page. You get tags for remoteSortableColumn and remotePaginate