Adding validation property attributes in views with Html.EditorFor() methods not inside a Html.BegingForm() method - asp.net-mvc-3

I have noticed that validation attributes are only added to the elements that were created via Html.EditorFor() helper method and which are inside a Html.BegingForm() method, that respectively creates the "Form" tag and attributes.
Is there any way, besides manually creating the elements and attributes of course to add the required validation attributes to elements created with helper methods and which are not inside the Html.BegingForm() method ?
I need to validate at the client side and don't want to manually either create said attributes or script this behavior explicitly and instead take advantage of the MVC feature that adds said attributes automatically as per metadata on the model for use with the jquery-validate plugin at the client-side.

The unobtrusive validation attributes emitted only if:
the UnobtrusiveJavaScriptEnabled flag is set to true
the ViewContext.FormContext is not null (e.g the Html helper is executed inside a Html.BeginForm block)
So you can manually create a FormContext and assign it to ViewContext.FormContext before using your Html helpers:
#{
ViewContext.FormContext = new FormContext();
}
#Html.TextBoxFor(x => x.SomeProperty)
However you should note that with this approach you lose the from nesting feature of Html.BeginForm so if you want to create a new logical form you need to again create new FormContext() and manage the old context yourself.

Related

Replace Orbeon Form with a new one asynchronously via AJAX

I am using Orbeon forms with Hybris. We have several pages linked together where a user needs to go through them in a sequence (checkout process).
The content of the Orbeon form is dynamically being determined based on actions from previous steps. E.g.
If user adds Product A to the cart on the step 1, only two fields will be visible on the form located on step 2, if he adds another (Product B) on step 1, one more field should be visible on the form.
I am using certain preprocessor class which prefills some of the hidden fields on the form and then the logic for dynamic display is on the Form itself, based on those hidden fields. This works in a simple scenario when moving back and forth, through the steps.
However, the problem is that I need to have a HTML Mini-cart displayed on the page as well (not part of Orbeon Form), which can also trigger adding/removing of the products asynchronously.
So while I am on step 2 where the form is displayed, the user can also remove/re-add some of the products -> therefore, this needs to trigger asynchronous re-rendering of the form and change the display of the form (with new fields added or removed).
I'm using AJAX for this async stuff and the problem I am facing is that a lot of Orbeon-specific Javascript files and variables is being generated when the page loads for the first time, and some random FormID is used. This FormID is different when I retrieve the new form from the back-end and when trying to replace the HTML content I'm getting various errors in the console, because old Form id is used all over the place.
Does anyone have any suggestion if this could be achieved and how to approach this problem?
Update: Example of "hidden" field glass-coverage-selected
<xf:instance id=""fr-form-instance"" xxf:exclude-result-prefixes=""#all"">
<form>
<glass-coverage-selected/>
<section-1>
<massive-exterior-walls/>
</section-1>
...
Later, a bind is created:
<xf:bind id=""section-40-bind"" ref=""section-40"" name=""section-40"" relevant=""instance('fr-form-instance')/glass-coverage-selected = 'yes'"">
<xf:bind id=""previous-glass-insurance-bind"" ref=""previous-glass-insurance"" name=""previous-glass-insurance"">
<xf:required id=""validation-156-validation"" value=""true()""/>
</xf:bind>
And that bind is used to control the visibility of certain section:
<fr:section id=""section-40-control"" bind=""section-40-bind"">
<xf:label ref=""$form-resources/section-40/label""/>
<fr:grid>
<xh:tr>
<xh:td>
<xf:select1 id=""previous-glass-insurance-control"" appearance=""full"" bind=""previous-glass-insurance-bind"" class=""previous-insurance"">
<xf:label ref=""$form-resources/previous-glass-insurance/label""/>
<xf:hint ref=""$form-resources/previous-glass-insurance/hint""/>
<xf:help ref=""$form-resources/previous-glass-insurance/help""/>
<xf:alert ref=""$form-resources/previous-glass-insurance/alert[1]"" validation=""validation-156-validation""/>
<xf:alert ref=""$form-resources/previous-glass-insurance/alert[2]""/>
<xf:itemset ref=""$form-resources/previous-glass-insurance/item"">
<xf:label ref=""label""/>
<xf:value ref=""value""/>
<xf:hint ref=""hint""/>
</xf:itemset>
</xf:select1>
</xh:td>
</xh:tr>
</fr:grid>
</fr:section>
You can manipulate the values of form fields in JavaScript, in the browser. If you want to set the value of "hidden fields", you make sure that those fields as not hidden by putting false() under Visibility for the field in Form Builder. If you do this, for security reasons, the value of the field isn't even sent to the browser by Orbeon Forms, and it can't be set from JavaScript. Instead, to be able to set the value from JavaScript, you need to hide the control with CSS. The simplest way to do this is to add the class xforms-disabled for that field in the Control Settings dialog.
Then, assuming the name of the control in Form Builder is my-control, in JavaScript you can write var control = ORBEON.jQuery('*[id $= "my-control-control"]'); ORBEON.xforms.Document.setValue(control.attr('id'), '42');. Note the -control added at the end of the name of the control. And to test this first, I recommend you don't put the CSS class, so you can more easily see if setting the value works.
For the documentation on the above setValue() and other JavaScript APIs, see the page Client-side JavaScript API.

dojox mvc at() target

