How to keep query results after deleting an item? - grails

In my Grails application I have multiple pages that list a group of data objects inside of a table. In these pages I provide a search function which when performed will adjust the table to only display the data objects that match the query. However If a user decides to delete one of these data objects the application will take them back to the default table which displays everything. I would like for query results to remain intact after performing a delete.
I will use my "Skill Evaluations" page as my example in this post.
Here is the relevant code in the domain class
SkillEval.groovy
class SkillEval {
static hasMany = [lines: SkillEvalL, courses: CourseOffering, choiceLabels: ChoiceLabel]
String name
String formVersion
static def search(params) {
def criteria = SkillEval.createCriteria()
def results = criteria.list(params) {
or {
ilike("name", params.search+'%')
}
}
return results
}
}
Relevant section of the gsp view file
list.gsp
<g:form>
<div class="search">
<label for="searchField">Search:</label> <input type="text"
id="searchField" name="search" value="${params.search}" /> <input
type="submit" value="Search" />
</div>
<br>
<table id="mainTable">
<thead>
<tr>
<th>Name</th>
<th>Version</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<g:each var="eval" in="${skillEvalList}">
<tr>
<td>
<strong>
${eval.name}
</strong>
</td>
<td>
${eval.formVersion}
</td>
<td>
<g:actionSubmit value="Delete" controller="skillEval" action="delete" onclick="setId(${eval.id});return confirm('Are you sure?');" class="delete" />
</td>
</tr>
</g:each>
</tbody>
</table>
<g:if test="${(skillEvalCount/maxCount) > 1}">
<div class="pagination">
<g:paginate action="list" total="${skillEvalCount}" />
</div>
</g:if>
<input id="evalId" type="hidden" name="id" value="" />
</g:form>
</div>
<r:script>
function setId(id)
{
$('#evalId').val(id);
}
</r:script>
Relevant code in the Controller class
SkillEvalController.groovy
def delete(Long id) {
def skillEval = SkillEval.get(id)
if (skillEval) {
def allInstances = SkillEvalI.findAllByForm(skillEval)
allInstances.each { evalInstance ->
evalInstance.lines.clear()
if(!evalInstance.delete()) {
println "Failed to delete skill eval instance"
}
else {
println "Instance successfully deleted."
}
}
try {
skillEval.delete(flush: true)
}
catch (DataIntegrityViolationException e) {
}
}
redirect(action: "list")
}
How can I make the view retain the queried results after deleting one of the queried items?

When you redirect to the list action you can provide parameters -- just capture the parameters (if any) in the delete action and pass them in the redirect call to list at the end of the controller action.
(Update: Forgot that actionSubmit does not accept params as an attribute, so cobbled together this solution from this SO answer and the Grails docs)
Example:
// View (list.gsp)
<g:actionSubmit action="deleteWithParams" value="Delete" ... />
// Controller
def list() {
def deleteWithParams = { forward(action:'delete', params:[search: params?.search]) }
render...
}
def delete(Long id) {
// Deleting the skillEval ...
redirect(action: "list", params: [search: params?.search])
}

Related

Thymeleaf: How to get selected item on click

