Pass Apex method parameter value with Visualforce 'apex:actionSupport' - apex-code

Can anyone please tell me how can I pass Apex method parameter value with Visualforce 'apex:actionSupport'.
Apex code:
public void renderField(String sampleType) { }
Visualforce code:
<apex:inputField id="sampleType" value="{!job.Sample_Type__c}">
<apex:actionSupport event="onchange" action="{!renderField(?)}" rerender="otherSampleType"/>
</apex:inputField>

Action methods don't support passing arguments like that. Instead, you just have to bind VF components to controller properties. In your case, it looks like you may be wanting to get the value of the "sampleType" inputField. If so, you just need a controller property that holds a reference to the "Job". Assuming the type is Job__c, this declaration on the controller would work:
public Job__c Job { get; set; }
When your actionSupport fires, Job.Sample_Type__c will be populated from the inputField.

Related

Enum unbinds from the model on ajax call

I am reading an enum value from the db then bind it to the model. When i post the form with ajax, somehow the enum is unbound or the model property in null or zero but it display properly on the view. I have posted code below. Im using entityframework and mvc3
//model code constructor
public CarModel(Car car)
{
State=(CarState)car.State;
//car.State comes in as an int
//etc setting other variables
}
//CarState property
public CarState {get;set;}
//model code
#Html.DisplayFor(m=>m.CarState)
//Controller code()
Save(CarModel car)
{
//I have code that saves the changes
}
The minute i get to "car", CarState has no value.
It's not quite clear how you are passing this value to the controller action. You have only shown some #Html.DisplayFor(m=>m.CarState) but obviously this only displays a label in the view. It doesn't send anything back to the server. If you want to send some value back you will have to use an input field inside the form.
For example:
#Html.EditorFor(m => m.CarState)
or use a HiddenFor field if you don't want the user to edit it.
In any case you need to send that value to the server if you expect the model binder to be able to retrieve it. The model binder is not a magician. He cannot invent values. He binds values to your model from the Request.

Play Framework: automatic validation of controller methods applied?

I have some issue with validation of parameters passed to a controller method.
Following the suggestion from the tutorial, I am using the same controller method for "save" and "create new" of an entity. See example in
http://www.playframework.org/documentation/1.2.4/guide9
So, my controller method looks like:
public static void saveEntity(long l, Long itemId,
#Required(message="error.shouldspecifyname") String name,
#Required(message="error.shouldspecifycategory") String category)
If 'itemId' is not part of the data sent via an HTTP request - it is supposed to be set to 'null'.
Unfortunately, it seems like "Play" is automatically adding a validation error on the "missing" parameter.
When looking into the validation errors' list, every time 'itemId' is 'null' - I am getting an error Incorrect value for field itemId
Is it a documented behavior? Any way to override it, or "get rid" of the error.
I am handling the errors simply using redirection, like:
if(validation.hasErrors() )
{
validation.keep();
showSomePage();
}
So the errors are displayed "out of the context" they get generated. This is the reason the "automatic" error bothers me.
Thanks for any hint.
Most likely it fails to validate itemId because it's declared as Long, are you sure you have "Long" there ant not just "long"? We are using validation with controllers every where and it works with #Required and passed "null" to "Long" values.
Worst case you can remove error from validation object based on "itemId" key, also if you're using controller to save model object, you might want to use:
public static void saveEntity(#Required #Valid MyEntity entity) {
if(validation.hasErrors() ) {
validation.keep();
showSomePage();
}
entity.save();
}
It will automaticly hook your changes inside existing entity if you pass ID from page with:
<input type="hidden" name="myEntity.id" value="${myEntity.id}">

What, exactly, does a modelbinder do? How to use it effectively?

I was researching something and came across this blog post at buildstarted.com about model binders. It actually works pretty darn well for my purposes but I am not sure exactly whats going on behind the scenes. What I did was create a custom ModelBinder called USerModelBinder:
public class UserModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult value = bindingContext.ValueProvider.GetValue("id");
MyEntities db = new MyEntities();
User user = db.Users.SingleOrDefault(u => u.UserName == value.AttemptedValue);
return user;
}
}
Then in my Global.asax.cs I have:
ModelBinders.Binders.Add(typeof(User), new UserModelBinder());
My understanding is that using the model binder allows me to NOT have to use the following lines in every controller action that involves a "User". So instead of passing in an "id" to the action, the modelbinder intercepts the id, fetches the correct "item"(User in my case) and forwards it to the action for processing.
MyEntities db = new MyEntities();
User user = db.Users.SingleOrDefault(u => u.UserName == value.AttemptedValue);
I also tried using an annotation on my User class instead of using the line in Global.asax.cs:
[ModelBinder(typeof(UserModelBinder))]
public partial class User
{
}
I'm not looking for a 30 page white paper but I have no idea how the model binder does what it does. I just want to understand what happens from when a request is made to the time it is served. All this stuff "just working" is not acceptable to me, lol. Also, is there any difference between using the annotation versus adding it in Global.asax.cs? They seem to work the same in my testing but are there any gotchas?
Usually the Model Binder (in MVC) looks at you Action method and sees what it requires (as in, the objects types). It then tries to find the values from the HTTP Request (values in the HTTP Form, QueryString, Json and maybe other places such as cookies etc. using ValueProviders). It then creates a new object with the parameters that it retrieves.
IMO What you've done is not really "model binding". In the sense that you've just read the id and fetched the object from the DB.
example of usual model binding:
// class
public class SomeClass
{
public int PropA {get;set;}
public string PropB {get;set;}
}
// action
public ActionResult AddSomeClass(SomeClass classToBind)
{
// implementation
}
// pseudo html
<form action="">
<input name="PropA" type="text" />
<input name="PropB" type="text" />
</form>
if you post a form that contains the correct values (lets say you post a form with PropA and PropB ) the model binder can identify that you've sent those values in the form and build a SomeClass object.
If you really want to create a real working example you should use a strongly typed View and use HtmlHelper's EditorFor (or EditorForModel) to create all the correct names that MVC needs.
--
for reference MVC's default binder is the DefaultModelBinder, and some (there are more, you can look around in the System.Web.Mvc namespace) ValueProviders that it uses by default are the FormValueProvider and the QueryStringValueProvider
So, as I already said, how this basically works is that the default model binder reads the model that the action is recieving (say SomeClass in the example) reads what are the values that it can read (say PropA and PropB) and asks the ValueProviders for the correct values for the properties.
Also, if I recall correctly, you can also see the value providers in runtime using the ValueProviderFactories static class.
A ModelBinder looks at the arguments of the selected Controller action's method signature, then converts the values from the ValueProviders into those arguments.
This happens when the ControllerActionInvoker invokes the action associated with the ControllerContext, because the Controller's Execute() method told it to.
For more about the ASP.NET MVC execution process, see Understanding the MVC Application Execution Process