I've created a sandbox with a demonstration of binding UI components to both data and state: http://dojo-sandbox.net/public/51073/1
It's my plan to generate code from a page definition creating a page-level widget which is templated. This widget will have its own scope, where the model and state will reside, which I am trying to simulate in the sandbox by way of the Page object.
The sandbox is working because the Page object is in the global state, which appears to be the default context for object resolution in mvc binding.
However the plan is to have a view widget supporting each page with both the Model and State contained within the widget's scope. The generated template for the view would be bound to both the Model and the State. I can establish the source via the 'target' property, but when the same UI component must be bound to two different models, one for value and one for state, the single source doesn't support this.
The Model data will come to me from the back-end, and the State data is derived via the State.Execute method once the Model data is present.
I've taken a look at the 'rel:' parameter of at(), but don't see how to leverage this syntax within a specific context, ie my view widget's scope. It seems to be working fine for the default global scope.
Is there a standard way to direct the data-dojo-props value binding at one source, and the data-mvc-bindings for attributes at another? Or, more precisely, what is the at('rel:') syntax which will support specifying the context of the relation, and not rely on the 'target' of the widget or containing widget?
If there is no way to specify the 'target' at this level, I will generate more logic in the Execute method to specifically set the html attribute on the component during state compilation.
data-mvc-bindings is for allowing non-widgets use dojox/mvc/at. If a widget is declared for an element data-dojo-props is the one for use instead.
If target is specified via data-dojo-props or data-mvc-bindings, it’ll be set eventually to the widget.target. ”rel:” syntax looks for a widget having .target up in DOM tree.
It means that one “group” cannot have more than one "relative binding target”, in case it’s one of your questions. You can have a “scope object” that contains pointers to more than one models and use it as a “relative binding target”, that may serve a similar purpose:
<div data-dojo-type="dijit/_WidgetBase"
data-dojo-props="target: {model0: model0, model1: model1}">
<input type="text"
data-dojo-type="dijit/form/TextBox"
data-dojo-props="value: at('rel:model0', 'value'),
disabled: at('rel:model1', 'disabled')" />
</div>
A working example can be found at http://jsfiddle.net/asudoh/M3bRC/. Hope these help.
Best, - Akira

Why unobtrusive validation wont work in asp.net mvc3 without using #Html.BeginForm()

To make unobtrusive validation work in asp.net mvc3 you have to use the html helper #Html.BeginForm() as mentioned in this very good post : http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-validation.html.
Without using the helper unobtrusive validation will not be triggered. I could verify that.
Can you explain me what does the helper #Html.BeginForm() do to allow unobtrusive validation to be triggered when the form is submitted ?
Can you also explain me how could I do that manually (read allow unobtrusive validation without calling the #Html.BeginForm()) ?
Please note that I know I can call unobtrusive validation using $("#myform").valid() but I would like to know the magic behind the helper and how to reproduce it.
When you call BeginForm (see http://j.mp/WrmAyk for the FormExtensionsclass), a new MvcForm object is created.
If you look in the constructor of this class (see http://j.mp/Wrml6F for the MvcForm class) you will see that it creates a new FormContext object: _viewContext.FormContext = new FormContext();.
When an input, textarea or select is rendered using the HTML helper, the following is called: tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata));, which takes care of rendering the validation attributes from the model metadata.
This GetUnobtrusiveValidationAttributes method (see http://j.mp/Wrn4oa for the HtmlHelper class) checks to see if the FormContext is null before rendering attributes:
FormContext formContext = ViewContext.GetFormContextForClientValidation();
if (formContext == null)
{
return results;
}
This is why no validation attributes are rendered unless you are within a form. You can get round this by creating a 'fake' FormContext, like #karaxuna suggests.
Write this in your view and it will work:
ViewContext.FormContext = ViewContext.FormContext ?? new FormContext();
When code is inside #Html.Beginform (in the same view), then html element validation attributes are got from metadata, In other case, it is not.

ASP.NET MVC Validate dynamic form elements

I want to add the ability to build a form in my app. The user adds input fields to the form in the UI of my app, and for each form element she can specify data-type.
I use ASP.NET MVC 3, and want to use as much as I can of the validation mechanism supported by the frameworks. For my own forms in the app, I decorate each ViewModel with dataannotations to and use client validation.
Is there any way I can add those annotations to a dynamic ViewModel?
It's fine to use e.g. #Html.TextBox("name"), but how do I mimic the data annotations, so that jQuery Validate and the unobtrusive plugin picks them up correctly?
Have you tried adding the data-dash-attributes like this? (Hint: Use an underscore instead of the dash, it will be translated to a dash in the according attribute)
#HtmlTextBox("name", new { data_... = "some value", data_... = "some value" })

set every single form readonly without using widgets in the model

I am trying to build a template with some forms. I have a model with about 400 attributes for one entity. Now i want to make two different templates. In one Template the attributes should be listed like django form do. In the other template the attributes should be set readonly.
I don't want to create two diffent Forms for every attribute by using widgets.
cust_form = GeneralDataForm(instance=_customer, auto_id=False, label_suffix='')
I tried inserting the widget here but it doesn't work.
using this code you can make any form readonly. are you looking for something like this?
cust_form_read_only = make_form_readonly(cust_form)
def make_form_readonly(form):
for name, field in form.fields.items():
field.widget.attrs['readonly'] = True
field.widget.attrs['disabled'] = True
return form

Resources