Grails: Supplying Data to a Global UI Element - grails

Please pardon this newbie question...
In Grails, if I want a partial to be embedded in a layout so that it appears globally, which requires live data, let's say a list of categories, where is the best place to pull the category data to feed it into the view?
I realize this is a very basic question, but I haven't seen this covered in any tutorials yet.

I started this as a comment to Bill James's answer but I figured it might be longer. Bill suggeseted using groovy code inside ${} to make the template (called partial in Rails) work globally:
<g:each in="${ Category.findAll() }" var="cat" />
But, you should not just add code if you dont feel like it might mess up your tidy xml/html. You can always put it in a closure inside a TagLib and thus make it a Tag. The closure must have no parameters, or an 'attr' parameter, or an 'attr' and 'body' parameters but other signatures are invalid.
class CustomTagLib {
static namespace = 'cus'
def categories = { attr, body ->
g.each( in: Category.findAll(), var: attr?.var ?: 'categories' )
}
}
Then you can use that tag into the template with the namespace you chose:
<cus:categories />
Personally I prefer using tags since most of the time it is a reusable code, so it's better for not violating the DRY principle.

You want to put it in grails-app\views\layouts\main.gsp. That's the default layout that most generated code (and likely most examples that you'll see) will use.
Check out the sitemesh section of the grails documentation.

I think you're trying to ask... "How do I feed the category data to the view when I don't know which action caused the page to render, so the action can't add the data to the model?" If that's so, you can use Groovy code directly in the ${} block, such as:
<g:each in="${ Category.findAll() }" var="cat" />
Note that findAll is added to every Model class, and can be called statically (via the classname, not an instance).
Hope this helps

Related

Customize fieldset output from form collection in ZF2

I have correctly set up a form in ZF2, which includes several elements and a collection containing a fieldset that can be duplicated by the user. All works fine, but I need more control on how the fieldset renders, ie. I need to add other things between some elements in the fieldset, rather than just output them one after another.
I'm not expert in ZF2, but from research I seem to understand that you can declare a custom fieldsetHelper in the formCollection, however:
I can't manage to do so; I tried to extend the FormCollection class, and adding protected $fieldsetHelper = 'myFieldsetHelper';, which is also declared in the module config, but I get:
Fatal error: Call to undefined function myFieldsetHelper()
I'm familiar with extending FormRow helper, but I don't know how the fieldset helper should be written (I only need to add my extra stuff between some elements), and can't find any example on the web.
Any help, please?
You can use other view helpers to customize the forms layout in your view script such as FormLabel, FormText, etc.
Please see my answer here
EDIT
You can also loop through all the collection elements in your view script and render separately.
<?php
foreach ($this->form->get('collection') as $fieldset) {
echo $this->formText($fieldset->get('elementName'));
}
?>

Play Framework - Variables in URL instead of as ? parameters

