In Grails using GORM, I'd like to retrieve two possible values for a form dropdown. This particular instance is to only have two possible countries in a dropdown. I've set them in my Config.groovy
The GORM statement in this that I've done only returns USA and I'd like to return Canada also - so I have the findAll statement slightly incorrect. Can someone help me?
Country<g:select name="Country" from="${....country.findAllById("100225","100038").sort{it.orderNumber}}" value="otherstuff" class="form-control" required="" aria-labelledby="country-label"/>
Config.groovy:
country.usa=100225
country.canada=100038
Domain class:
class country {
String name
String value
int orderNumber = 0
static constraints = {
name nullable:false, maxSize:50, blank:false
value nullable:false, maxSize:100, blank:false
}
String toString(){
"$name - $value"
}
static mapping = {
table 'country'
cache: 'read-write'
columns{
id column:'id'
name column:'name'
value column:'value'
orderNumber column:'order_number'
}
id generator: 'assigned'
}
}
you should rather use findAllByIdInList(["100225","100038"]).
Also consider not writing such code within the view. Make it part of your model and prepare it in the controller.
Related
i found this and it was very useful to what i want to do, but is there is way to make what in the inList follow the Grails Internationalization
Thanks
i found workaround , i think it may help ..
1. toString()
As you know, the scaffolded screens just output values in selects and dropdowns through the toString() method of the shown object. We can construct each enum with a hardcoded translation and have toString() return that value.
class Product {
enum Status {
AVAILABLE("Beschikbaar"), SOLD_OUT("Uitverkocht")
final String value
Status(String value) {
this.value = value
}
String toString() {
value
}
}
String name
Status status
static constraints = { name blank: false, unique: true }
}
The actual names of the enum now only appear in the generated HTML:
<select name="status" required="" id="status" >
<option value="AVAILABLE" >Beschikbaar</option>
<option value="SOLD_OUT" >Uitverkocht</option>
</select>
2. MessageSourceResolvable
By now you’ll probably understand above hardcoded solution works for just one language, one hardcoded in the enum itself – which will cause problems when in a month from now your application actually needs to support a 2nd language :-) So how do we leverage the fact that we have already have message_XX.properties where we’ve put our other message keys?
Use the underlying Spring framework. Have our enum implement org.springframework.context.MessageSourceResolvable e.g. like this:
enum Status implements org.springframework.context.MessageSourceResolvable {
AVAILABLE, SOLD_OUT
public Object[] getArguments() { [] as Object[] }
public String[] getCodes() { [ name() ] }
public String getDefaultMessage() { "?-" + name() }
}
Now we can provide a value in our messages_nl.properties for each enum we have:
product.label=Product
product.name.label=Naam
product.status.label=Status
AVAILABLE=Beschikbaar
SOLD_OUT=Uitverkocht
using Grails 2.43 currently. I have two domain classes (State and County), and two Select dropdowns for State and County.
Is there a way with a GORM finder to have a dynamic query that will return the specific counties in a state, when that state is selected. Thereby excluding all other counties that are not in the selected State?
Form elements:
<g:select name="locationState" class="form-control" from="${....State.list().sort{it.orderNumber}}">
<g:select name="locationCounty" class="form-control" from="${...State.FindByName(it.orderNumber).counties}">
Here are the example classes:
class State {
static hasMany = [county:County]
String name
String value
int orderNumber = 0
static constraints = {
name nullable:false, maxSize:50, blank:false
value nullable:false, maxSize:100, blank:false
}
String toString(){
"$value"
}
static mapping = {
table 'state'
cache: 'read-write'
columns{
id column:'id'
name column:'name'
value column:'value'
orderNumber column:'order_number'
}
id generator: 'assigned'
}
}
class County {
State state
String county
static constraints = {
state nullable:false
county nullable:false, maxSize:100, blank:false
}
String toString(){
"${state.name} - $county"
}
static mapping = {
table 'county'
cache: 'read-write'
columns{
id column:'id'
county column:'county'
state column:'state_id'
}
id generator: 'assigned'
}
}
It depends on how you've associated your domain classes. If State hasMany County(ies) and/or County belongs to State, you can use the dynamic finders. For example:
// All Counties
County.list()
// All States
State.list()
//All Counties in State Vermont
State.findByName("Vermont").counties
//State for a county
County.findByName("Chittenden").state
If you're trying to make a somewhat dynamic form, you could show your State dropdown first and have the County dropdown inactive until the State is chosen. Then you can make an asynchronous call to get the counties for the State or if the full objects are already loaded, you could just populate the County select box with selectedState.counties.
See GORM Object Relational Mapping: http://grails.org/doc/latest/guide/GORM.html#domainClasses
In Grails - I need to make a controller method that will populate State and County dropdown form fields so that when a State is selected it will fill only that State's counties into the County dropdown.
A colleague told me that's an asynchronous call in Grails, but I'm a novice in Grails and I really don't know what that is or how to start one. Any help would be greatly appreciated.
Here's my code snippets:
using Grails 2.43 currently. I have two domain classes (State and County), and two Select dropdowns for State and County.
Form elements:
<g:select name="locationState" class="form-control" from="${....State.list().sort{it.orderNumber}}">
<g:select name="locationCounty" class="form-control" from="${...State.FindByName(it.orderNumber).counties}">
Here are the example classes:
class State {
static hasMany = [county:County]
String name
String value
int orderNumber = 0
static constraints = {
name nullable:false, maxSize:50, blank:false
value nullable:false, maxSize:100, blank:false
}
String toString(){
"$value"
}
static mapping = {
table 'state'
cache: 'read-write'
columns{
id column:'id'
name column:'name'
value column:'value'
orderNumber column:'order_number'
}
id generator: 'assigned'
}
}
class County {
State state
String county
static constraints = {
state nullable:false
county nullable:false, maxSize:100, blank:false
}
String toString(){
"${state.name} - $county"
}
static mapping = {
table 'county'
cache: 'read-write'
columns{
id column:'id'
county column:'county'
state column:'state_id'
}
id generator: 'assigned'
}
}
The async guide linked in the comments is for make programatic, asynchronous calls. For example, if you had two computationally expensive method calls (or ones that would require network I/O) you can use threads to run them (roughly) in parallel. Grails provides many different helpers to make this kind of asynchronous programming very easy.
However, this is not likely something you need for your GORM queries. You want to populate a second select box. You could accomplish this two ways, by reloading the page after the state is selected, or by using JavaScript to populate the box. I am assuming you want to do the latter. Grails does provide tools (such as the <g:remoteFunction /> tag) to handle this without writing your own JavaScript but the Grails AJAX library has since been deprecated and its use is not recommended.
Instead, you should just write your own JavaScript. I'll show you a technique using jQuery:
In your view, initialize both selects, but the second should be initialized as empty. We are also going to give them IDs to make them easier to select from jQuery:
<g:select name="locationState"
class="form-control"
from="${....State.list().sort{it.orderNumber}}"
id="location-state" />
<g:select name="locationCounty"
class="form-control"
from="${[]}"
id="location-county" />
Then, we will need to expose an action on the controller to load the counties when the user selects a state:
def loadCountiesByState() {
def state = params.state
def counties = State.findByValue(state).counties
render g.select(name: 'locationCounty', class: 'form-control',
from: counties, id: 'location-county')
}
You should be able to test this part just by pointing your browser to /app-name/controller-name/loadCountiesByState?state=CA. I don't know exactly how your data is modeled so you might need to alter the State.findByValue(state) part to fit your needs.
Now we just need to wire up the control with some JavaScript. Make sure you have jQuery included.
<script type="text/javascript">
$(function() {
$('#location-sate').change(function() {
var state = $(this).val();
$.ajax({
url: '/app-name/controller-name/loadCountiesByState',
date: { state: state },
success: function(data) {
$('#location-county').replaceWith(data);
}
});
});
});
</script>
This will replace the dropdown with a new select that should be fully populated with the counties.
This drop down almost works the way I want it too. I'm unable to display the body property or the toString of an answer object.
<g:select name="questionId"
from="${questionInstance.answers.id}"
value="${questionInstance.correctAnswer.id}"
noSelection="['':'Select a Module']" />
unfortunately, no matter what combination I try, I can not get the drop down to, by default, select the correctAnswer without using the id in the from attribute.
<g:select name="questionId"
from="${questionInstance.answers}"
value="${questionInstance.correctAnswer}"
noSelection="['':'Select a Module']" />
what am I doing wrong?
question
class Question {
DateTime dateCreated
DateTime lastUpdated
String body
Answer correctAnswer
Integer ordinal
static belongsTo = [lesson: Lesson]
static hasMany = [answers: Answer]
static constraints = {
body blank: false
correctAnswer nullable: true,
validator: { Answer val, Question obj ->
// Correct answer must have this as it's question
val ? val.question == obj : true // TODO: Give this a proper error message
}
ordinal unique: 'lesson'
}
static mapping = {
lesson lazy: false
answers sort: 'ordinal'
}
}
answer
class Answer {
DateTime dateCreated
DateTime lastUpdated
String body
Integer ordinal
String reason
static belongsTo = [question: Question]
static constraints = {
body blank: false
ordinal unique: 'question'
reason blank: false
}
static mapping = {
question lazy: false
}
String toString() {
"Answer: $body"
}
}
I'd say, this should work:
<g:select name="questionId"
from="${questionInstance.answers}"
value="${questionInstance.correctAnswer}"
optionKey="id"
optionValue="body"
noSelection="['':'Select a Module']" />
Could you provide the domains Questions and Answer?
In the meanwhile try adding attributes optionKey="id" optionValue="name"
provided the Domains have a name property.
Let's say I have the following domains:
class Store {
String name
static hasMany = [ products: StoreProduct ]
}
class Product {
String name
static hasMany = [ stores: StoreProduct ]
}
class StoreProduct {
BigDecimal discount
static belongsTo = [ store: Store, product: Product ]
static mapping = {
id composite: ['store', 'product']
}
In other words, there is a many-to-many relationship between Store and Product with an intermediate StoreProduct domain class to track the individual discount per store.
Grails has built-in support for one-to-many relationships, so you can pass in a list of IDs with the proper field name and the controller will automatically resolve the IDs to a list of entities. However, in this case it's a many-to-many with an intermediate domain class.
I've tried the following code in the Store edit view to allow a user to select a list of products:
<g:each in="${products}" var="product" status="i">
<label class="checkbox">
<input type="checkbox" name="products" value="${product.id}"/>
${product.name}
</label>
</g:each>
But Grails throws various errors depending what I use for the name attribute. I've also tried the following for the input name:
products
products.product
products.product.id
product[0].product
product[0].product.id
But none of them work properly.
My question is, is there any built-in support for this kind of relationship in Grails, particularly when it comes to the view?
Change your domain structure as follows:
class Store {
String name
Set<Product> getProducts() {
StoreProduct.findAllByStore(this)*.product
}
}
class Product {
String name
Set<Store> getStores() {
StoreProduct.findAllByProduct(this)*.store
}
}
import org.apache.commons.lang.builder.HashCodeBuilder
class StoreProduct implements Serializable {
BigDecimal discount
Store store
Product product
static mapping = {
id composite: ['store', 'product']
version false
}
boolean equals(other) {
if (!(other instanceof StoreProduct)) {
return false
}
other.store?.id == store?.id &&
other.product?.id == product?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (store) builder.append(store.id)
if (product) builder.append(product.id)
builder.toHashCode()
}
}
From the domain classes above:-
Either one of the domain (Store or Product) has to take the onus of the relationship by having a belongsTo. Refer API for details.
Domain class (StoreProduct) with composite primary key should implement Serializable.
Please also provide a stacktrace to debug if available.