How to conditionally disable a form input field - grails

Say I have a Domain object Teacher with two fields String name, TeacherType teacherType, where TeacherType is an enum containing AssitantProfessor, AssociateProfessor, Professor.
After I generate the views using grails run-target generate-all Teacher, it produces an _form.gsp that is used for both create and edit of Teacher. In the edit view I want only the name to be editable but the TeacherType to be unmodifiable once created (this is just an example, it is a requirement that certain fields can't be updated after creation). In the create view, both TeacherType and name should be editable.
Since both create.gsp and edit.gsp render the _form template, what is the preferred approach here?
Create two separate templates i.e. _formCreate.gsp , _formEdit.gsp; Or
Pass in a model map within create.gsp and edit.gsp and use them in _form.gsp to conditionally render the view?
e.g.
In create.gsp:
<fieldset class="form">
<g:render template="form" model="[teacherInstance: teacherInstance, 'mode':'create']"/>
</fieldset>
In edit.gsp
<fieldset class="form">
<g:render template="form" model="[teacherInstance: teacherInstance, 'mode':'edit']"/>
</fieldset>
In _form.gsp
<g:if test="${mode == 'edit'}">
<g:select name="teacherType" from="${TeacherType?.values()}" keys="${TeacherType.values()*.name()}" required="" value="${teacherInstance?.teacherType?.name()}" disabled="disabled"/>
</g:if>
<g:else>
<g:select name="teacherType" from="${TeacherType?.values()}" keys="${TeacherType.values()*.name()}" required="" value="${teacherInstance?.teacherType?.name()}" disabled="false"/>
</g:else>
Approach 2 works but I suppose if the number of conditional statements increase it may just be better to follow approach 1 and split the forms.
Is there another approach that I'm not aware of?

The disabled attribute of <g:select> (and many other <g:...> form field tags) can be a boolean-valued expression:
<g:select name="teacherType" from="${TeacherType?.values()}"
keys="${TeacherType.values()*.name()}" required=""
value="${teacherInstance?.teacherType?.name()}"
disabled="${mode == 'edit'}"/>
This will render as disabled="disabled" if the expression evaluates to true, and as the absence of a disabled attribute (i.e. the field will not be disabled) if the expression is false. You could even use a boolean entry in the model, e.g. render the template with
model="[teacherInstance: teacherInstance, editing:true]"
(or editing:false respectively) and then say disabled="${editing}" on the <g:select>.

Related

html helper - how do I get rid of the name attribute?

I have a strongly typed partial view. The model has a property that is a list of users in Active Directory represented by a class called ADUser.
I have a partial view that represents a drop down list for this property. While I use the value of this drop list for some other things, I have no need to submit its value, so I thought I would remove the name attribute. However, once the Html loads, the name attribute is always set to what the Html helper wants to assign it. Is there a way I can remove that attribute so that the drop down's value doesn't submit?
In my main partial view (_adusers is the name of the list):
<%: Html.Partial("ADUserDropDown", Model._adusers)%>
In my drop down's partial view:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<MyProject.Models.ADUser>>" %>
<%= Html.DropDownList("", new SelectList(Model, "ValueText", "DisplayText"), new { name = "", size = "12" })%>
<input type=button value="Search..." />
<input type=button value="Close" />
This results in:
<select name="_master" size="12">
_master being the name of the parent model. If I add something to the first parameter of Html.DropDownList, it results in:
<select name="_master.WhateverINamedIt" size="12">
I want to achieve:
<select size="12">
There is no point of using the HTML helper then. You can change the code of the partial view to:
<select size="12">
#foreach(var item in Model)
{
<option value="#item.ValueText">#Html.DisplayFor(m => item.DisplayText)</option>
}
</select>
However if you want to stick with the DropDownList helper the name parameter in the html attributes has to be specified with the capital letter:
<%= Html.DropDownList("", new SelectList(Model, "ValueText", "DisplayText"),
new { Name = string.Empty, size = "12" })%>
As an alternative you can remove the name with jQuery:
$('[name="_master.WhateverINamedIt"]').removeAttr('name');
Don't like or use jQuery, the plain javascript will do the job:
document.getElementsByName('_master.WhateverINamedIt')[0].removeAttribute('name');

displaying bean class items on view - beginner

The bean class looks like this:
String houseNo
String address
Person person
The view looks like this
<g:form action="save">
<fieldset class="form">
<g:render template="form" />
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save"
value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
According to my knowledge in Grails, i think is <g:render template="form" /> will pull all form attributes and display it.
But what i want to do is Instead of displaying a drop-down for Person, i want to display all Person related fields like personName, personAge. How can i display these fields in a label underneath ?
Help
You're correct about the way g:render works, the template part refers to a GSP which will look through the bean values and print them according to the html + groovy markup in "_form.gsp" (located in your views folder under the controller name).
To change the way the Person domain object is displayed, simply edit this "_form.gsp" and take out the 'select' html code - replacing it with groovy markup using the property values of the bean, eg.
${beanName.person.personName} //(use the existing code to help workout the bean name etc)
Hopefully that helps you on your way.

Render selectManyCheckbox without HTML table

is there a way to remove the table out of rendered html that is created by the h:selectManyCheckbox tag in server faces?
I am using twitter bootstrap and i placed the checkboxes inside a dropdown menu:
<ul class="dropdown-menu dropdown-menu-form">
<li><label class="checkbox"> <input type="checkbox" />
Activated
</label></li>
<li><label class="checkbox"> <input type="checkbox" />
Deactivated
</label></li>
</ul>
So the generated html table destroys the layout ...
You could just render a bunch of <h:outputLabel><h:selectBooleanCheckbox> inside <ui:repeat>. This way you've markup freedom. You'll only need to alter the model from e.g. List<T> to Map<T, Boolean> to represent the checked values and then loop over the map afterwards to collect checked ones.
A ready-to-use component is Tomahawk's <t:selectManyCheckbox> which has an additional layout attribute value of spread.

Updating many instances in one view

I'm starting with Grails and I don't know how should I face the following use case.
The app is about sports results prediction, so I have in my domain "Match" and "Prediction", and I want to have one view where the user can update all the predictions of matches that haven't been played yet.
So far I've defined a method in my "PredictionController" that searches all the already existing predictions of games that have to be played and generates new Prediction instances for any new Match with a date higher than now. I've created a view for that method and I'm getting correctly all the predictions that I should complete or update, and I've defined in my controller another method for the form sumbission (so I'm trying to resolve this in the same way that the 'create' and 'update' scaffolded methods work).
My question is, How can I access to all the Predictions modified by my view? How can I send all the predictions to my update method? Is it defining a hidden field with a variable containing all the collection?
This is the form in my GSP view:
<g:form action="savePredicctions">
<fieldset>
<g:each in="${predictions}">
<li>
<div>
${it.match.homeTeam}
<g:field name="${it.match}.homeGoals" type="number" value="${it.homeGoals}" />
</div>
-
<div>
<g:field name="${it.match}.awayGoals" type="number" value="${it.awayGoals}" />
${it.match.awayTeam}
</div>
</li>
</g:each>
</fieldset>
<fieldset class="submit">
<g:submitButton />
</fieldset>
</g:form>
You can use a command object to store the instances of Prediction.
#Validateable
class PredictionCommand {
//data binding needs a non-null attribute, so we use ListUtils.lazyList
List<Prediction> predictions = ListUtils.lazyList([], FactoryUtils.instantiateFactory(Prediction))
}
In your view, you need to control the index of your list, and send the attributes of Prediction to the controller:
<g:each in="${predictions}" status="i">
<g:textField name="predictions[$i].homeGoals" />
<g:textField name="predictions[$i].awayGoals" />
</g:each>
And in your controller you can use bindData() to bind params to your command:
class CommandController {
def save() {
PredictionCommand command = new PredictionCommand()
bindData(command, params)
println command.predictions
}
}

ASP.Net MVC 2 - How to stop the view from using prefixes on fields?

ASP.Net Html.TextBoxFor (and the other XxxxxFor editor helper methods) default to rendering a field prefix. How do I disable field prefixes so it simply renders the property name as the Name/ID?
Here's an example:
<%= Html.EditorFor(m => chart.Title) %>
is rendered as:
<input id="Chart_Title" name="Chart.Title" type="text" value="">
I would prefer it to be rendered as:
<input id="Title" name="Title" type="text" value="">
There's a parameter in an overload of EditorFor called htmlFieldName. Specify your name here.
The helpers take whatever you give it. So you need to pass in just the "Title" portion of the variable; maybe try assigning title to a variable, and use Html.EditorFor for that Title variable, and that might give you a different response.
The reason it does that is the helpers are setup to reflect from the Model context, so typically you may see Model.Chart.Title, and as such, the helpers create this path in the name so it can post the entire model back to the action method, if it needed to.
HTH.

Resources