I'm a just starting to learn Play, so this is a basic question, but I've searched every term I can think of and can't find the answer.
All I want to do is have a page that on submit takes an ID from a text field and puts it in the URL directly (e.g. /myservice/person/123). Instead, the URL being generated contains the ID as a parameter (e.g. /myservice/person?id=123).
I know my controller is being invoked correctly if I type the URL in by hand, so I'm inclined to think my routes file is correct. This is what my entry looks like:
GET /person/:id controllers.PersonActions.getPerson(id: String)
So I'm assuming something is going wrong in my template, which looks like this:
#form(routes.PersonActions.getPerson(personID)) {
#* #inputText(personForm("id")) *#
<input type="text" name="id" value="#personID">
<input type="submit" value="Get">
}
You can see that I've commented out another way using #inputText also, but it behaves identically for me. I'm not tied to either method.
I've also tried this using POST, which removes the ID from the URL entirely, which I don't understand either, but since I'm just doing a simple query, I'd rather use GET.
Can anyone help me understand what's going on here? I feel like there's something fundamental about how routing/URLgeneration works that I'm not understanding, but I've gone through the tutorial and the docs so many times today I'm at a loss.
Thanks in advance.
Oh, and I'm using Java 7, Play 2.1, and Eclipse Kepler
I think you are trying to skip a step and map form request data from a view directly to a controller method. You will need to submit the form, have a controller parse the data and then render the next appropriate view based on the data you parsed from the form.
Remember that the personId in your view is a parameter that is bound server-side when the view is rendered. In this case, the submit url of the form is hard coded to whatever personId is passed in to the view at render time -- it doesn't change dynamically when the input box changes.
To fix, add a controller method to accept requests from /person (I'm guessing this based on the part in your question that says the form is being submitted to /person?id=123, in any case it should be the URL of the form you've shown above)
e.g. if you want to use a GET method for the form add:
GET /person controllers.PersonActions.findPerson(id: String)
and in your PersonActions controller (I'm assuming you're using Java, if scala I'm sure you can adapt it from the docs)
public static Result findPerson(String id){
/*
* I'm assuming this method exists and works because you say
* when you type in /person/123 manually the routing works
* and your router says getPerson is the method name for that URL.
*/
return getPerson(id);
}

How can I pre-populate a hidden form field in grails?

I have just gotten started with Grails and I have a very basic application running. I want to pre-populate a hidden form field with a random string.
What is the best way to do this? I have looked at the taglib but I am not sure what the best practice is for this sort of thing. Should I create a class in the src/java or src/groovy folder or is there a better way to get this done?
Lastly, and I know this is a very basic question, but if I do create a class or taglib, how exactly is that called from within the .gsp page?
Thanks!
If your action looks like this
def create() { [orgInstance: new Org(params)] }
it means that a new Org object is passed to your view which can be referenced as orgInstance
Since the model [orgInstance: new Org(params)] is a map, you can simply add another parameter:
def create() { [orgInstance: new Org(params), hiddenValue: 'something random'] }
This can be used in your .gsp in the following way:
<input type="hidden" name="test" value="${hiddenValue}" />
Regarding your other question: a custom taglib is used in the same way as the other Grails-Tags: <g:myTag ...>...</g:myTag> . You can change the namespacegto whatever you like -g` is the default. See the documentation for more details: http://grails.org/doc/latest/ref/Tag%20Libraries/Usage.html

How do I encapsulate calls to ViewBag or ViewData?

I want to be able to able to register script blocks in the ViewData or ViewBag and then unload them on my layout page at the correct position.
I tried writing a #function {} in my _Layout but this cannot be called from my Views.
So how do I write a class that allows me to do something similar to
#Something.registerscript("myscript.js")
And then on the Layout page
#Something.RenderScripts()
I saw an implementation using the singleton pattern here...
Add CSS or JavaScript files to layout head from views or partial views
But im afraid that will cause problems as this should be dynamic not static!
Is this for a generic solution or do you just want to include scripts files from within your views? For the latter, you can always create a section called "Head" or whatever which is created within the <head>-element.
For example:
_layout.cshtml
<html>
<head>
#RenderSection("Head", false)
</head>
...
</html>
View.cshtml
#section Head
{
<script type="text/javascript">...</script>
}
I wouldn't propose this as an answer, since there is the possiblity that you do want to actually do more than this (as far as I know, this doesn't work with EditorTemplates etc.). But in case you were thinking to complicated, this works very easy.
Why would you use ViewBag for this ? If you want to create something that has request-wide scope, use HttpContext.Current.Items - in your case implement one storing helper method, and one "render everything stored" method.
Viewbag or it's close relative viewdata I'd say are the best collections to use for this, as your context appears to be within the view. Where would you register the script & where would you render it?
You could, I think, write helper extensions to wrap up the register & render side of things. I believe helper methods can access viewdata. You'd get the added bonus of the abstraction away from the actual store you used, as you'd only reference it from these helper methods.

EditorTemplates/Object.cshtml using EditorFor() instead of Editor()?

I am trying to create a generic editor template that replicates Html.EditorForModel(), to later customize and build upon. Brad Wilson's template gets pretty close, but I found that it chokes when the same key exist in both ViewData (or ViewBag) and the model. For example ViewBag.Title causes problems if the view model also has a Title property.
I learned here that using strongly-type helpers (i.e. Html.EditorFor(x => x.Title) instead of Html.Editor("Title") seems to help. So I tried to modify Brad's template, but I ran into a brick wall, as nothing I tried so far has worked. I can't figure out how to use strongly-typed helpers in a context where I don't know the model type, like an editor template for example.
Is there any way to create an Object template like Brad's, but using strongly-typed helpers (i.e. LabelFor, EditorFor, ValidatorMessageFor) instead of weakly-typed ones (i.e. Label, Editor, ValidatorMessage)?
Thanks.
I solved this problem in a slightly roundabout way, by removing the ViewData right before the call to #Html.Editor and then putting it back after.
Object.cshtml:
object oldViewData = null;
var hasConflictingViewData = ViewData.TryGetValue(prop.PropertyName, out oldViewData);
if (hasConflictingViewData)
{
ViewData.Remove(prop.PropertyName);
}
#Html.Editor(prop.PropertyName)
if (hasConflictingViewData)
{
ViewData.Add(prop.PropertyName, oldViewData);
}
The only other option I could think of is using a ton of reflection to call EditorFor generically with a runtime type, and pass in an expression for the pertinent property.
You can view all of the code for the new Object.shtml by going and downloading the MVC source code. I thought it was also in some common folder on your pc already but I can't remember where.
http://aspnet.codeplex.com/releases/view/58781

Resources