I am not sure if this is the best approach but I have a controller that originally I intended to control a show index that renders many partials on it (a header partial and then, has some if else magic to render different partials based on the step the user is in in filling out a form... a form has many sections across several pages). I think ultimately ajax is the way to go but I am not even to that point yet. I am not sure this is the right way to do it, so I guess that is what I am asking... is the many different partials to one controller the way ? or does each "page" of form data have to be broken out into its own controller? allowing the user to fill out form (check boxes, comment section) and click "next" passing the model of the data they are filling out along the way and saving that model in each next?
U may not need several controllers, but 1 controller with some actions may be a good start. =)
Then each action should load only the partial it needs. like u can give the action name to the partial, making easy to know which partial to render.
Or maybe u can try to use wicked.
There is a railscasts for it.
Well, you could use a method to decide which partial to render.
Use this example or do some meta programming.
class YourController < ApplicationController
def index
render :partial => partial_selector(param)
end
private
def partial_selector param
#logic to decide what partial do render
#returns the partial name
end
end
Related
I'm trying to figure out how to do an inline editing for a user-generated object, what the rough procedure (no code just steps), and whether or not there's some way to do this without AJAX - of course it wouldn't be "inline" anymore.
Say the user object is just 1 line of text and 1 image. Something like,
class UserObject(models.Model):
text = models.CharField()
image_path = models.CharField()
If I were to use AJAX, would this be how it'd go? (sorry this is vague, I can figure out the details just trying to see if I understand the concepts correctly)
Create a form, populate it with an instance of the object belonging to the current user
Next to the image, I'd have, say, a "remove" button, which triggers an AJAX call to a URL that's something like project/remove/ab12345 that's connected to a view that handles it.
Wait for the AJAX call to be done
Then somehow remove the image and buttons, maybe by just deleting the div that contains it all
Is that right??
Also, what if I don't want to use AJAX? Would it go something like this?
Create a form, populate it with an instance of the object belonging to the current user
Next to the image, I'd have, say, a "remove" button, which directly links to the URL that's something like project/remove/ab12345 that's connected to a view that handles it
After the view deletes the image, it goes back to the editing page, which just refreshes and the image is no longer there.
Any pointers would be greatly appreciated!! I can figure out the details of the coding, just wondering if I am getting the concepts right.
An object created by a user is really no different from one you create yourself (except you have to be suspicious of potentially malicious input!). The simplest way to be able to edit objects outside the admin interface is to use the built-in UpdateView. Similarly you can delete them with a DeleteView. If you want to restrict you can edit objects you can user the PermissionRequiredMixin from django braces.
OK since I posted this ultra-vague question I'm going to answer it.
AJAX-free:
The AJAX free version is pretty much as I described, create a view and a URL that deletes the image and goes right back to the referring page. Next going to try the AJAX version, which basically requires a view that returns some kind of a signal of failure or success.
urls.py
url('^project/remove_image/(?P<image_id_string>[0-9A-Fa-f]+)/$', pbrand.views.ProjectRemoveImageView.as_view(), name='project_remove_image'),
views.py
class ProjectRemoveImageView(View):
redirect_url = '/project/edit' # the editing url
def get(self, request, image_id_string, *args, **kwargs):
# ... some checks on permissions
image.delete()
return HttpResponseRedirect(self.redirect_url + "/" + project.id_string)
inside the template
<a class = "btn btn-default btn-sm" href="{% url 'project_remove_image' i.id_string %}" role="button">remove</a>
I am looking for the way to refresh a template inside a view rendered from another controller than the template's controller, I mean:
I got two controllers AdminController & UserController. And two gsps /admin/listUsers & /user/_searchResult.
Then a want to render view listUsers who have inside the template _searchResult and all right.
Now, i want to refresh the template _searchResult, but cant find how. I tryed calling render(view:"/admin/listUsers", template:"/user/_searchResult", model:[searchResult:result])
AdminController.groovy
#Secured(['ROLE_ADMIN'])
def listUsers(){
//...
}
UserController.groovy
#Secured(['ROLE_ADMIN'])
def search(){
//search users for the givven params and send result by chain if there's an action or update a template if it's needed
//in my case this method need to update the template _searchResult
}
#Secured(['ROLE_ADMIN'])
def searchResult(){
//...
[searchResult:result]
}
listUsers.gsp
//...
<formRemote name="searchForm" url="[action:"search", controller:"user"]">
//Some fields for the search
//I need to place here some hidden inputs to send which
//template i want to update or action to redirect
</formRemote>
<g:render template="/user/_searchResult"/>
//...
_searchResult.gsp
//Just itterate and print the search result in a table
I hope I have explained the problem correctly, thanks!
I don't think I entirely understand your question, but I think the source of your confusion is that the way you are naming things doesn't follow regular conventions and you're not using the right tools for the job. Let me explain...
The methods on Controllers are called Actions. They send some data (the Model) to a View to be rendered into HTML. Views can be composed from smaller, reusable fragments called Templates. (sorry if I sound like I'm being condescending here, but I'm just trying to make sure we're all on the same page).
Now, what you've called templateA is actually a View, not a Template. You're correct that templateA (your View) can call templateB to render some markup, but then having the templateB try to call a method on another Controller doesn't make sense. That's not how things flow.
If you have some logic that needs to be executed after you've sent your Model to the View, you want to use a Tag Library (http://grails.org/doc/latest/guide/theWebLayer.html#taglibs).
To summarise, here's a quick recap.
A request should only call one Action, which sends the model to only one view.
If you need to reuse logic between Controllers, move that code to a Service.
If you need to reuse markup between Views, move that markup to a Template.
If you have logic that you want to have executed after you've sent the Model to the View, use a Tag Library.
Hopefully this will point you in the right direction.
--- UPDATE ---
OK, with the real code I can see better what you're trying to achieve. Firstly, as you're using the <g:formRemote> tag, you should have a good read of the docs at http://grails.org/doc/latest/ref/Tags/formRemote.html to understand what it does.
What you will have here is 2 separate requests. The first will be a regular page load by your browser, which is handled by the listUsers() action. Once the page is then finished loading, the user will enter a search term and hit the submit button. This will fire off a second ajax request, which will be handled by the search() action. This action could use the _searchResult.gsp template to render a HTML table to display the search results. When the browser get this, it will insert it into the DOM where you've told it to put it using the "update" attribute of the <g:formRemote> tag.
The important thing here is that from the server's perspective, these are 2 separate requests that are completely independent. They both first call an action, then send a model (a Map containing some data) to a view, which renders/merges the data with HTML and sends it back to the browser.
The difference between the 2 is that the first is a complete page load by the browser, whereas for the second request, the browser only loads a small chunk of HTML (the search results table) and updates the page content without reloading it.
So your code would look more like this...
AdminController.groovy
#Secured(['ROLE_ADMIN'])
def listUsers() {
render(view:"/admin/listUsers")
}
listUsers.gsp
<g:formRemote name="searchForm" update="insertSearchResultsHere"
url="[controller: 'user', action:'search']">
<input name="searchTerm" type="text" />
</g:formRemote>
<div id="insertSearchResultsHere"></div>
UserController.groovy
#Secured(['ROLE_ADMIN'])
def search() {
// use the search term to get a List<User>
render(template: "/user/searchResult", model: [users: users])
}
_searchResult.gsp
<table>
<g:each var="user" in="${users}">
%{-- Iterate through your search results --}%
</g:each>
</table>
I solved it by placing the attribute update and rendering the template alone:
gsp:
<formRemote name="searchForm" url="[action:"search", controller:"user"]" update="divToUpdate">
//Some fields for the search
</formRemote>
<div id="divToUpdate">
<g:render template="/user/_searchResult"/>
</div>
Controller:
def search(){
render(template:"/user/_searchResult", model:[searchResult:result])
}
When i asked this question, i was new on Grails community and i was confused with the use of remoteFunction and tags that use it like remoteForm. But i had this confusion because of i had not read the documentation. So in my case, the solution was search for documentation about how to use remote tags and render. Thanks to #AndrewW for show me the way.
I have controller PlayerController and actions inside: View, Info, List.
So on urls "/Player/View" i get result with default Layout.
I want to get result with different Layout on request "/External/View".
How can i achieve this?
Although you can override the layout from the controller as has been suggested in another answer, in my opinion this means the controllers are getting just too involved in determining what the UI will be. Best to leave this purely to the Views to decide.
The closest to what you're asking is to do this in your current "~/Views/_ViewStart.cshtml":
#{
if(Context.Request.Path.StartsWith("/External", StringComparison.OrdinalIgnoreCase))
Layout = "~/Views/_ExternalLayout.cshtml";
else
Layout = "~/Views/_Layout.cshtml";
}
Where "~/Views/_ExternalLayout.cshtml" is your alternative layout.
Might want to check the leading "/" is correct on there, I can't remember if it is.
If you put this in the existing _ViewStart, then any view that is being rendering in response to a url starting with "/External" will use this new layout, otherwise the 'normal' one will be used.
Another approach is to use the routing table to add a route value that can be used here to make a layout decision; but I've gone for this approach to keep it simple.
You can specify which layout should be used when returning a view inside your 'ExternalController' controller action.
return View("View", "~/Views/Shared/_AnotherLayout.cshtml")
Imagine I have a form (Page1.cshtml) with 1 link (LinkBrands). I also have a controller for Page1 (Page1Controller) and one for brands (BrandController). When the user clicks the link what is better to do:
LinkBrands-->Page1Controller-->BrandController (Page1Controller's action will redirect to BrandController)
OR
LinkBrands-->BrandController
Not sure what route is better. Any suggestions?
Usually you don't have a single controller per view. You would use multiple views or partial views all calling actions on the same related controller. I assume Brand is a separate entity from whatever else Page1 is trying to display, therefore it should probably use the BrandController directly but since there really isn't enough information to go on with your example as to what page1's function is I couldn't say what you are trying to relate.
If you need to capture information from the brand link as it relates to page1 then sure have it collect that in page1controller first before redirecting to brandcontroller to display a new view.
What does your Page1Controller do?? It seems as though you are defeating the purpose of the Model-View-Controller architecture and trying to form it back to the WebForms method with code-behind.
So without seeing what exactly your controllers are doing, I'd say your second option is best.
It all depends.
If you have to execute any logic in Page1Controller (saving data for instance) before displaying the second page, then you need to go by Page1Controller, and then go to BrandController:
LinkBrands-->Page1Controller-->BrandController
In case you just need to redirected to the second page (you do not need anything from Page1Controller, you do not need it to perform any action, and you can create a the model for second page in BrandController) then go with the second option:
LinkBrands-->BrandController
Hope this helps.
Are it in any way possible to execute another action in the same on in another controller from an action, action filter or in any other way without doing a physical redirect.
The reason for this is that I have a dynamic paging system, where the user will load a url, for an example
/1/some-page-title
This url is maped to the controller “Home” and the action “Element”, this action will then load a row from the database where the element id is “1”. Depending from the data on the element from the database will the page be rendered as a contact form, an image gallery and so on.
Now I could map the paths so
/Page/1/some-title/ will render a normal html page,
/Contact/1/some-title/ will render a contact form
/Gallery/1/some-title/ will render a gallery
But I would prefer the paths to be simple.
There are problems with this answer, it's been a long time since I did anything thing with ASP MVC, so I'm not actually aware of what the problems are.
Unfortunately I can't delete an accepted answer.
So, I'm striking through the answer as it was, if you can actually answer this, or make it better, please do so.
Yes, very simple really :)
Say you're in controller C action A. You want to "redirect" to controller B action Z, just call the other controller action from the current one, returning it's result.
public ActionResult A()
{
return B.Z()
}
You may be looking for Html.RenderAction or Html.Action. However, these are used in the view and not the controller.