I have this crowded form with some 30-40 fields, and most of them have kinda complex logic. Understandibly I wanted to make these form areas reusable for both create and edit pages since both are identical in terms of form items and fields. I got them to work without much effort, and they work fine for most parts, except the quest for reusability introduced some other challenges and now I am questioning if it's worth it.
For me some of the challenges of using the same forms for both create and edit are:
Conditionals everywhere. Want to make a field uneditable in edit mode? Extra props to pass in and disable said fields with those props.
Edit mode needs initial state so forms fields are filled in with existing data but create page does not like that, so even more and even worse conditions like:
const { user } = React.useContext(DetailContext) ?? {}; // I know...
const [userType, setUserType] = useState(user?.user_type ?? null); // yep
At this point I can't even decide how to safely assign and use stuff, and I can't estimate what parts are prone to breaking.
Is this inevitable and fine as is or is this complete silliness? What are some good practices for making form areas or forms reusable? Can I reduce noise without sacrificing reusability?
The question is indeed kind of broad but a general solution might still help you. There are a couple of main points you need to consider:
Are all the fields present in both edit and create mode or there might be situations where not all of them are included in either?
Are there fields that are supplied on creation but cannot be edited after that(in edit mode)?
Are there initial values for any of the creation form fields?
I would tackle the problem in the following manner:
You'll have a single form component which accept field properties as parameter(component props). For each field you supply the following information:
Initial value, if any (initialValue)
If the field should be present in the form at all (isDisplayed)
If the field should be present but disabled (isDisabled)
This way you cover all of the previously mentioned points while keeping a single form component. Also, you'll supply a parameter like mode with possible values edit/create which guides the form logic and how the form submit would be handled(difference in handling logic, different endpoints and such). Then, in your form component you'll have to do some checks based on the provided parameters i.e. should the given form input be disabled if isDisabled is true or if it should be displayed at all - isDisplayed.
It's not a perfect solution, but it is flexible enough to enable you to use the same form template and share most of the handling logic. If, however, you have vast differences in how the edit/create forms are structured, you might be better off to duplicate some logic by introducing two separate components but save your sanity and time figuring out how to cover and abstract every single new extenstion you want to introduce in one of them.
I'm on just a bit of a journey here. I can create server controls, validation controls, custom validators, etc. and add them to a page. What I'm curious about is if it's possible to hoist a custom validator 100% client-side without the use of <asp:________Validator />.
For example, if I simply placed a:
<span id="some_custom_id">* REQUIRED!</span>
Is it possible to wire that in the global/window object as a validator?
For example, on the window object you can see the collection of validators via:
> Page_Validators
>> Array[2]
>>> 0: span#someid
>>> 1: span#anotherid
>>>>>>: controltovalidate: "idofthecontrol"
>>>>>>: validationGroup: "validationGroupOfControl"
>>>>>>: evaluationfunction: RequiredFieldValidatorEvaluateIsValid(val)
My reasons are for a deeper understanding of how asp.net is creating the client-side validation. I've generated a custom validation object and pushed it to the array of validators, but it breaks nearly everything else in the validation. I'm also wondering if the asp.net scripts are being dynamically generated to handle/house the functions for different types of validations - as in I can't rely or assume that the appropriate validation methods will be available for me to just tie into.
It would be cool to push these validators/messages to the validation summary control. I understand server-side validation is needed, but that isn't the point of the question.
Another way to look at this is creating a dynamic set of form fields with JavaScript, all on the client, or swapping out, changing what's required and what's not based on selections, all of which ties into the validation summary.
I can do this with plenty of workarounds, and piggy back the Page_Validate method, but it doesn't feel optimal. As in I can create custom validation methods and intercept the form submission... no problem. I just want to find a way to properly manipulate the page validators on the global object and keep everything simplified.
Since I'm monkeying around in new lands, I'm more interested in if anyone has done this, is it reasonably possible, and perhaps pointing me in the right direction.
I'm using play framework 2 with scala. How can I implement user validation on scala template engine? I need something like captcha (I've heard that google recaptcha is a good choice) to validate that the user is a human not a bot.
As I said, I'm using play and thats why all my POST/GET functions are documented in routes file. So, if the user passes validation what method should I call? For example there is a form with field 'Name'. The user passes the validation and he calls something like
POST /create/:name
to call Scala some method for creating post. The problem is that everyone can call it just by url without passing the validation.
So as a solution I see two ways: to use javascript API to call Scala method or to pass some "validation token" that will be used as a key to check on server if user has passed validation or not. Can you tell me some general validation patterns used for frontend
Update:
I have tried Google's recaptcha, but I'm confused of using provided public-private keys, I want to generate them by myself. Thats why I want to look at other possible solutions of my problem.
I have used recaptcha and it is okay. Later I will implement my own captcha mechanism.
Thanks, Sergei.
I am currently working on a project using Symfony2 and seeking some advice on that.
I am thinking of a hybrid application in two(2) different ways a) Login Page shall use traditional form with CRF Token and let symfonty2 handle it. b) All Inner pages ( which potentially are modules ) I want them to be non AJAX, but the other activities inside that shall behave like a Single Page.
For example I have an employee module. When user clicks on that it is entirely loaded from Server ( all the templates and forms etc ) now each activity under employee module like add/update delete/view etc shall be loaded through AJAX and response to be returned in JSON i.e AngularJS.
I am currently thinking of using FOSUserBundle to return html on initial request and then based on request type Accept: application/json it will return the JSON ( remember the add/updat delete/view part? ).
My question is it a better idea to use Angular Partials (html) files or Symfony2 Twig? or would it be better to use Angular JS, but let those partials be rendered by Symfony2 twig? ( I am thinking of Forms here, would want to validate that both from client and server side )
Has any one been through similar problem, if yes then what approach was used to develop HYBRID application using AngularJS and Symfony2 or any other framework? any relevant ideas are appreciated.
I was in the same situation you are. AngularJS+Symfony2 project, REST API, login using FOSUserBundle, etc.
... And every way has pros and cons, so there is no right way, i'm just gonna say exactly what i did.
I choose AngularJS native templates, no CSRF validation, a base template built using Twig, server-side validation, use of the FOSJSRoutingBundle, and some helpers (BuiltResponse and BaseController).
Why native templates?
With the use of verbatim, we solve the variable problems, but we gonna have a more complex logic in our templates.
We also will have a less scalable application. All our forms templates are doing a request in the Symfony application, and one of the best pros of the AngularJS is load our controllers, templates, etc from a storage service, like S3, or CDN, like Cloudfront. As there is no server-side processing, our templates would load so much faster. Even with caching, Twig is slower, obviously.
And both, Twig and AngularJS templates, are really complex to manage, in my own experience. I started making them together, but was painful to manage.
What i did?
I created static templates in front-end, with the same field names, it's not really good. We need to update the templates every time we update the forms, manually. But was the best way i found. As the field names are equal, we won't have problems to ajust the model names in the Angular controllers.
And if you are creating the software as a service, you will need to do it anyway. Will you not load the form templates from the application in a mobile app, right?
Why no CSRF validation?
We don't use CSRF validation in a REST API, obviously. But, if you wanna do it, you need to make a request every time you load a form, to get the CSRF token. It's really, really bad. So, we create a CRUD, and also we need to create a "csrf-CRUD", 4 routes more. That doesn't make any sense.
What i did?
I disabled the CSRF in the forms.
Base template?!
Yep. A base template is just to load any route in our application. Here is what i'm doing:
This will help us to avoid errors when users are going directly to some Application URL if you are using html5 angularjs urls. Simple like that.
Server-side validation, why?
If we do a validation in the Angular, we need to do the same in the server-side, so we have 2 validation codes to maintain. That is painful. Every change we do in the form, we need to change the validation in the front, validation in the back and also the Angular static form. Really, really painful.
What i did?
I basically did a server-side validation using the Symfony constraints. For every request, the application validates the form and check if any error was found, if yes, it gets the first one and send it as a response.
In the AngularJS, the application checks if there is any error inside of the errors key. So, we have a proccess used in all application to do any form request. It's like that:
And the routes?
There is another problem: the routes. Put the url directly is not a reliable way. If we change anything in the url, that route is gone and the users won't like that.
To fix that, we can use the FOSJsRoutingBundle. With that library, we can put the route name directly in the Angular controller, and it will fill with the exact url of the route. It's completely integrated with the Symfony, so parameters will work very well.
Instead using the url directly, we can do it:
Routing.generate('panel_products_show', {id: $routeParams.product_id});
And voilá! We get the route url.
That will solve the biggest part of the problems you have. But there are more.
Problem 1 - Form inputs
The forms from Symfony generally have a prefix, like "publish_product", so every field has a name like [publish_product]name. Ah, how that was a problem for me.
In the Angular, publish_product is not considered a array. You need to put the single quote to do this, like ['publish_product']name. And it's really bad, we need to change every key to use this format. In AngularJS, i was doing like that:
{{ formData('[publish_product]name') }}
Absolutely stupid.
The best solution was simply remove the form prefix in the Symfony, using the createNamedBuilder method instead just createBuilder. I let the first parameter null, and yeah, we don't need to use the prefix anymore. Now, we use:
{{ formData.name }}
So much better.
Problem 2 - Routes hard do maintain
Every request can return anything, i need to repeat much code. That is really hard to maintain, so i just create some application rules, built responses, a BaseController, etc.
createNamedBuilder
createNamedBuilder is a big method. We need to do this, for every form we have:
It's simple to solve. I just created a BaseController and i'm extending every controller from it. I created a simple method that does it.
For every route, we do not need to repeat 3 lines, much better.
Responses
When my application started growing, i had a serious problem: all my responses are different. That was really hard to maintain. For every request i was doing, sometimes i was using "response", sometimes "data", the error messages were lost in the response, etc.
So, i decided to create a buildResponse, that i just need to set some parameters and i get the same result for every route, even GET routes.
response key shows me the status and the message. It can be error or success, and the message os a optional field, that can come blank. For example, a success status with the message "You created the product".
data key shows me any information i need. For example, the user added the product, and now he needs the link to see it. In the data, i put the url of the post, and i easily can get it from the AngularJS controller.
notifications is a specific key for my business logic. Every action can return a notification to the user.
It doesn't matter what keys you have. The most important thing is have a standardized response, because when your application grows, it will be really helpful.
That is a route from my controller:
Completely standardized. The Scrutinizer code quality tool says all my routes are duplicated. :D
Have a BaseController and a builtResponse will help you so much. When i started refactoring my code, each route lost about 4-10 lines.
Details: getFormError return the first error of the form. Here is my method:
public function getFormError(FormInterface $form)
{
if ($form->getErrors()->current()) {
return $form->getErrors()->current()->getMessage();
}
return 'errors.unknown';
}
... And the parameters from the buildResponse are:
1. Status. I get it from a constant in the BaseController. It can be changed, so i believe is important do not use a string value in each route.
2. The translation message. (I use a preg_match to check if it has a translation format, because getFormError already translates the error).
3. The data (array) parameter.
4. The notifications (array) parameter.
Other problem i'm gonna have
The project just have one supported language until now. When i start to work in a multilingual version, i'm gonna have another big problem: maintain 2 versions of the translations: the back-end messages and validations and the text from the front-end. That probably will be a big problem. When i get the best approach, i'll update this answer.
I took some months to get the this approach. So many code refactorings and probaly much more in the future. So i hope it help someone to do not need to do the same.
1. If i get a better way to do this, i'll update this answer.
2. I'm not good at writing english, so this answer probably will have many grammatical errors. Sorry, i'm fixing what i'm seeing.
The question is related to validating/catching the data before the binding update, in a manner that you can implement validation. Does anyone have any examples that are a generic type implementation, not specific of doing something in a similar manner? I know there are many ways to probably handle this, but I do not want to have to write validation for specific instances. To give a brief understanding, we are using ketchup plugin along side with jsviews, and some custom validation methods. I appreciate the response I have already received, but changed the manner I was asking the question, to maybe get some other responses.
Thanks in advance!
I mentioned in the comment above that there would be some samples related to validation. Here are the links:
A JsViews "validate" tag control
Generic edit control - the base class for the validate control
Datepicker with validation
Datepicker with validation (wizard) (How to use the validation group control in association with stepping through a wizard. Happens to use the datepicker in this example)