Play Framework Html class and Form Rendering without Input - forms

I have 2 questions. Version 2.4.x of the Play! Framework.
Whenever I render a layout using layoutName.render(inputargs...); it returns an "Html" object. I have not found a reference to this class in any of the docs. Where do I find this class? This doesn't seem to yield anything. (Edit2: Found in play.twirl.api.Html)
I am rendering a search bar on every page which is created using an input form. The problem is that the main layout needs my model class for the form as an argument: mainLayout.render("title", something_else, new Form<Search>()); Is there any way of writing it as mainLayout.render("title", something_else); whilst still retaining the form?
Edit3: Apparently the form is not needed at all; so long the name of the input is the same as the model's name any form will work:
#helper.form(action = routes.SearchPage.search()) {
<input type="text" name="term">
}
will work for a search term, but only as long as "term" is a public variable of the class in which we are going to store the post data.
Edit:
Currently using a method that inserts the empty form. The problem is that the Html class is not found. I have no idea where it is located.
public static Html renderMainLayout(String title, java.util.ArrayList<String> content) {
play.data.Form<Search> userForm = play.data.Form.form(Search.class);
return layout.render(title, content, userForm);
}

Related

Thymeleaf form with multiple objects of the same class

Simple problem but can't find a solution: I have a Thymeleaf form used to add a new object, say of a Book class. It works perfectly well and I only need that particular form for adding new objects, not editing the existing ones. The question is: how can I put several objects of the Book class in the same single form? So, purely for convenience, instead of filling form for a single book and clicking Send you can fill form for several books at once and only then click Send, have them all inserted into the database (in whatever order) and also have the option to fill the form partially (e.g. the form has room for 5 books but it will also accept 1, 2, 3 or 4 and you can leave the rest blank).
Edit: I've tried passing a list of object to the Thymeleaf template with the form bound to the whole list and iteration inside, but Thymeleaf throws BingingResultError upon rendering it.
You need to use a wrapper object to realize what you want.
Something like:
public class BooksCreationDto {
private List<Book> books;
// default and parameterized constructor
public void addBook(Book book) {
this.books.add(book);
}
// getter and setter
}
Then you need to pass this object as a model attribute in your controller:
BooksCreationDto booksForm = new BooksCreationDto();
model.addAttribute("form", booksForm);
bind fields using index property
th:field="*{books[__${itemStat.index}__].title}"
and get back the result with
#ModelAttribute BooksCreationDto form
in your controller.
For a complete and detailled explaination visit: https://www.baeldung.com/thymeleaf-list

Typo3 Extension PHP View

Using the infos in this link:
https://docs.typo3.org/typo3cms/ExtbaseFluidBook/8-Fluid/9-using-php-based-views.html
I try to create an action to output a JSON.
I have a normal controller with the list action:
public function listAction()
{
$storelocators = $this->storelocatorRepository->findAll();
$this->view->assign('storelocators', $storelocators);
}
And in ext/my_storelocator/Classes/View/Storelocator I have a class List.php:
<?
class Tx_MyStorelocator_View_Storelocator_List extends Tx_Extbase_MVC_View_AbstractView {
public function render() {
return 'Hello World';
}
}
All I get is:
Sorry, the requested view was not found.
The technical reason is: No template was found. View could not be resolved for action "list" in class "My\MyStorelocator\Controller\StorelocatorController".
So I guess there is something wrong with the paths. Or where is the Problem?
Edit: Extensioninfos
Vendor: My
key: my_storelocator
controller: NOT SURE (I created it with the extension_builder so I guess my controllers name is Storelocator)
action: list
From my understanding a classname like Tx_MyStorelocator_View_Storelocator_List should be correct. But its not working
You will need to create an empty file for the HTML view for your controller, e.g. Resources/Private/Template/Storelocator/List.html, even if you do not plan to use the HTML view or if you just return the content yourself (which is perfectly fine).
The reason for this is simply technical limitation.
First of all, TYPO3 now has a built-in JSON view, described thoroughly here: https://usetypo3.com/json-view.html. It lets you easily define which properties you'd like to render.
The error message means that your Controller is still pointing to the TemplateView - because thats the error the TemplateView throws if it can't find the defined template file.
You can specify which view to use to render within your controller. You can either set a default view via the $defaultViewObjectName property, like so:
/**
* #var string
*/
protected $defaultViewObjectName = '\TYPO3\CMS\Fluid\View\TemplateView';
You can also set it from within the Controller inside initialization actions like so:
public function initializeExportPDFAction(){
$this->defaultViewObjectName = 'Vendor\Extension\View\FileTransferView';
}
(I have, however, not yet found a way to define the template from within actions, any tips in the comments would be appreciated)
Your path syntax is probably out of date. Instead of writing a render() function in Classes/View/Storelocator/List.php, try writing a listAction() function in a Classes/Controller/StorelocatorController.php file. Extension Builder should have created this file for you, if you made an aggregate model with the usual "list, create, edit ..." and such actions.
Review A journey through the Blog Example and the following chapter, Creating a first extension, for tips.
Keep in mind that there is a mismatch between the documentation and the Extension Builder generated PHP code files. Developing TYPO3 Extensions with Extbase and Fluid has some parts up to date, and other parts still using old syntax.

