I have just entered into the Grails arena.
I have a requirement where I want to put one drop down and one button on one page, and by clicking on button only that drop down values should be changed, other controls on the page should remain unchanged.
My code is as follows :
_connType.gsp
<div id="mappedDeviceDiv">
<select id="mappedDevice" name="mappedDevice" value="" style="width:200px">
<g:each in="${deviceList}" status="i" var="dl">
<option value="${dl}">${dl}</option>
</g:each>
</select>
<g:submitToRemote class="blackButton" update="mappedDeviceDiv"
url="${[controller:'resource',action:'getDeviceList']}"
value="Get Devices"/>
</div>
ResourceController.groovy
def getDeviceList = {
println "Getting NV devices.. + Nirmal" + params
def model = buildAccessRequestModel()
List<NVDeviceBean> deviceList = NVUtil.getDevices(params.datasource, null);
Collections.sort(deviceList);
List<String> devices = []
for(NVDeviceBean deviceBean : deviceList) {
devices.add(deviceBean.getName())
}
println "list = "+devices
model.putAt('deviceList', devices)
render (template:'config/connType',model:model)
}
So, in above scenario, it's setting the values in the devices perfectly, but at the view side in a drop down m getting whole connType page, instead of only list values which is in devices variable of controller.
Any help would be highly appreciated..
You might want to create/modify one of the controller actions to return a list of HTML options. You could even have this action render a template, too.
def getDeviceOptions = {
def options = []
// code that creates the option list goes here.
render(template:'config/optionList', model: [optionList: options ])
}
And the template...
<!-- config/_optionList.gsp -->
<g:each in="${optionList}" status="i" var="dl">
<option value="${dl}">${dl}</option>
</g:each>
Then, tell the g:submitToRemote tag to update the select object.
<g:submitToRemote class="blackButton" update="mappedDevice"
url="${[controller:'resource',action:'getDeviceOptions']}"
value="Get Devices"/>
That should get you started in the right direction.
Related
Dear grails specialists
I'm sending a list of publications to my gsp view page. I can see the list well, but after adding one of the publications into the books list and rendering the publications gsp view page, the publications list is not seen as a list of publications but as a String. So when I try to get each publication it gives me the chars.
I am using the version of grails 2.2.0.
Here i send publications in controller Entries:
def books{
def unit = Unit.get(params.id)
def period = Period.get(params.periodId)
def publications = []
if (unit) {
def units = unit.downHierarchy().id
units.removeAll { null }
publications = Publication.publicationsOfUnits(units)?.listDistinct()?.findAll{it.date.getAt(Calendar.YEAR) == period.year}?.sort{ it.date }
}
[publications : publications, id: unit.id, unitId: unit.id, periodId: period.id]
}
and here is my view page:
<table>
<g:each in="${publications}" var="p">
<g:if test="${p instanceof publicationBook}">
<tr>
<td>${p.authors.join(",")}</td>
<td>${p.title}</td>
<td>
Add to Books
</td>
</tr>
</g:if>
</g:each>
</g:table>
here i add the publication to books:
def saveBook = {
saveEntry("book", new Book())
render(view:"books", model: params)
}
and here is the book Form where I send the list of publications again to controller for rendering:
<g:form name="bookForm" controller="entries" action="saveBook" class="default" method="post">
<g:hiddenField name="entryId" value="${entry?.id}"/>
<g:hiddenField name="unitId" value="${unitId}"/>
<g:hiddenField name="periodId" value="${periodId}"/>
<g:hiddenField name="publications" value="${publications}"/>
<div class="buttons">
<button class="button icon icon_arrow_right leave_empty" onclick="$('#leaveEmpty').val('true');bookForm.submit();"
</div>
</g:form>
I would very appreciate any advise or help to solve the problem..
You are NOT passing the proper model here render(view:"books", model: params).
Either use redirect(action:"books", id: id), or fill the model with the publications list etc., as you are doing in the books action
In my controller I have conditions, for example if value is 80, then I need to show certain button in my view, if value is 50 then I need to show a different button in my view. How would I do this in grails?
Its seem not to be a controller logic. You can just in the view do something like:
<g:if test="${val == 80}">
<input type="submit" value="Submit">
</g:if>
<g:else>
<input type="button" value="a button">
</g:else>
If you want to send val from the controller to the view, its something like:
class TestController {
def index = {
['val':80] //or [val: params.val] if you want to get it from parameters.
}
}
If you want to do this on the same page, you need javascript.
If you want to render page according condition, try <g:if> tag
I feel a better way to do this is to use a tag library rather than having logic in your .gsp. Also you can reuse this logic if it is needed elsewhere in your application.
// in your gsp
<lib:showButtons myValue="$val"/>
// in your tag lib
def showButtons = { attrs ->
def myValue = attrs.myValue
def value = "Submit"
def type = "submit"
if(myValue != 80) {
value = "a button"
type = "button"
}
out << '<input type="$type" value="$value" />'
}
Trying to populate a g:select from a function in my controller, is it possible?
Currently we have this:
def run(Long id) {
def reportInstance = Report.get(id)
def listPromptValues = populatePrompts(reportInstance)*.values()
if (!reportInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'report.label', default: 'Report'), id])
return
}
[reportInstance: reportInstance, listPromptValues: listPromptValues]
}
def populatePrompts(Report rp){
//for each prompt in the report, go out and get it's values
rp.prompts.collectMany {
reportService.listDatatypeValues(it.datatype)
}
}
And then the g:select in question is
<li class="fieldcontain">
<g:each var="prompt" in="${reportInstance.prompts}">
<span id="prompts-label" class="property-label">
<g:message code="report.prompts.label" default="${prompt.name}:" />
</span>
<g:if test="${prompt.datatype.type == 'DropDown'}">
<g:select id="prompt.name" from="${listPromptValues}" name="prompt.name" value="" noSelection="['':'']"/>
<br>
</g:if>
</g:each>
</li>
Which works just fine if there is only one prompt, however we need to be able to call the populatePrompt function directly from the gsp view if there is more than one prompt in the loop, possible sending the reportId and then getting back the listPromptValues. I can't seem to get the onChange(remoteFunction...) to work properly and am coming up empty handed in searching the vast Google webs.
Something like how createLink works
${createLink(controller:'report', action:'runReport', id:"${reportInstance.id}")}
But instead of createLink, it would be the from attribute of the select tag, something like:
<g:select id="prompt.name" from="{(controller:'report',action:'populatePrompt', id:"${reportInstance.id}")}" name="prompt.name" value="" noSelection="['':'']"/>
Any ideas, or direction to go?
I think #JamesKleeh proposed a viable solution in his last comment.
Given the fact that your gsp structure is quite static, it doesn't make sense to fetch the prompt select options to be dynamically loaded. Just return these options in a List package within listPromptValues from your controller and take it in the gsp directly.
Concerning your parameters like [prompt1: ['a','b','c'], prompt2: ['d','e','f']], you can get this map in your populatePrompts method and put each key-value pair into gsp select tags. Like this:
controller
{ ....
def listPromptValues = populatePrompts(reportInstance)
....
}
def populatePrompts(Report rp){
//for each prompt in the report, go out and get it's values
def promptMap = [:] //map to be returned
rp.prompts.each {
promptMap.put(it.name, reportService.listDatatypeValues(it.datatype))
}
return promptMap
}
gsp
<g:each var="prompt" in="${reportInstance.prompts}">
<span id="prompts-label" class="property-label">
<g:message code="report.prompts.label" default="${prompt.name}:" />
</span>
<g:if test="${prompt.datatype.type == 'DropDown'}">
<g:select id="prompt.name" from="${listPromptValues[prompt.name]}" name="prompt.name" value="" noSelection="['':'']"/>
<br>
</g:if>
</g:each>
Quiz project, a question has a radiobuttonlist with either 2 items(T/F) or 4 items (a,b,c,d)
number of questions varies. Panel is used to show only one question at a time (show/hide).
after answering all questions user clicks on submit button and all answers should be saved in database. In code behind selecteditem is always null and value is always empty string.
<asp:DataList ID="dtQuestion" runat="server" RepeatDirection="Vertical" OnItemDataBound="FormatDataListRow" >
<ItemTemplate>
<asp:Panel id="panel" runat="server" BorderColor="#536895" BorderStyle="Solid" BorderWidth="1" style="display: none;" EnableViewState="true">
<asp:Label id="lblQuestionDesc" runat="server" Text="" ></asp:Label>
<asp:RadioButtonList id="rbl" runat="server" EnableViewState="true" > </asp:RadioButtonList>
</asp:Panel>
</ItemTemplate>
</asp:DataList>
on submit click. I call a function that search the page for RBL I am able to see their correct ID's and list items but nothing is selected.
string id;
if (c.GetType().ToString().Equals("System.Web.UI.WebControls.RadioButtonList"))
{
if (c.ID != "rbl")
{
id = c.ID;
al.Add(id + "," + ((RadioButtonList)c).SelectedItem.Value); //SelectedValue); //
}
}
It seems that you're populating the RadioButtonList on the page load -
If so - make sure you surround your population of the RadioButtonList with an
If/Then/Postback block:
if not Page.IsPostBack then
' populate your RBL
end if
eg:
if (!IsPostBack)
{
loadradiobuttonlist();
}
Try accessing the submitted value like this:
this.Request.Form[((RadioButtonList)c).UniqueID]
During debugging you can always check what values you've got in this.Request.Form collection.
I am using the webflow plugin for Grails for the first time and am having some difficulties.
To summarize, once within the Webflow, no information appears to be returning to the controller from the form. All examples that I have looked at indicate that the params are returned to the controller action normally and then you can put objects into the flow scope as necessary. Unfortunately, the illustrated printlns are both outputting null, and any programatic output of the params shows that the expected 'testField1' and 'testField2' are not in the params object. Excuse the non-uniform text boxes and ways of submitting - they were the result of experimentation.
A simplified version of the controller action flow:
def generateProductVariantsFlow = {
start() {
action {
[productInstance:Product.get(params.id)] //the entry params contains the expected id
}
on ("success").to("selectAttributeValues")
}
selectAttributeValues() {
on("next"){TestCommand tc -> //params does not have testField1 or testField2
println "TEST COMMAND"
println "${tc.testField1}"
println "${tc.testField2}"
}.to("selectProductVariants")
on("cancel").to("finishBeforeStart")
}
selectProductVariants {
on("cancel").to("finish")
on("previous").to("selectAttributeValues")
on("next").to("confirmNewVariants")
}
//other states here
finish {
redirect(action:"list")
}
finishBeforeStart { //somewhat misleading state name, but shouldn't be relevant
redirect(controller:"product",action:"show")
}
}
The GSP and Command are equally simple -
selectAttributeValues GSP:
<%# page import="com.castaway.rigging.Product" %>
<g:form action="generateProductVariants">
<input type="integer" id="testField1" name="testField1" value="test1" />
<g:textField name="testField2" value="test2"/>
<div class="buttons">
<span class="button"><g:actionSubmit class="cancel" name="cancel" value="Cancel"/></span>
<g:link action="generateProductVariants" event="next" >Next</g:link>
</div>
</g:form>
</div>
</body>
Command:
class TestCommand implements Serializable {
def testField1
def testField2
}
Why do you use a link instead of a submit button to trigger the next event?
Clicking that link will do a GET request which will not include the form fields.
You need to use a submit button to trigger the next event.
cheers
Lee