views:

140

answers:

3

Hello there, I am trying to make a filter for my data so other people can see it, lets say I have a bunch of Events, like a calendar, and I want to see all that have a name or title with the word "Soccer". I've been trying to figure out how to do it but nothing works for me, I also tried to use filterPane plugin but did not work quite as well and I prefer to write something myself and maybe upload it to the Grails plugins webpage for future references,

Any help would be greatly appreciated.

-Fernando

+1  A: 

You could query by example or use the findAllWhere if you only need to filter by equality. Otherwise you will need to use the criteria builder to generate the appropriate query.

Blacktiger
Oh, and I hope you don't have to join multiple domain classes together for your filter as that can be quite tricky. ;)
Blacktiger
I only have one main class Entry, and findAllWhere sounds good.Wouldn't that filter the description too?? I don't need to filter description, only by the title of the event.Would findAllWhere work too??
fgualda87
The findAllWhere method doesn't sound like it will work for your situation. It looks for exact matches only where you probably want some form of like query. In your case I would recommend reading up on the createCriteria method in the grails user guide.
Blacktiger
yes, that seems like the best thing to do, thank you.
fgualda87
+3  A: 

If it's in a domain class try:

def matches = Book.findAllByTitleLike("wonderful")

of if you don't want to worry about upper/lower case:

def matches = Book.findAllByTitleILike("wonderful")

If your book titles are in a collection:

def books = ['Wonderful Tonight', 'Atlas Shrugged', 'A Tale of Two Cities']
def matches = books.findAll{it.indexOf("wonderful") > -1} // returns []
matches = books.findAll{it.indexOf("Wonderful") > -1} // returns ['Wonderful Tonight']
matches = books.findAll{it.toLowerCase().indexOf("wonderful") > -1} // returns ['Wonderful Tonight']

Update:

So now that we have a more complete description of your problem, let's figure out a simplified way to solve it.

Today, you want to search by event title and its date so we'll start there then look at how we might generalize this and make more complete solution down the road.

Our general flow is going to be something like:

  1. You display a search form to your user
  2. User enters a date and/or title to search for and submits the form
  3. You find the matching entries
  4. You display the matching entries to the user

First, let's create a view for the search form, in grails-app/views/entry/ create a file called search.gsp with the following content:

<g:form controller='entry' action='searchResults'>
   Entry Title: <g:textField name="title" value="${title}" />
   Entry Date: <g:datePicker name="day" value="${day}" precision="day" />
   <g:submitButton name="submit" value="Search" />
</g:form>

Next, we'll create the controller. In grails-app/controllers/ create a new controller EntryController.groovy. You can do this by executing the 'grails create-controller Entry' if you don't already have the EntryController created.

Now, we'll create two controller closures:

def search = {
  render(view:'search')
}

and