symfony2 forms custom fields

So, I have a form for editing blog articles.
Among other things I need to be able to edit article tags. They are stored as ArrayCollection inside my Blog entity. (ManyToMany cascade: persist,remove)
Now, Simfony handles this type of data with <select> tag and it works just fine for selecting, but I want to be able to remove and add tags too.
This is also possible and is very well explained in this Cookbook article: How to Embed a Collection of Forms
However, result of this tutorial is still not very elegant and I would love to have input box similar to StackOverflow tag box.
Since there are many already done solutions under free licences I decided to just use one of them, for example jQuery Tags Input.
Basically, all I need to do is run $('#tags_input_box').tagsInput() and it transforms it into SO-like tag box.
Now, I'm searching for the easiest way to bind some custom made input to my form and submit it back together with the rest of 'genuine' fields in a shape that will be understood by Symfony2.
Could anyone refer me to some document or give me some starting info where I should begin my research on this matter ?
It appears that plugin sends it in as a comma-separated string value.
Probably the easiest way would be to simply treat it as a single input in your form, and then split it up when you process the form.
// Entity to hold it in string form.
namespace Some\Entity;
class TagStringEntity {
protected $tagString;
// getTagString and setTagString
}
// Custom form type.
// Use this AbstractType in your form.
namespace Some\Form;
Symfony\Component\Form\AbstractType;
class TagType extends AbstractType {
public buildForm(FormBuilder $builder, array $options) {
$builder->add('tagString'); // will default to text field.
}
}
// In Controller
public function displayFormAction() {
// Join the tags into a single string.
$tagString = implode(',', $article->getTags()); // assuming it returns an array of strings.
$tagStringType = new TagStringType();
$tagStringType->setTagString($tagString);
// build form, etc...
}
public function checkFormAction() {
// ...
if ($form->isValid()) {
// Get the tag string, split it, and manually create your separated tag objects to store.
}
}
That's probably the cleanest and simplest way to do it using that jQuery plugin. Takes a bit of working around since you are turning multiple items into many and vice versa, but not too bad.

How to validate and post data from dynamic form in ASP.NET MVC 2

I have an existing ASP.NET MVC 2 application that I've been asked to extend. I am adding a new feature to the site where I generate an employee assessment form based on a dynamic list of questions retrieved from our HR system. I have everything working with the exception of validation and posting the responses back to the site. Here's some details:
I retrieve a list of "Questions" from our back-end system via a web service call.
Each "Question" contains the text to display as well as the following settings:
The question Type (corresponds to textbox, textarea, radio button list or checkbox list)
If comments are allowed
If an answer is required
When applicable, the list of possible responses
To generate the form, I use a for-each loop over the list of Questions. I use the value of the QuestionType property to determine which partial view to render (one for each of the types). For example, if QuestionType == SingleChoice, that partial renders the choices as a radio button list. If comments are allowed for the question, I also render an additional textarea field to hold the user's comments.
As I said, rendering the form is working fine but now I need to:
A. Enforce when an answer is required. I'm using DataAnnotations for validation everywhere else in the solution but since I'm not working against a static model, I don't see how I can do that.
B. Post the results back to the site. For each question, there can be text entered into a textbox or textarea, a selected value for a radio button list or multiple selected values for a checkbox list. Plus, each question could also have additional text sent back in the form of a comment.
All of the examples that I've seen working with dynamic "lists" are only concerned with posting a single value for each field and it is always the same type (e.g. a list of textboxes). With the variations I have to support, plus the need to send back the entered/selected value(s) and a comment for each question, I'm stumped.
Any guidance is appreciated.
I've just finished completing exactly the same task.
I chose to write a custom model binder for my dynamic form object. The model binder pulled out a bunch of prefixed form keys for hidden fields which contained some delimited meta data about the question (i.e IsRequired, QuestionType, QuestionId etc etc)
I'm using MVC3 but I think this should all work in MVC2.
I created a ModelBinder like:
public class DynamicFormModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Create the object to be bound to (I had a kind of form object
// with a simple list of answer objects
DynamicForm form = new DynamicForm(new List<Answer>());
HttpRequestBase request = controllerContext.HttpContext.Request;
var keys = request.Form.AllKeys.Where(k => k.StartsWith("MyFormsKeyPrefix_Meta_"));
foreach (var key in keys)
{
// Loop over each question's meta data. Metadata will always be present
// even if the user hasn't selected an answer as it's a hidden field
// TODO: Split the meta data and pull out IsRequired, QuestionType etc
// TODO: Get all the posted form values for the question (these values
// will come from textboxes, dropdowns, checkboxes etc)
// Use a prefix like: MyFormsKeyPrefix_Answer_{QuestionId}
// textboxes & dropdowns will only ever have one value
// but checkboxes could have multiple
// TODO: If it's a mandatory question then ensure there is at least
// one posted value that is not an empty string
// If there is a validation error then add it to the model state
bindingContext.ModelState.AddModelError(key, "Field is required");
foreach(var answerHtmlName in answerHtmlNames)
{
// TODO: Loop over each posted answer and create some kind of nice
// Answer object which holds the QuestionId, AnswerId, AnswerOptionId
// and Value etc.
// Add the answer to the forms answers list
form.Answers.Add(answer);
}
}
return form;
}
}
I register the ModelBinder in Global.asax using the following:
ModelBinders.Binders.Add(typeof(DynamicForm), new DynamicFormModelBinder());
So, the action method that recieves the form post looks something like:
public ActionResult ProcessForm(DynamicForm form) {
if(ModelState.IsValid)
{
DynamicFormService.Process(form);
return RedirectToAction("TheHttpGetAction");
}
return TheHttpGetAction();
}