I want to call a method with the clicked object as a param.
Problem: on every reload or button press the method is called for every element.
<form action="#" th:action="#{/}" th:object="${chessBoard}" method="post">
<table>
<tr th:each="i, iter1: *{board}">
<td th:each="item, iter2: ${i}">
<button th:onclick="${chessBoard.selected(item)}" th:text="${item.text}"></button>
</td>
<tr>
</table>
</form>
You don't need the onclick method in your form to submit a parameter.
You can simply pass a parameter to the controller with a RequestedParam annotation in your controller.
It will be something like:
<form th:action="#{/}" method="post">
<table>
<tr th:each="i: ${board}">
<td th:each="item: ${i}">
<button name="item" th:value="${item.id}" th:text="${item.text}"/>
</td>
<tr>
</table>
</form>
and in your controller:
#PostMapping (path = "/")
public String test(Model model, #RequestParam(name = "item") int id) {
System.out.println(id);
}
A second option is to use an attribute that you add to your model and you get back in your controller with something like:
#PostMapping("/")
public String greetingSubmit(#ModelAttribute ChessBoard chessBoard, Model model) {...}
Html will be something like
<form th:action="#{/}" th:object="${chessBoard}" method="post">
<table>
<tr th:each="i: ${board}">
<td th:each="item: ${i}">
<button th:field="*{id}" th:value="${item.id}" th:text="${item.text}"/>
</td>
<tr>
</table>
</form>

How to send Id to Controller from Ajax Input Button

I have this grid which has an edit button. How do I add code to the input button so that the value of the Id is sent to the Controller?
#using (Ajax.BeginForm("EditLineItem", "OrderSummary", new AjaxOptions() { InsertionMode = InsertionMode.Replace, UpdateTargetId = "content" })) {
<div id="summaryGrid">
<table >
<tr>
<th>Report Type</th>
<th>Borrower Name</th>
<th>Property Address</th>
<th>Est Comp Date</th>
<th>Report Price</th>
<th>Exp Fee</th>
<th>Disc.</th>
<th>Total Price</th>
</tr>
#{
foreach (var item in Model) {
<tr>
<td >#item.ReportName</td>
<td >#item.BorrowerName</td>
<td >#item.Address</td>
<td >#item.EstimatedCompletionDate</td>
<td >#item.ReportPrice</td>
<td >#item.ExpediteFee</td>
<td >#item.Discount</td>
<td >#item.TotalPrice</td>
<td >#item.Id</td>
<td ><input type="submit" value="Edit" /></td>
</tr>
}
}
</table>
</div>
}
just put a name on your input button.
<input type="submit" name="id" value="edit" />
Then on your action, you should be able to get the value for id.
If you want more complexity then you are going to have to rethink the way you are doing it. Most likely by writing your own JQuery methods.
$('input.edit').on('click', function (evt) {
evt.preventDefault();
var values = $(this).data();
$.post($(this).attr('href'), values, function (result) { /*do something*/ });
});
Html :
<a href="/edit/1" class="edit" type="submit" data-id="1" data-method="edit" />
That's a start, but you could probably tweak it to fit your needs. At that point, you don't need to wrap the whole table with the Ajax.BeginForm.
To add to Khalid's answer: I tested with this form:
<form method="get">
<input type="submit" name="Id1" value="Edit" id="id1" />
<input type="submit" name="Id2" value="Edit" id="id2" />
<input type="submit" name="Id3" value="Edit" id="id3" />
</form>
The post looks like this when clicking on the third button:
http://localhost:34605/HtmlPage.html?Id3=Edit
In other words, the browser passes the name of whichever button is clicked.
This is an example of getting the Id in the controller:
if (Request.QueryString.HasKeys()) {
string key = Request.QueryString.GetKey(0);
int id;
int.TryParse(key.Substring(2, 1), out id);
Response.Write("You selected id: " + id);
}
I have since found an even easier way of doing this:
Use the <button> element instead of <input>
With <button> you can do this:
<button type="submit" value="#item.Id" name="id">Edit</button>
and then in the controller, all you need is this:
public ActionResult EditLineItem(int id)
{ //Do something with id}
Note that this does not work with IE6.

grails select is not rendering value

I want to make a select box in grails. I am using 2.1.0. I have a view page which shows a select box named class. But it does not shows any value. The list I have used in the from attribute of select works fine is browser when I render it as json. Can anyone make my combo box work for me please ? Here is my code below :
my view page >>>
<g:form controller="admistratorAction" action="addStudent">
<table class="centerTable">
<div class="height"></div>
<tr>
<td><label>Full Name :</label></td>
<td><g:textField name="fullname" id="fullname" class="field"/></td>
</tr>
<tr>
<td> <label>Admission Class :</label></td>
<td><g:select name="class" id="class" class="field" from="${classList}" noSelection="['':'-Choose a class-']"/></td>
</tr>
<td colspan="2" align="right"><g:submitButton name="createSubmit" value="Create" class="button" onclick="return confirm('Are you sure???')"/></td>
</tr>
</table>
</g:form>
here is my controller >>
package administrator
import common.classes.Classes
import grails.converters.JSON
class AdmistratorActionController {
def addStudent = {
render "add student"
}
def classList = {
def classes = Classes.executeQuery("SELECT c.classes FROM Classes c")
def all_class = [classes : classes]
render all_class as JSON
}
}
You do not need to convert it to JSON in order to have it in gsp page
class AdmistratorActionController {
def addStudent = {
def n = params.fullName
def c = params.class
// do something with them
}
def classList = {
def classes = Classes.list()
// pass details to view 'classList'
[classList : classes]
}
}
Create -> views/administratorAction/classList.gsp
have you form ready and you will be able to get ${classList} in it

Passing data from GSP to a controller in Grails

I create a GSP page with controls depending on the rows in a database.
This depends on the value returned by the <g:each in="${Vehicles}" var="vehicle">
So, if there are 3 vehicles, 3 rows with text boxes will be generated. (The maximum can be 200)
<g:form action="update" >
<label for="SearchTerm">${term}</label>
<g:each in="${Vehicles}" var="vehicle">
<tr>
<td> <label for="Name">${vehicle.name}</label> </td>
<td><g:textField name="${vehicle.id}.ModelNo" /> </td>
<td><g:textField name="${vehicle.id}.Year" /> </td>
</tr>
</g:each>
<td> <g:submitButton name="update" value="Update"/></td>
</g:form>
How can I basically pass this value to my controller so that I can then save/update the data to the database. or Is there any easy way to achieve this scenario?
You need some code like this in the GSP
<g:form action="update" >
<label for="SearchTerm">${term}</label>
<g:each in="${Vehicles}" var="vehicle" status="i">
<tr>
<td> <label for="Name">${vehicle.name}</label> </td>
<td><g:hiddenField name="vehicle[${i}].id" value="${vehicle.id}"/>
<g:textField name="vehicle[${i}].ModelNo" value="${vehicle.ModelNo}"/> </td>
<td><g:textField name="vehicle[${i}].Year" value="${vehicle.Year}"/> </td>
</tr>
</g:each>
<td> <g:submitButton name="update" value="Update"/></td>
</g:form>
The Controller needs to either have a Domain with a List Property or a Command Object with a List Property ie
SearchCommand {
List<Vehicle> vehicle = new Arraylist<Vehicle>(3);
}
Then in the controller (if using the command object)
def save = {SearchCommand searchCmd->
searchCmd.vehicle.each {vehicle ->
/* Process Vehicle */
}
}
Hope that Helps
You need to use the request object from your controller. If you can generate the names of the controls you need to access do something like the following
idList.each {
theYear=request.getParameter(it+Year)
}
If you want a list of all your generated form fields use something like
java.util.Enumeration theFields=request.getParameterNames()
theFields.each {
//look at your field name and take appropriate action
}
For more info on the request object see this

binding asp.net mvc form element to complex object for posting to controller

I am trying to refactor to avoid parsing the FormCollection from the view so i changed this to pass in an strongly typed object. My form elements are the same names as the properties on the LinkUpdater Object. But when i put a breakpoint on the first link in the controller all of the properties are null.
any ideas or suggestions?
View:
<%using (Ajax.BeginForm("AddNewLink", "Links", new AjaxOptions { UpdateTargetId = "LinkList", LoadingElementId = "updating", OnSuccess = "done" }))
{ %>
<fieldset style="text-align:left">
<table>
<tr><td>Url:</td><td> <input style="width:500px" type="text" name="URL" /></td></tr>
<tr><td>Description: </td><td><input style="width:400px" type="text" name="Description" /></td></tr>
<tr><td>Tags: </td><td><input style="width:400px" id="Tags" name="tags" type="text" /></td></tr>
<tr><td><input type="submit" value="Add Link" name="submit" /></td></tr>
</table>
</fieldset>
<% } %>
Controller Post:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddNewLink(LinkUpdater linkUpdater_)
{
string[] tags = linkUpdater_.Tags.Replace(" ", "").Split(',');
linkRepository.AddLink(linkUpdater_.URL, linkUpdater_.Description, tags);
.....
}
LinkUpdater class:
public class LinkUpdater
{
public string URL;
public string Description;
public string Tags;
}
Model binder in MVC binds to properties, while you use fields. Change to
public string URL { get; set; }
And by the way, there're other drawbacks, like if you use private set, it will silently skip binding, too.
Is there any particular reason your are not using the strongly-typed HTMLHelpers to render your input fields?
<%using (Ajax.BeginForm("AddNewLink", "Links", new AjaxOptions { UpdateTargetId = "LinkList", LoadingElementId = "updating", OnSuccess = "done" }))
{ %>
<fieldset style="text-align: left">
<table>
<tr>
<td>
Url:
</td>
<td>
<%=Html.TextBox("URL", Model.URL, new { style = "width:500px;" }) %>
</td>
</tr>
<tr>
<td>
Description:
</td>
<td>
<%=Html.TextBox("Description", Model.Description, new { style = "width:400px;" }) %>
</td>
</tr>
<tr>
<td>
Tags:
</td>
<td>
<%=Html.TextBox("Tags", Model.Tags, new { style = "width:400px;" }) %>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Add Link" name="submit" />
</td>
</tr>
</table>
</fieldset>
<% } %>
I'm not sure it will fix your problem, but it's a step in the right direction at least.

Resources