def searchResults = {
  def entryCriteria = Entry.createCriteria()
  def results = entryCriteria.list {
    if(params?.title) {
      ilike{"title","%${params.title}%"
    }
    if(params?.day) {
      eq("eventDate", params.day)
    }
  }
  render(view:'searchResults', model:['results':results])
}

Finally, let's create a searchResults.gsp in grails-app/views/entry

<h1>Results</h1>
<g:each in=${results}>
  ${it}
</g:each>

So, now putting it all together:

  1. Run your app and go to localhost:8080/${appName}/entry/search, and that should bring up your search form.
  2. Enter a title and/or date, submit the form and that should send your form data into the searchResults closure in your controller
  3. The criteria search in the closure will find all the Entries that match your search criteria
  4. You render the search results view and pass it your matching entries, then on the gsp we loop through each of the results and display it.

As a disclaimer, I'm writing this code on the fly in the stack overflow text editor, so I won't be surprised if there are a couple syntax issues that I missed. Hopefully the explanation will be enough to get you on your way. Now let's talk about taking this basic example and polishing it up to a more respectable solution.

I would recommend you try to do the following after you get the hang of this basic example:

  1. Try building a command object to represent your search form, it will allow you to validate your user's input and is a more manageable approach than dealing directly with the request parameters like I did above.
  2. Build some unit tests for your command object and the controller flow; check that error messages are being populated for your various validations.
  3. Take the criteria search that we have defined in the searchResults closure, and move it out to a separate Grails Service, pass your command search object to the service to get your results. Then, you can re-use the search functionality if you need it else where in your application later.
  4. Build some unit tests for your service; mock out the Entry domain object and verify that your search functionality is working correctly.

If you're struggling to get the above solution to work, try to simplify it even further. Eliminate the date search and just search by title. Replace all the criteria logic in the searchResults action with:

def results = Entry.findByTitleILike(params?.title)

Start simple and improve and you'll get the hang of it in no time.

Good Luck!

proflux
Thanks proflux, this looks good and straight to the point, I am still a little lost.I updated the info to make it specifically about my project.I only have one main domain class named Entry so I guess it would be,def matches = Entry.findAllByTitleLike("Soccer")Where do I put that piece of code? In a method?Then how do I call it to make the filter work??Also I need to filter the date the event is going to take place, like let's say I wanna see all the activities ocurring between June 23rd and June 27th.Thanks again!! I hope you can help me!
fgualda87
Another poster mentioned the Filter plugin, unfortunately I don't have enough rep to comment directly on that yet. :-) I would avoid that one for the time being, it seems to be in a state of decay, the last activity was in Feb 2009 so it seems like it's pretty much dead at this point. I'm adding an update to better explain...
proflux
Proflux:I did everything you said, when I look for a word in the search.gsp it gives me an error saying: "Error processing GroovyPageView: Tag [each] missing required attribute [in] ". Any idea on what is going on and how to fix it?I wanna thank you you've been of great help!
fgualda87
Also, the results should update the table and show them in the same table. So the table should be updated to searchResults, right?
fgualda87
Oops, looks like I forgot some quotes there in the g:each tag. Change in=${results} to in="${results}".
proflux
You'll have to help me understand your last comment... "The results should update the table and show them in the same table" Do you mean that you want to display the results as an html table?
proflux
The thing is that it is a filter, I need to like update the table so it shows only the results filtered, the rest of the page should be the same, but if anything I can copy the same code to the new page, don't worry. I'll change my code and let you know in a second.
fgualda87
Wow! It works almost perfectly fine! It tells me which ID's have the words. I'll try to put up a screenshot so you can see what I want to do.Also, now that we are more into my program I will try to create a new question.
fgualda87
you can change the content of what is displayed by switching ${it} to ${it.title} or whatever to show the property you want. To update a table, you have several options depending on what you need. You could make it as simple as just adding your search form and results on the same page, so in order to update the table you would submit the form and refresh the screen. Only slightly more complex you could send an ajax call to the server and update the table portion of the page dynamically. Or, you could go as far as using a JQuery/YUI widget and dynamically get your results over JSON
proflux
Wow, that sounds way more complicated. I opened a new question since this post has evolved, the link is http://stackoverflow.com/questions/3105021/grails-filter-data-in-a-grails-table-dynamically if you don't mind keep helping me. Thanks for everything. You answered a million questions already.
fgualda87
Also, if you could vote the question I would really appreciate it too. Thanks!
fgualda87
I have a problem with that though... Is not filtering... Is just giving me everything on the table.
fgualda87
can you check the entryCriteria.list {} and tell me if something is wrong, I think the mistake is there
fgualda87
Check and see what the values of params.day and params.title are. Are the name attributes of your form elements the same as the parameter names used in the filter? for example in the form you have <g:textField name="title" /> and in the controller you're looking for params.title? Most likely reason I would guess is that neither of the if-statements in the criteria are being triggered.
proflux
I see the problem with the criteria, the 'ilike' clause is bad; missing the closing parenthesis and I used a curly brace instead of parenthesis on the opening one. See the response to your new question for a better example, or the Grails reference doc. I wrote a demo for this locally so the code I posted in the other question is functioning as I expect.
proflux
Yeah i fixed that when I saw it the first time. Everything looks perfect. Now I only need to make the dates filter work. The title filter is working, but is not recognizing the dates. I have two dates and from those two I have FROM and TO... And I tried something earlier this morning and it would only filter the first FROM date, not the range :/
fgualda87
+1  A: 

The filter plugin seems to meet your requirements.

Don
I tried it but it doesn't seem to be working right... Or maybe I did something wrong, but I followed the instrucions on the page and did the same thing they did on their example and it gives me an error
fgualda87