Loading models in Zend_Form using Zend Framework

I'm trying to build a form using the Zend_Form component, but the number of elements varies. The information for each Zend_Form element is stored in a database (name, options, validators, filters, etc.).
The application I'm working on consists of building surveys which contain a varying number of questions. Each question is associated with different arrays of answers. Ultimately my goal is to build arrays of radio/checkbox buttons, dynamically, server-side.
I'm looking for a pretty way to generate my form, but I'm not sure of the best way to load the model within the form. Should the model be loaded in the controller then passed (somehow, via a parameter?) directly to the form, or is it better to load the model within the Form init() method? Where's the best place to put the logic, should it be within the form class, or within the controller, or within the model?
My idea is to fetch form element properties (name, rules, filters, etc.) in the database, then iterate and finally render the form. What do you think of this approach? Ultimately, elements will be dynamically added (client-side), this time, using AJAX and a JavaScript library (such as jQuery).
Here are a couple useful links I found via Google, but I think they all answer a slightly different question than mine:
On building dynamic forms, server side:
http://framework.zend.com/wiki/display/ZFPROP/Zend_Form+generation+from+models+-+Jani+Hartikainen
http://weierophinney.net/matthew/archives/200-Using-Zend_Form-in-Your-Models.html
http://codeutopia.net/blog/2009/01/07/another-idea-for-using-models-with-forms/
On building dynamic forms, client side, with AJAX processing:
http://www.jeremykendall.net/2009/01/19/dynamically-adding-elements-to-zend-form/
I think I found a possible solution, it involves passing an array of Zend Form elements to the Zend Form::__construct() method. The constructor takes an array of options, one of them is called "elements". Have a look at the source code within the Zend Framework library.
I coded a new private method within the controller, called buildSurveyForm(). Note : the object, passed as a parameter, is built from a huge SQL query with half a dozen JOIN statements, fetching data from a few tables (surveys, questions, answers, etc.) within the database. One of the public attributes for this class consists of an array of questions, stored as objects (with public methods/attributes as well, etc.). Same for answers. The code for building these classes is pretty trivial and out of topic here.
Here's the code within the survey controller. I copy/pasted and edited/dropped a few lines to make it a lot clearer :
private function buildSurveyForm(MyApp_Object_Survey $survey)
{
foreach ($survey->questions as $question)
{
$element = new Zend_Form_Element_MultiCheckbox($question->order);
$element->addMultiOptions($question->getAnswersLabels());
$element->setName($question->order);
$element->setLabel($question->title);
$elements[] = $element;
}
// Here's the trick :
$formOptions = array('elements' => $elements);
$surveyForm = new MyApp_Survey_Form($formOptions);
$urlHelper = $this->_helper->getHelper('url');
$surveyForm->setAction($urlHelper->url(array(
'controller' => 'survey',
'action' => 'vote'),
'default'
));
$surveyForm->setMethod('post');
$this->_forms['survey'] = $surveyForm;
return $this->_forms['survey'];
}
The MyApp Survey Form class only contains a Submit button within the init() method. The dynamically generated elements with the code above are added BEFORE this submit button (which is unexpected, but useful). This class simply extends Zend_Form.
Then, within survey controller / view action :
public function viewAction()
{
$surveyModel = $this->_model['survey'];
$survey = $surveyModel->getFullSurvey($this->_getParam('id'));
$survey = new MyApp_Object_Survey($survey);
// Calls above private method :
$surveyForm = $this->buildSurveyForm($survey);
$this->view->assign(array(
'surveyForm' => $surveyForm,
));
}
Adding filters, validators and decorators to form elements is now trivial. My proposal is a bit dirty, but I think it gets the job done. I will add a new proposal if I find something more elegant. Feel free to post different answers/solutions.
You could extend Zend_Form.
Zend form is not good place for logic, only form representation.
So, Load all needed elements using model in controller and pass them to the form in contructor as parameters.