IValidatableObject and Nullable value types

I have a struct that implements IValidatableObject, which I use for properties on a view model. The validation works fine with non-nullable properties, but if add a property of type Nullable<MyStruct> the IValidatableObject.Validate method is never called for that property, even if it has a value.
Is there any way that I trigger the validation on my nullable properties too, or is IValidatableObject not intended to be used with value types?
Thanks
Additional information:
I wanted to be able to specify units when entering data in my form, e.g. 10m, 100km, 1cm etc. I also wanted to validate that the entered data was within range and of a correct format. My struct converts the string with potentially different units (100cm/100m/1km) into a decimal property which always has the same unit (1/100/1000) and vice-versa.
I used IValidatableObject for validation because the validation will always be the same for any instance of MyStruct - I didn't want to add an attribute each time it is used.
My model would look something like this:
public class MyModel
{
public MyStruct Ab {get; set;}
public MyStruct? Cd {get; set;}
}
My view is a strongly typed view using the model, which renders my struct as a text box using a display template. When the form is posted, I have a custom model binder to convert the entered string back to my struct.
My controller action looks like:
public ActionResult MyAction(MyModel model)
{
//do stuff
}
The model is bound ok for properties of type MyStruct and Nullable<MyStruct>.
It seems that this is not possible.
I dug into the MVC source. In System.Web.Mvc.DataAnnotationsModelValidatorProvider there is the following code:
// Produce a validator if the type supports IValidatableObject
if (typeof(IValidatableObject).IsAssignableFrom(metadata.ModelType)) {
//stuff
}
According to this rejected bug report, Nullable<T> cannot be assigned to an interface that T implements:
"In short, a "DateTime?" value can be unboxed to a DateTime or an IFormattable value. But it cannot be assigned to a DateTime or IFormattable location."
Thus no validators are returned.
Looks like I will have to do this another way.

Need to allow an action method string parameter to have markup bound to it

I have an action method that takes in a string as its only parameter. The action method transforms it, and returns the result back to the client (this is done on an ajax call). I need to allow markup in the string value. In the past, I've done this by decorating the property on my model with [AllowHtml], but that attribute cannot be used on a parameter and the AllowHtmlAttribute class is sealed, so I cannot inherit from it. I currently have a work around where I've created a model with just one property and decorated it with the aforementioned attribute, and this is working.
I don't think I should have to jump through that hoop. Is there something I'm missing, or should I make a request to the MVC team to allow this attribute to be used on method parameters?
If you need to allow html input for a particular parameter (opposed to "model property") there's no built-in way to do that because [AllowHtml] only works with models. But you can easily achieve this using a custom model binder:
public ActionResult AddBlogPost(int id, [ModelBinder(typeof(AllowHtmlBinder))] string html)
{
//...
}
The AllowHtmlBinder code:
public class AllowHtmlBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var name = bindingContext.ModelName;
return request.Unvalidated[name]; //magic happens here
}
}
Find the complete source code and the explanation in my blog post: https://www.jitbit.com/alexblog/273-aspnet-mvc-allowing-html-for-particular-action-parameters/
Have you looked at ValidateInputAttribute? More info here: http://blogs.msdn.com/b/marcinon/archive/2010/11/09/mvc3-granular-request-validation-update.aspx.

Resources