I have this <g:formRemote> having this attributes,
<g:formRemote name="innerForm" id="innerForm"
url="[controller:'user', action:'actionAJAX']"
update="formMessage">
<div id="formMessage">Fill up the fields</div>
<g:render template="form" bean="${newUser}" />
<div class="buttons">
<g:submitButton name="Create User"/>
<input type="reset" value="Cancel"/>
</div>
</g:formRemote>
which upon submit procceeds to a closure having this lines of codes,
def actionAJAX() {
def userInstance = new User(params)
render(template:"error", bean:userInstance)
}
_error.gsp would contain scaffold display of bean error in which violates the domain constraints (nullable, blank, etc.). It would look like this:
<g:hasErrors bean="${userInstance}">
<ul class="errors" role="alert">
<g:eachError bean="${userInstance}" var="error">
<li <g:if test="${error in org.springframework.validation.FieldError}">data-field-id="${error.field}"</g:if>><g:message error="${error}"/></li>
</g:eachError>
</ul>
</g:hasErrors>
message
The problem is that I can't display the errors of the bean [def userInstance = new User] on the _error.gsp. The scenario was only to leave all of the fields of _form.gsp (having the contents of the generate-view and removing all required attribute) but upon submit the closure only returns message on the <div id="formMessage"> which was expected to display all the errors of the domain that violates the domain constraints.
If that is all of the code you are showing, your main problem is you are not calling .validate() or .save(). You must call either one to get errors in your object.
def actionAJAX() {
User userInstance = new User(params)
if ( !user.save() )
{
render(template:"error", model:[userInstance: userInstance])
}
else
{
render(template:"success", model:[userInstance: userInstance])
}
}
Just a quick look at the code, so maybe I'm missing one of many Grails conventions, but you are passing to the render method the userInstance with 'bean' as map key. And then referring to it as ${userInstance}. Try to refer it as ${bean} inside the templeta or pass it like:
render(template:"error", userInstance:userInstance)
It's not an answer for your question, just an additional tip: you can use g:renderErrors tag inside your error template or even instead of it.
Related
I'm trying to build a dynamic view, where I can pass a list of properties that need to be filled in by the user.
The collection of properties is dynamic, so I can't build the view that displays specific properties.
I've been able to display the property names and their initial values, and the user can change the values on the screen, but those updated values don't make it to the controller action that would update the model.
I've tried using a dynamic model, as well as a list of key/value pairs.
I'm thinking that it has something to do with the over-posting protection. Since the properties are dynamic, I can't list them in the Bind attribute in the update action.
Here's the controller action methods:
public IActionResult Test()
{
dynamic testObj = new ExpandoObject();
testObj.IntProperty = 100;
testObj.StringProperty = "A String Value";
return View(testObj);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Test(ExpandoObject model)
{
return Ok();
}
Here's the view:
#model dynamic
#{
ViewData["Title"] = "Test";
}
<form asp-action="Test" method="post">
<div class="form-horizontal">
#foreach (var propertyName in ((System.Collections.Generic.IDictionary<string, object>)Model).Keys)
{
<div class="form-group">
<label class="col-md-2 control-label">#propertyName</label>
<div class="col-md-10">
#Html.TextBox(propertyName, ((System.Collections.Generic.IDictionary<string, object>)Model)[propertyName])
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
</form>
This is a new application, and I'm doing code-first - so the model can be changed somewhat. All I really need to do is to be able to have different properties that can be updated.
Thanks in advance.
I recommend that you do not rely on the IModelBinder for this purpose at all and why I recommend this is because the form data that is passed between the controller and view is dynamic in terms of structure. A better, yet more troublesome, solution would be to get the form data directly out of the HttpContext.Request.Form. This type has an indexer which allows you to access the posted values by their names. For example
var name = HttpContext.Request.Form["name"].FirstOrDefault();
The .FirstOrDefault() (or SingleOrDefault(), this throws an exception when finding more than a value that meets a condition in a collection) is called assuming that there would be a single value (or a single value that meets a condition) for the "Name" input. However, when you have an array of those, you can get the values either in a foreach loop, or using linq methods, or directly by an index. For example:
var name = HttpContext.Request.Form["name"].FirstOrDefault(x=> x.ToString().StartsWith("x"));
var name = HttpContext.Request.Form["name"][0];
When updating a domain instance I need to check some data before allowing the update.
I made it in the beforUpdate method and it prevents the update but in the flash message you can read "Domain 68 updated!" and that is not what I want to show the user.
The beforeUpdate looks like this:
def beforeUpdate() {
def oldVolume = getPersistentValue('volumeInStock')
if (oldVolume != volumeInStock && oldVolume!=volumeInitial){
throw new ValidationException("Changing InStock not allowed after offer/sold or planed volumes added!",this)
}
}
I was thinking about throwing an exception, but that didn't look as easy as I thought. When I tried the code above it says that there are method like that. and I can't find any example or instructions how I should make the call.
So the main question is how can I inform the user about the problem?
Is it the wright way to use exception, then I need some help how to do that or else what else can I do? :(
I tend to use a generic exception handling mechanism for my controllers like the following which works for most scenarios, this might not work for you if you need to do additional stuff other than render the message to the screen.
trait ControllerExceptionHandler {
def handleException( Exception e ) {
def msg = e.message ?: e?.cause?.message
flash.fail = msg
log.info msg
return
}
}
Then your controllers implement this trait:
class MyController implements ControllerExceptionHandler {
def save() {
// do something that might throw an exception, if it does the ControllerExceptionHandler will deal with it
// it worked
flash.message = message( code: 'default.success.message' )
}
}
In your gsps:
<g:render template="/templates/alerts"/>
views/templates/_alerts.gsp
<g:if test="${flash.message}">
<g:render template="/templates/message" model="[type: 'info', message: flash.message]" />
</g:if>
<g:if test="${flash.fail}">
<g:render template="/templates/message" model="[type: 'danger', message: flash.fail]" />
</g:if>
views/templates/_message.gsp
<div class="alert alert-${type} alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
${message}
</div>
The above makes use of bootstrap styling.
But why do you avoid standard grails validation mechanism?
Just define constraints, validate() or save(), put errors to flash if hasErrors().
Throwing exceptions may break your transactions (if you save in transactional services, that is recommended).
So i got a page that have a search form, and when the user search for a value if there are no records on database the form returns empty, but if there are records the form is populated with data.
What i was thinking was this
var db = Database.Open("myDataBase");
var selectCommand = "SELECT * FROM exportClient";
var searchTerm = "";
if(!Request.QueryString["searchField"].IsEmpty() ) {
selectCommand = "SELECT * FROM exportClient WHERE clientAccount = #0";
searchTerm = Request.QueryString["searchField"];
}
if(IsPost){
var selectedData = db.Query(selectCommand, searchTerm);
}
And Then:
<body>
<div class="col_12">
<form method="get">
<label>search</label><input type="text" class="col_3" name="searchField" />
<button type="submit" class="button red" value="search">search</button>
</form>
</div>
#if(!Request.QueryString["searchField"].IsEmpty() ){
foreach(var row in db.Query(selectCommand, searchTerm)) {
<div class="col_12 box">
<form method="post">
// HERE IS THE FORM POPULATED
</form>
</div>
}
} else {
<div class="col_12 box">
<form method="post">
// HERE IS THE FORM NOT POPULATED
</form>
</div>
}
</body>
But what is happening is that the form that is not populated is always showing up when i enter the page, and i need that the only thing that user see when enter the page is the input field to do the search.
What am i doing wrong ?
I'm not sure of having understood your goal, but in my opinion your main problem is to detect if either exists or not a query string.
I think that your code should be like this
#if(Request.QueryString.HasKeys())
{
if(!Request.QueryString["searchField"].IsEmpty() ){
<p>searchField has value</p>
} else {
<p>searchField hasn't value</p>
}
}
There are a number of potential issues I can see with your code, hopefully you can put these together to achieve what you wanted:
As Selva points out, you are missing the action attribute on your forms.
The selectedData variable you create inside your IsPost() block goes out of scope before you do anything with it. Perhaps you didn't include all your code though, so ignore this if it just isn't relevant to the question.
To answer the main question: if you don't want the empty form to appear when the user hasn't yet performed a search, surely you just need to completely remove the else block - including the empty form - from your HTML?
Hope that helps.
I try to made nested form with validation. All works fine, but when I remove one of nested form, validation continue to use removed form. I made jsfiddle example http://jsfiddle.net/sokolov_stas/VAyXu/
When example runs, form are valid. If click "+" button, nested form will be added and valid will be false. Then click "-" button, and valid will be false all the same.
The question is: How to remove dynamic created form from validation processing.
Well, for one thing, a <form> inside of a <form> is not valid HTML.
Second, you're not supposed to be doing DOM manipulation from inside the controller. The controller is for "business" logic. See the section on controllers here
For what you're doing, you'd probably be better off using one form, with an ng-repeat inside of it, and adding additional elements to an array:
<form name="myForm" ng-controller="FormCtrl" ng-submit="doSomething()">
<div ng-repeat="item in items">
<input ng-model="item" type="text" required/>
</div>
<a ng-click="addItem()">+</a>
<a ng-click="removeItem()">-</a>
<button type="submit">Submit</button>
<div>Form valid: {{myForm.$valid}}</div>
</form>
and the controller:
function FormCtrl($scope) {
$scope.items = [];
$scope.addItem = function() {
$scope.items.push(null);
};
$scope.removeItem = function() {
$scope.items.pop();
};
$scope.doSomething = function () {
//your submission stuff goes here.
};
}
this is probably a stupid question but I cannot figure out how to do it.
So I'm new to Scala/Lift and I read the ajax form chapter in http://simply.liftweb.net/index-4.8.html#toc-Section-4.8 but the "RedirectTo" in the example does not seem to be very "ajaxian" to me. Often in case of submitting a form via ajax, you would just partially rerender the same page, right?
So that's what I'm trying to do and am completely failing right now.
How do I let Lift rerender just a part of the same page after I submit the form via ajax?
Any hints would be appreciated. Thanks.
Basically, what I have looks like this:
<div id="main" class="lift:surround?with=default;at=content">
<h2>Welcome to your project!</h2>
<div class="lift:Test">
<div>
<form class="lift:form.ajax">
<fieldset>
<label for="name">Name:</label>
<input id="name" name="name" type=text>
<p></p>
<input id="save" type="submit" value="Save">
</fieldset>
</form>
</div>
<div>
<span id="theName">Name</span>
</div>
</div>
</div>
class Test {
def render = {
var name = ""
def process(): JsCmd = {
Thread.sleep(500)
S.notice("Entered name is: %s".format(name))
Noop
}
"#theName " #> "This shall be updated with the name given in the form above" &
"#name" #> (SHtml.text(name, name = _) ++ SHtml.hidden(process))
}
}
How would I update "theName" when submitting the form?
Have a look at http://lift.la/shtmlidmemoize-simple-ajax-updating (Example Code). There is SHtml.memoize and SHtml.idMemoize which automatically caches the HTML code. Not sure why it is not used in this example in the Simply Lift book.
You have a 2 step form right? The above poster is correct.
Save your transformation in a RequestVar.
in your above example, the method you want to save is render, so 1st memoize the transform:
private def renderTest= SHtml.memoize { render }
Then, you can save this memoized transformation in a RequestVar (lasts for 1 request), or maybe a TransientRequestVar depending on your needs.
private object testTemplate extends RequestVar(renderTest)
When you want to replay the transform, from an ajax event - testTemplate.is.applyAgain.
I might have misunderstood the original question, b/c if you want to do a 2 step form, you don't really need the memoize. The memoize is if something changes on your current form, and you want to update it via an ajax event, i.e. on click or on change, b/c normally the form wouldn't update unless you did an ajax submit.