Skip to content

Instantly share code, notes, and snippets.

@cdeszaq
Created February 7, 2013 19:40
Show Gist options
  • Save cdeszaq/4733549 to your computer and use it in GitHub Desktop.
Save cdeszaq/4733549 to your computer and use it in GitHub Desktop.
Example of how to have multiple child elements created from a single view. Of note, the `RequestedPeersCommand` object is the part that lets n People be selected to request peer evaluations from.
<%@ page import="edu.wisc.radiology.performanceevaluations.Score" %>
<p>Please enter the people you would like to request a Peer Evaluation from for <strong>${performanceReview.employee}</strong>:</p>
<g:each in="${0..2}">
<div class="control-group">
<label class="control-label" for="people[${it}].id">Peer</label>
<div class="controls">
%{--TODO: Use Select2 (http://ivaynberg.github.com/select2/index.html)--}%
<g:select name="people[$it].id" from="${possiblePeers}" optionKey="id" noSelection="['':'Please select']" />
</div>
</div>
</g:each>
<p>
In order for this to be a complete review, <em>please think carefully about peer evaluations</em>. Individuals who work closely with
this person would be the best selection. <strong>Please request at least 3 peer evaluators</strong>.
</p>
$(document).ready(function(){
// *** Request Peer Evaluations ***
// Remove the modal dialogue when it closes so that content re-loads
// See: http://stackoverflow.com/a/12287169/20770
$('#requestPeerEvaluationsModal').on('hidden', function () {
$(this).removeData('modal');
});
// Attach the peer request submission handler
$("#requestPeerEvaluationsModal form").submit(function(e) {
e.preventDefault();
var method = this.method;
var action = this.action;
var data = $(this).serialize();
$.ajax({
type: method,
url: action,
data: data,
success: function(data) {
// Replace the table
$("#evaluationList").replaceWith(data);
// Trigger timed fade
initiateTimedFade(2000)
// Close the modal
$("#requestPeerEvaluationsModal").modal('hide');
},
error: function(data) {
alert("Failed to request peer evaluations.");
}
});
});
// Attach the add more peers handler
// TODO: Use this
$("#requestPeerEvaluationsModal .addMore").click(function(e) {
e.preventDefault();
var peerList = $("#requestPeerEvaluationsModal .modal-body");
var kids = peerList.children("div");
var nextId = "people[" + kids.size() + "].id";
var clone = kids.last().clone();
// Update the id in the clone
$(clone).find("label")
.attr("for", nextId);
$(clone).find("select")
.attr("name", nextId)
.attr("id", nextId);
// Put it before the comment at the bottom
kids.last().after(clone);
});
});
package edu.wisc.radiology.performanceevaluations
import grails.converters.JSON
import grails.converters.XML
import grails.plugins.springsecurity.Secured
import grails.validation.Validateable
@Secured("hasRole('ROLE_USER')")
class RequestPeerEvaluationController {
def springSecurityService
def requestPeerEvaluationService
def performanceReviewStatusGateService
// Dangerous actions are limited to dangerous methods that make sense for that action
static allowedMethods = [
save: ["POST"]
]
// Return a page for requesting new peer evaluations
def create() {
withPerformanceReview { PerformanceReview performanceReviewInstance ->
// TODO: Gate Me
def possiblePeers = requestPeerEvaluationService.getPossiblePeers(performanceReviewInstance)
def model = [
performanceReview: performanceReviewInstance,
possiblePeers: possiblePeers
]
render(template:"requestPeerEvaluationsTemplate", model: model)
}
}
// Create a new peer evaluation requests from the request data
def save(RequestedPeersCommand requestedPeers) {
withPerformanceReview { PerformanceReview performanceReviewInstance ->
// TODO: Gate Me
requestedPeers.people.each {
requestPeerEvaluationService.requestPeerEvaluation(it, performanceReviewInstance)
}
def message = 'Peer evaluations requested'
def messageType = "success"
// Respond successfully
withFormat {
html {
render(template:"/performanceReview/evaluationListTemplate", model: [message: message, messageType: messageType, performanceReview: performanceReviewInstance])
}
}
}
}
// Must be public so that controller-specific actions can reach it. It can't do anything nefarious though, so it's OK.
// Methods can't have default parameters but closures can...
private withPerformanceReview = { id = "id", Closure c ->
def performanceReviewInstance = PerformanceReview.get(params[id])
if (!performanceReviewInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'performanceReview.label', default: 'PerformanceReview'), params.id])
response.status = 404
withFormat {
// Browsers get helpful 404 content (the list), the others just get the error message
html { forward(action: "list") }
json { render flash as JSON }
xml { render flash as XML }
}
} else {
c.call performanceReviewInstance
}
}
}
@Validateable
class RequestedPeersCommand {
Collection<Person> people = [].withDefault { new Person() }
}
package edu.wisc.radiology.performanceevaluations
import org.joda.time.LocalDate
class RequestPeerEvaluationService {
def mailService
def springSecurityService
boolean requestPeerEvaluation(Person peer, PerformanceReview performanceReview) {
// TODO: Gate me properly
if (!peer.id || PerformanceReviewPeer.countByPerformanceReviewAndPerson(performanceReview,peer) > 0) {
return false
}
// Update the performance review's status
performanceReview.performanceReviewStatus = PerformanceReviewStatus.findByName("Open")
if (!performanceReview.save(flush: true)) {
return false
}
PerformanceReviewPeer prp = createPerformanceReviewPeer(peer, performanceReview)
sendPeerEmail(prp)
true
}
private static def createPerformanceReviewPeer(Person peer, PerformanceReview review) {
// TODO: Gate me
PerformanceReviewPeer prp = new PerformanceReviewPeer(person: peer, performanceReview: review)
prp.save(flush: true)
prp
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment