I've got a controller, which is getting a list of objects associated with a user and passing it to the view using the render method, like so:
class HomeController {
def index() {
def postList = user.posts
postList.each{ it ->
println "Title: " + it.title
}
render(view: "/index", model: [returnPosts: postList])
}
In my view I have the following code:
<h2>Recent Posts:</h2>
<ul>
<g:each var="post" in="${returnPosts}">
<li><g:link controller="post" action="show" id="${post.id}">${post.title}</g:link></li>
</g:each>
</ul>
Now, in my controller, I've put in the 'println' statements to ensure that the list is not null, and sure enough it's not. However, when I open the page, the g:each tag doesn't run even once as if the "returnPosts" variable is null, even though in the controller the println statments show that it's not.
I've been going crazy trying to figure this out, can anyone see any reason why the view wouldn't have access to this variable?
You seem to have a controller attribute called 'post' and also your g.each var is 'post'. Potential problem there?
There are couple of things you could do to fix this problem. Firstly, if your view is called index.gsp then you don't need to explicitly call render, returning a list of model objects would do. Your code will look like this:
def index() {
def postList = user.posts
postList.each{ it ->
println "Title: " + it.title
}
[returnPosts: postList]
}
Another thing you could also do is to explicitly import the model object that you are accessing in the view. Not that it matters, but you could try using a name other than post, given that it is a common word. So your gsp will look like this :
<%# page import="com.blah.post" %>
<h2>Recent Posts:</h2>
<ul>
<g:each in="${returnPosts}" var="post">
<li><g:link controller="post" action="show" id="${post.id}">${post.title}</g:link></li>
</g:each>
</ul>
Related
I'm creating a Grails app following this tutorial: http://grails.asia/grails-tutorial-for-beginners-display-data-from-the-database
When I try to display data from database though, nothing happens. Below is my controller code:
def index(){
def users = User.list();
[users:users]
}
def displayUsers(){
if(User.count()==0){
render 'User list is empty!';
}else {
render(view: 'userlist.gsp');
//a little test
println User.list().size();
println User.count();
for(User u : User.list()){
println u.username;
}
}
}
The User.count() is working, because I can see the usernames in console and userlist.gsp renders every time, but it seems that my view code doesn't see the list. Here's the userlist.gsp code:
<body>
userlist.gsp
<g:each in="${users}" var="user" status="i">
<h3>${i+1}. ${user.username}</h3>
</g:each>
</body>
What can be wrong with this code? I've been making precisely the same steps as in the tutorial above in my analogical app, but it doesn't seem to work. This is especially weird, since I've found a similar question under this link: grails: show list of elements from database in gsp
and it's been marked as accepted answer. Why does exacly the same way not work in my app?
render gsp view as follows (pass data as a model).
render(view: "userlist", model: [userList : User.list()])
Now get model data in gsp as follows.
<body>
userlist.gsp
<g:each in="${userList}" var="user" status="i">
<h3>${i+1}. ${user.username}</h3>
</g:each>
</body>
You can do with many options:
rename your gsp action in controller from def index() to def userlist()
or rename index.gsp file to userlist.gsp
you can redirect to userlist.gsp with ${users} object
So change in controller def index() action
[users:users] to redirect(action: "userlist", params: ["users": users])
Note: 2nd method will show parameters in url.
Refer Grails Doc
You can use chain
e.g. chain(action: "userlist", model: ["users": users])
Refer Grails Doc
every gsp action (page) needs to be injected
I am trying to use a partial view that uses a different model than the one used in the main view. The partial view has
to show a list with the products recently added. But I am stuck on how and where to implement the logic for retrieving the data I need from the database.
Home/Index.cshtml:
#Html.Partial("~/Views/Shared/_LatestProducts.cshtml", new List<Website.Models.LatestProductsList>())
Shared/_LatestProducts.cshtml:
#model List<Website.Models.LatestProductsList>
#foreach (var item in Model)
{
<a href="#" title="img">
<img src="~/Content/images/latest-product-img.jpg" alt="" /><p>#item.ProductName</p>
</a>
}
And I have the following code that I am trying to use in order to get some products for tests and show them in the partial view:
public PartialViewResult _LatestProducts()
{
List<LatestProductsList> latestProd = (from p in db.Products
where p.ID < 5
select new LatestProductsList { ProductName = p.Title }).ToList();
return PartialView(latestProd);
}
I thought that I might use it in the HomeController, but that obviously doesn't work and I am not sure if partial views should have their own controller, if I can
just call it from another class. I am still wrapping my head around ASP MVC, so any help will be appreciate it.
Just call the action that renders the partial view in Index.cshtml.
#Html.Action("_LatestProducts", "Product")
Second parameter is the name of the controller that has the _LatestProducts method.
Just a reminder: Names with _ prefix is for partial views only, not action methods. You should rename it to LatestProducts.
new.gsp:
<html>
<head>
</head>
<body>
<g:form name="myForm" controller="New" action="index" params="username:username">
<div>
<fieldset class="form">
<label for="name">Name:</label>
<div>
<g:textField name="username" value="${params.userName}"/>
</div>
</fieldset>
</div>
<g:submitButton name="Submit" value="Submit" />
</g:form>
</body>
<html>
NewController.groovy:
package sample
import com.sun.org.apache.bcel.internal.generic.NEW;
class NewController {
def index = {
if($params.userName){
render(view:"/login.gsp")
}
}
}
login.gsp is a simple page, having a simple welcome note.
if some body the solution please reply,
thanks in advance.
by prasanth
Change your controller name to "new" instead of New in
It will work.
Or else you can modify your "save" action in controller, so that when you click on save button new page will be rendered.
There are a few issues in the posted code that will cause you problems:
You're accessing the parameters with $params instead of params. The $ character is only necessary when you are in a GString. e.g. def foo = "your username is ${params.userName}"
Your view is named new.gsp but your action is named index. Grails will by default look for a view matching the action name in a directory named for the controller. In other words, since you don't tell it explicitly to render /new.gsp grails will look for /new/index.gsp. You can either rename the view to /new/index.gsp or tell grails to render the view new in the index action.
When attempting to render your logged in page, you're calling render(view: 'login.gsp'). The gsp extension is not necessary when calling the render tag. You're intended to use the grails view name, not the filename. render(view: 'login')
If you're using a recent version of grails (>2.0) you should be using controller methods rather than closures. e.g. def actionName() { } as apposed to def actionName() = { }. The reasoning is in the grails documentation.
Here's what it could look like with all the issues addressed:
rename new.gsp to /new/index.gsp. rename login.gsp to /new/loggedIn.gsp.
controller:
class NewController {
def index() {
if (params.userName) {
forward action: 'loggedIn'
return // render and forward don't end flow control
}
}
def loggedIn() {} // no logic, automatically renders '/new/loggedIn.gsp'
}
Add a handler to your controller named login.
def login = {}
If the view file is new.gsp then you need your action to also be new or else have a URL mapping (in UrlMappings.groovy) to do something like:
"/new" {
controller = 'new'
action = 'new'
}
Or you can set
static defaultAction = 'new'
...in your NewController.
Then Grails will find the appropriate action on your controller.
if your action is called index, you can acces the page on
localhost:8080/webapp/NewController
I am maintaining a grails 1.1.1 application. There is an include code which works if we include from a regular gsp. But when I try to include it from _header.gsp it doesn't work. I am using exactly the same statement. It actually calls the method in the controller but nothing gets returned in the view.
Following is the code which works from a regular gsp
<g:include controller="abcGenericComponent" action="visitOurBoardsComponent" />
This is the method in controller
def visitOurBoardsComponent = {
def visitOurBoardsContent = abcGenericComponentService.getVisitOurBoardsComponent(request)
log.debug "Calling vistitboards ${visitOurBoardsContent}"
[visitOurBoardsContent: visitOurBoardsContent]
}
The log statement is showing up in the logs. That means the method is getting executed.
This is the included gsp
<ul>
<g:each var="ourBoards"
in="${visitOurBoardsContent}">
<li>
${ourBoards?.displayName}
</li>
</g:each>
I get the following error when returning a view:
Server Error in '/' Application.
--------------------------------------------------------------------------------
The view 'student' or its master was not found. The following locations were searched:
~/Views/Student/student.aspx
~/Views/Student/student.ascx
~/Views/Shared/student.aspx
~/Views/Shared/student.ascx
Here is my controller action:
[HttpPost]
public ActionResult SubmitStudent()
{
StudentViewModel model = TempData["model"] as StudentResponseViewModel;
ViewData["id"] = model.Id;
ViewData["name"] = model.Name;
string comment = Request["comment"];
var student = student.studentTable.Where(s => s.studentId == model.Id);
return View(student);
}
Here is my View:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<IEnumerable<string>>" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Student</title>
</head>
<body>
<div>
Student name listed below:
</div>
<table>
<% foreach (var item in Model) { %>
<tr>
<td>
<%= Html.Encode(item)%>
</td>
</tr>
<% } %>
</table>
</body>
</html>
A few things to consider here.
First of all, returning a view after a HTTP POST is really a bad design choiche. You can google about the PRG Pattern and you will find many articles that will explain why you should always redirect to a HTTP GET which will render your view.
Second, I find strange that your code is looking for a view name "student". As per MVC specification, the controller will look for a view named as the action method unless an overload of the View() method which accepts the view name as parameter is called (which is not your case, at least not in the code you posted).
In your example, it seems like it should look for a view named "SubmitStudent". Again, the model type you declare on your view doesn't match the model you're passing to it. It accepts an IEnumerable<string> but you're passing to it an IQueryable<Student> (that's what your student variable contains).
I think you omitted some parts of your code. The parts you posted don't quite match with one another.
In order for your code to work, you're going to need a view called SubmitStudent.aspx inside the Views\Student\ or Views\Shared\ folders.
It also looks odd that your view inherits a list of strings and not a Student object or whatever type of object your query returns. Your view is expecting an enumerable list of string's
This line is also confusing:
var student = student.studentTable.Where(s => s.studentId == model.Id);
Did you mean:
var student = model.studentTable.Where(s => s.studentId == model.Id);
Your view must be in "Views\Student\" - unless you have changed the view engine settings which I imagine you have not.
So I believe your view is not there.