I just started playing around with Play 2.1.1 using Scala. Going through some tutorials/sample apps, I came across the helper methods that can be used to create forms, e.g.:
#(myForm: Form[User])
#helper.form(action = routes.Application.submit) {
#helper.inputText(myForm("username"))
#helper.inputPassword(myForm("password"))
}
I am still a n00b to this. But as far as I understand, this basically requires a form object being defined within the controller, which "wraps" the model (simplified):
val loginForm = Form(
tuple(
"email" -> text,
"password" -> text
))
)
def login = Action { implicit request =>
Ok(html.login(loginForm))
}
I found this suprising, as I get the feeling that the indirection through the Form object seems "in the wrong place". What I was expecting was something like this (pseudo):
#(user: User)
#helper.form(action = routes.Application.submit) {
#helper.inputText(() => user.userName)
#helper.inputPassword(() => user.password)
}
...so that one does not have to define the Form object within the controller; all form-related stuff would be located within the view template.
Mixing the "this-will-be-rendered-into-a-form" logic into the controller seems like a minor violation of SOC to me.
Now I'm wondering: Is this just the way things are done in Play, or did I miss something? Is there a "nicer" way to handle this?
Cheers, Alex
I think it would be annoying too with many form definition in controller, especially the apps will involved many form.
But Play!Framework make developer to write code more flexible. You can mix plain HTML inside scala template helper like this :
#helper.form(action = routes.Application.submit) {
<input type="text" name="username">
<input type="password" name="password">
....
}
In my opinion, the scala helper actually helpful with form to update data that have been created before. Because it will bind the existing value into the default input value. And additionally, it also help to display error that caused by object validation.
If the form is not considered the previous value, like login form, I think the use of plain HTML input will be considered better.
Related
In Rails I can use accepts_nested_attributes_for to allow a single form to create two different but related objects. Now, I'm working on a Scala Lift project and I want to do something similar. I have a User model and an Address model. I want to have a single form that creates the User and their Address. How does this work in Lift?
In general, Lift approaches form processing by binding a handler function to each input which is called on form submission. In each of those functions, you would define the logic you need to set the appropriate fields in your model.
Using something like the example below you can instantiate your classes and then perform the appropriate action on submission. You will see this creates a User and an Address class and then sets a field on each of them. The function bound to the submit button will take care of persisting them both. Since the actions happen in a function, you can include as much logic as necessary to make your application work (data transformation, setting multiple fields, etc...). For example, in the submit logic I associate the id of the Address with the User to define how they are related.
In your Snippet
val user = new User()
val address = new Address()
".nameField" #> SHtml.input(user.name, (txt) => {
user.name = txt
}) &
".addressField" #> SHtml.input(address.address1, (txt) => {
address.address1 = txt
}) &
".submit" #> SHtml.submit("Save", () => {
//persist address
user.addressId = address.id
//persist user
})
In your HTML
<form data-lift="form">
<input class="nameField"></input>
<input type="submit" class="submit"></input>
</form>
In general, that is how you would accomplish what you are looking to do. In addition to handling everything yourself, Lift includes Mapper which is pretty much a database ORM. I believe that can automate a lot of the relation mapping and make the creation of some forms easier. I don't really use it myself, so I can't give you a more concrete example. But, if you decide to check that out, you can find more information on Mapper here and here.
I'm looking for a filteredTextBox in lift to block users from inserting wrong input types.
Something like this Ajax example: http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/FilteredTextBox/FilteredTextBox.aspx
Someone knows something similar in lift or knows if SHtml.ajaxText has some Attribute to do that?
If you are targeting HTML5 capable browsers, SHtml has outputs for specific types - like SHtml.number(...) and SHtml.range(...). You can accomplish the same thing using SHtml.ajaxText(label, func, "type" -> "number") (or "type" -> "range", etc...).
To target other browsers (or for more robust functionality), JQuery might be your best bet. You could write your own validation function to get called, or googling quickly found this library which looks like it would work (though there must be others too). Based on their documentation, to use it, it looks like you'd just need to do this:
Snippet:
//add a class for the type (in this case to validate lowercase)
".lc-input" #> SHtml.ajaxText(label, func, "class" -> "validate-this-lowercase")
Template:
//Add this into a processed template - head_merge should add to the head of the document
<head_merge>
<script type="text/javascript">
$(document).ready(function(){
$(".validate-this-lowercase").filter_input({regex:'[a-z]'});
});
</script>
</head_merge>
<span class="lc-input"></span>
I am trying to grok the instructions given in the play 2 scala tutorial for form template helpers. I am getting stuck in the section "Writing your own field constructors". It gives a sample template (without saying what the name of the file should be):
#(elements: helper.FieldElements)
<div class="#if(elements.hasErrors) {error}">
<label for="#elements.id">#elements.label</label>
<div class="input">
#elements.input
<span class="errors">#elements.errors.mkString(", ")</span>
<span class="help">#elements.infos.mkString(", ")</span>
</div>
</div>
Then it shows this code:
object MyHelpers {
implicit val myFields = FieldConstructor(myFieldConstructorTemplate.f)
}
I am confused about how this is supposed to relate to the template. (eg, is the template file supposed to be called myFieldConstructorTemplate.scala.html?) I tried some variations on this without luck.
I'm new to both scala and Play, but I also know play 2 and its docs are new, so I'm not sure what incredibly obvious thing I'm missing.
thanks!
I've just had the same problem, I agree with you the documentation is not clear at all...
Possible error 1
not found: value FieldConstructor
It means that you haven't imported the helper with this instruction :
#import helper._
Possible error 2
not found: value implicitConstructor
It means that you are declaring the field constructor in the wrong place in your template (i.e. : in the #helper.form method). To fix this, I declared my field constructor just after my import instructions :
#import form._
#import helper._
#implicitConstructor = #{ FieldConstructor(foundation_field.render) }
(My foundation_field.scala.html file is in the views.form package).
In the tutorial this code is along the text:
Often you will need to write your own field constructor. Start by
writing a template like:
This means you have to create your own template (xxxx.scala.html) and add that code inside. After that, you import it in your template with the code they provide (remember to add that to each scala template that uses your custom field):
#implicitField = #{ FieldConstructor(xxxx.f) }
Check the samples of Play, the Forms sample uses a similar approach with Twitter bootstrap.
To follow the logic of Scala implicit keyword, the document is implicit too ;)
Scala and Play are too immature right now, for that reason the documentation is very poor.
This SOF answer is very good: https://stackoverflow.com/a/15268122/1163081
You can also check the Play source for more examples: https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/views/html/
Or this guys appears to discover the solution: https://groups.google.com/forum/#!msg/play-framework/2e1EqZJ-Qks/gXD1oo0IjfcJ
I am using an application (a blog) written using the CodeIgniter framework and would like to search my blog from my browsers location bar by adding a string to the end of my blogs url like this:
http://mysite.com/blog/index.php/search...
As you can see in the example above I am not really sure how to format the rest of the url after the search part so I am hoping someone here might be able to point me in the right direction.
This is what the form looks like for the search box if that helps at all.
form class="searchform" action="http://mysite.com/blog/index.php/search" method="post">
<input id="searchtext" class="search_input" type="text" value="" name="searchtext">
<input type="submit" value="Search" name="Search">
</form>
Thx,
Mark
Since your form is posting to http://mysite.com/blog/index.php/search, I'm assuming this 'search' controller's default function is the one your are attempting to submit your data to. I think that the easiest way to do this would be to just grab the post data inside of the controller method you're posting to. Example:
function search()
{
$search_params = $this->input->post('search_text');
}
Then you would have whatever the user input stored as $search_params, and you can take actions from there. Am I misunderstanding what you're asking?
It seems like you're kind of discussing two different approaches. If you wanted to make a request to
mysite.com/blog/index.php/search&q=what_I_am_looking_for
This is going to call the search controllers default method (which is index by default). If you wanted to use the URL to pass parameters like that you would go to your function in the search controller and do:
print_r($this->input->get('q'));
This will print out "what_am_I_looking_for".
An easier approach in my opinion would be to:
1. Create a view called "search_view" with the HTML content you pasted above, and have the form "action" http://www.mysite.com/blog/index.php/test/search
Create a controller called "Test" that looks like the following:
class Test extends CI_Controller {
function search()
{
$search = $this->input->post('searchtext');
print_r($search);
}
public function display_search()
{
$this->load->view('search_view');
}
}
Visit http://www.mysite.com/blog/index.php/test/display_search in your browser. This should present you with the form you placed in search_view.php. Once the form is submitted, you should be sent to the search function and print out the variable $search, which will have whatever text you submitted on that form.
If this isn't what you were looking for then I am afraid I do not understand your question.
I have been using plain forms and input fields in coldfusion for some time now but recently discovered that cfinput tags will automagically prevent some xss attacks for me. This has made me wonder, if there is any disadvantages to using cffrom and cfinput over normal form and input tags in coldfusion.
The only disadvantage I have found in the short time looking into it is that it adds 2 external style sheets and 1 script tag to the page.
so in short:
What are the advantages and disadvantages of using CFFORM over FORM in coldfusion?
I prefer to write my own JS around my forms. I started out with cfform back in the day, but eventually wanted to do more robust things (validations, etc) than cfform was able to handle. That forced me to learn JS, and I've been very happy writing my own JS since.
So I guess I'd say one big drawback is that you're restricted to what cfform can handle. Depending on your situation, that might be fine.
Another drawback that I ran into a long time ago (which to be fair, may have been addressed since), is that the JS generated by cfform would conflict or interfere with my hand-written JS.
It'll certainly come down to preference. It's neither "right" nor "wrong" to use cfform or regular forms. For me, I prefer to be able to do whatever manipulation I need to do manually, as there are no restrictions/limitations.
I have a love-hate relationship with <cfform> & <cfinput>.
To have the same xss protection that CFFORM provides, just wrap htmlEditFormat() around value="" in regular like so:
<input name="x" value="#htmlEditFormat(x)#">
For even better XSS protection, use OWASP Enterprise Security API (.jar included in one of the CF9 latest hotfixes)
I love how I can do ajaxified form easily without writing JS, but I hate how it generates lots of ugly JavaScript and loads up lots of JS and css files for something rather simple. So I've decided to use cfform for internal sites only and not for public facing site (performance issue).
Other then the ajax features, the checked attribute that accepts CF boolean and populating select with query object are features that cfinput and cfselect provide which can be quite useful.
Use the right tool for the right job. If you found the feature of <cfform> useful, use it. Just know its limitations, and decide for yourself.
I have been using ColdFusion for almost 14 years. The reason that CF is such a kick-ass product is that empowers new users to get a lot of work done quickly with not much understanding and it enables rocket scientists to build really powerful and secure applications quickly too.
CFFFORM, CFINPUT, CFLAYOUT, CFPOD are tags that are created for new users. Basically, they are training wheels. If you're new to web development, you should give this tags a try. As you gain experience, you'll want to drop these tags and move onto other techniques to create more robust applications.
There's nothing wrong with these tags, just like there's nothing wrong with training wheels. You just need to know that there's an appropriate tool for each job. Actually, there are lots of appropriate tools for each job.
Currently, I am developing a ColdFusion 9 / jQuery / SQL Server intranet that builds external web sites. I am doing it without using a single form tag. And, I am doing it completely in CFSCRIPT. Whoa!
Using jQuery, you don't need forms. You just need inputs. Here's how I create an input in CFSCRIPT.
<cfscript>
Options = "";
for (i = 1; i lte 10; i++) {
Options = Options & wrapOption("Some choice #i# ", i);
}
SelectBox = wrapSelect(Options, "MySelectID");
writeOutput(SelectBox);
SecretDiv = wrapDiv("", "", "MyDivID");
writeOutput(SecretDiv);
</cfscript>
The user defined functions to create the HTML are in my UDF_Library.cfm file:
// WRAP SELECT
function wrapSelect(SelectContent, Class, ID) {
LOCAL.SelectContent = ARGUMENTS.SelectContent;
LOCAL.Properties = "";
// CLASS
if (isDefined("ARGUMENTS.Class")) {
LOCAL.Properties = LOCAL.Properties & " class='#ARGUMENTS.Class#'";
}
// ID
if (isDefined("ARGUMENTS.ID")) {
LOCAL.Properties = LOCAL.Properties & " id='#ARGUMENTS.ID#'";
}
LOCAL.Item = "<select #LOCAL.Properties#>#LOCAL.SelectContent#</select>";
return LOCAL.Item;
}
// WRAP OPTION
function wrapOption(Content, Value, Selected) {
LOCAL.Content = ARGUMENTS.Content;
LOCAL.Properties = " value='#ARGUMENTS.Value#'";
// SELECTED
if (isDefined("ARGUMENTS.Selected") and (ARGUMENTS.Selected eq "selected")) {
LOCAL.Properties = LOCAL.Properties & " selected";
}
LOCAL.Item = "<option #LOCAL.Properties#>#LOCAL.Content#</option>";
return LOCAL.Item;
}
// CREATE DIV
function wrapDiv(Content, Class, ID) {
LOCAL.Properties = "";
// CLASS
if (isDefined("ARGUMENTS.Class")) {
LOCAL.Properties = LOCAL.Properties & " class='#ARGUMENTS.Class#'";
}
// ID
if (isDefined("ARGUMENTS.ID")) {
LOCAL.Properties = LOCAL.Properties & " id='#ARGUMENTS.ID#'";
}
LOCAL.Item = "<div #LOCAL.Properties#>#ARGUMENTS.Content#</div>";
return LOCAL.Item;
}
I use jQuery and refer to every element by its class or ID. If you do that, you can submit the data in each element to an ajax call like this:
<script type="text/javascript">
$(document).ready(function() {
$("#MySelectID").change(function() {
MyID = $("#MySelectID").val();
$("#MySecretDiv").load("CoolQuery.cfm?UserID"+MyID);
});
});
</script>
The point is, that as long as you are using CFFORM and CFINPUT, you can't do all the really powerful jQuery stuff. But, you need those tags to get started.
2012 is going to be a kick-ass year for the power of ColdFusion and jQuery!!!
Good luck!
I haven't used ColdFusion's CFInput in a long while. I've been using the jQuery Validation plugin so that I can perform validation on other things like:
is the element visible? (ie, hide a section if not essential, but eliminate the requirement if not shown.)
is a checkbox checked? (ie, you checked "other", now fill-in-the-blank is required.)
is it a valid date/time value? (ie, I additionally use the DateJS library to assist in this)
perform ajax query to determine if username is unique
is the URL entered valid?
compare password1 with password2
custom rules based on a combination of things
Most validation rules can be added inline to the class parameter:
<input type="text" name="Name" class="required">
<input type="text" name="Birthdate" class="required date">
<input type="text" name="Email" class="required email">
<input type="text" name="Website" class="url">
I prefer to use jQuery because sometimes I need to add this same logic to a non-ColdFusion based form and I don't have to worry about the fact the CFInput is a ColdFusion-Only tag.
Here's a link with more information regarding the jQuery Validation library:
http://bassistance.de/jquery-plugins/jquery-plugin-validation/