How to get the selected value of a dynamically created selectlist component - dynamic

I am not sure whether this is even possible, but I am trying to get the values of dynamically created selectlists in a VisualForce Apex controller class.
I am dynamically creating a selectlist for each field in a particular object (e.g. Contact) using the code below, but now I do not know how to get the selected value back. I have tried setting the value of each in the constructor and on a separate line (not in code sample below), but this does not seem to work.
VisualForce page:
<apex:dynamicComponent componentValue="{!contactPageBlockSection}" />
Apex controller:
public Component.Apex.PageBlockSection GetContactPageBlockSection(string objectName)
{
Map<string, Schema.SObjectField> FieldMap;
FieldMap = Schema.SObjectType.Contact.fields.getMap();
Set<string> FieldSet = FieldMap.keySet();
List<string> FieldList = new List<string>();
FieldList.addAll(FieldSet);
FieldList.sort();
Component.Apex.PageBlockSection pbs = new Component.Apex.PageBlockSection(columns = 2);
for (string fieldName : FieldList)
{
Component.Apex.PageBlockSectionItem pbsi = new Component.Apex.PageBlockSectionItem();
Schema.DescribeFieldResult field = (FieldMap.get(fieldName)).getDescribe();
if (field.isUpdateable() && field.IsAccessible())
{
Schema.DisplayType dt = field.getType();
Component.Apex.OutputLabel lblText = new Component.Apex.OutputLabel(escape = false);
lblText.value = field.getLabel();
pbsi.childComponents.add(lblText);
Component.Apex.SelectList selList = new Component.Apex.SelectList(id = field.getName(), multiselect = false, size = 1, style = 'width:200px;');
if (dt == Schema.DisplayType.Integer || dt == Schema.DisplayType.Double || dt == Schema.DisplayType.Currency || dt == Schema.DisplayType.Percent)
{
AddSelectOption(selList, 'Keep highest value');
AddSelectOption(selList, 'Keep lowest value');
AddSelectOption(selList, 'Keep master value');
pbsi.childComponents.add(selList);
pbs.childComponents.add(pbsi);
}
}
}
return pbs;
}
private void AddSelectOption(Component.Apex.SelectList selList, string option)
{
Component.Apex.SelectOption selOption = new Component.Apex.SelectOption();
selOption.itemLabel = option;
selOption.itemValue = option;
selList.childComponents.add(selOption);
}
Many thanks in advance

just bind the value attribute of the dynamically created select list to a string property using expression syntax like:
String selectedValue {get; set;}
...
setList.expressions.value = '{!selectedValue}';
the property should then store the selected value just as it would in a static declarative definition of the select list.

You could try and use dynamic visualforce binding. I.E.
map<String,String> FieldToString {get; set;}
...
selList.expressions.value = '{!FieldToString[\'' + fieldname + '\']}';
However, I have never used dynamic visualforce bindings within dynamic visualforce so caveat emptor.

Related

I want to select different packages on the basis of states, how to get value

public ActionResult Rajasthan()
{
//List<PackageGallery> all = new List<PackageGallery>();
using (travelAndTourismEntities objentity = new travelAndTourismEntities())
{
List<PackageGallery> all = (from p in objentity.PackageGalleries where p.ParentCategory == "Rajasthan" orderby p.Imageid select p).ToList();
// all = objentity.PackageGalleries.ToList();
return View(all);
}
}
I am writing this query but this is specific to rajasthan only how to make it generalize
You can create a parameter to your action method where you accept the state name you want to use in your filter.
public ActionResult PackageGalleries(string id)
{
var all = new List<PackageGallery>();
using (var db = new travelAndTourismEntities())
{
all = db.PackageGalleries
.Where(s=>s.ParentCategory==id)
.OrderBy(x=>x.ImageId).ToList();
}
return View(all);
}
And you can call it like yourSiteName/yourControllerName/PackageGalleries/rajasthan or yourSiteName/yourControllerName/PackageGalleries/kerala
The last part of the url will be mapped to the id parameter of the action method.

How to set Default value in MVC 4 razor DropDownListFor

I Have MVC Razor view with lot of DropDrownFor.
i wanna set default value to that DropdownListFor.
This is my View:
#Html.DropDownListFor(model => model.DestCountryId, ViewBag.CountryIdList as SelectList, "select", new { #class = "form-control input-sm" })
This is my ViewBag:
ViewBag.CountryIdList = new SelectList(db.Countries.Where(a => a.Currency != null), "Id", "Name");
Ho w to set Default value in this scenario
you need to do like this:
ViewBag.CountryIdList = new SelectList(db.Countries.Where(a => a.Currency != null), "Id", "Name",1);
For Example in the Countries List, you have a item CountryName and its id is 1, you need to pass the 1 in the last parameter, and element with that Id 1 will be shown selected by default.
Example:
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
List<Country> list = new List<Country>();
list.Add(new Country{ Id = 1, Name="Test"});
list.Add(new Country{ Id = 2, Name="Test2"});
now in controller action:
int Selected = 2;
ViewBag.CountryIdList = new SelectList(list, "Id", "Name",Selected);
Now the Test2 will be shown selected default in View.
The first parameter that you give to #Html.DropDownListFor is an expression that identifies the object that contains the properties to display.
You have already given "Selected" as default value if nothing is selected or your DestCountryId doesn't hold any value or it doesn't matches with the values passed in the CountryIdList. You need to assign a value to DestCountryId before rendering this view. You can do this either in controller or where you build your view-model like:
viewModel.DestCountryId = 33; where this value exists in the selectList value that you are giving to dropdownlist.
Also, a good practise is to not to use ViewBag. Try creating a simple model with properties that your current view needs.
You can also use SelectList(IEnumerable, String, String, Object) overload of SelectList where the object is the selected value.
Hope this helps.

how to set the selected value in the drop down list populated with ViewData in mvc

I am new to MVC, please help me to set the selected value in drop down list populated using View Data. I have gone through so many solutions but every solutions deals with selecting value for single drop down. I have same drop down listed using the foreach loop. Setting selected value for each dropdown in that foreach loop.
My code is shown below.
[In view]
int i = 0;
foreach (var item in Model.Select((x, j) => new { Data = x, Index = j + 1 })) {
#Html.DropDownListFor(model => item.Data.CategoryID,(IEnumerable<SelectListItem>)ViewData["categories"], new { #id = "category" + i })
i++;
}
[in controller]
SelectList selectList = new SelectList((IEnumerable<Category>)ConvertCategoryToList(dt1), "CategoryID", "CategoryName");
ViewData["categories"] = selectList;
There is a lot missing from your sample (e.g.what a category looks like, what the Edit actions look like, what is dt1, what the model is you pass to the view etc), but I will try based on what is shown.
Problem 1: Can't use foreach in binding
You can't use a foreach with a collection of form items. The items have no way of knowing which individual element to bind with (when they are sent back to the server they need more information to make each entry unique).
Solution:
It only knows how to bind if you use indexing (e.g. using for (int i=0; < count; i++){ #Html.DropDownListFor(model=>item[i]...)
Problem 2: Selected values only can come from SelectList!
This is the most irritating feature of DropDownListFor and appears to be a bug. It will not take the current selected value from the bound data. It will only take a current value from a SelectList, which means you need a unique SelectList for every dropdown.
Solution:
Create a unique SelectList in the view, per drop down required, with the item value as the current selection.
With some faking of your data, I got the following working:
Example
Controller:
Only store the list of items for the SelectList in the ViewBag:
ViewData["categories"] = ConvertCategoryToList(dt1);
View:
1. You need to pass a List and not an IEnumerable as IEnumerable cannot be indexed.
#model List<MyApplication.Item>
2. Create a SelectList for each dropdown
SelectList newSelectList = new SelectList((IEnumerable<MyApplication.Category>)ViewData["categories"], "CategoryID", "CategoryName", Model[i].Id);
3. Use the indexing method for addressing your items in the collection.
#Html.DropDownListFor(m => Model[i].Id, newSelectList, "Select an item")
Problem 3: What data to pass?
The other issue with your code, as-it-stands, is what to pass back and forth to/from the edit view? At the moment I would guess (from the variable name dt1) you are passing a DataTable(?). You will need to be very explicit about the data you are using in order to get a clean solution to this one. I would suggest posting a second question with all your code and Razor view HTML.
If you need to see more of my sample code (below), please post your own code so I can make them consistent.
Full dummy controller code below
public class TestController : Controller
{
public List<Category> dt1 { get; set; }
public TestController()
{
this.dt1 = new List<Category>();
for (int i = 1; i <= 10; i++)
{
this.dt1.Add(new Category() { CategoryId = i, CategoryName = string.Format("Category {0}", i) });
}
}
[HttpGet]
public ActionResult Edit()
{
//SelectList selectList = new SelectList((IEnumerable<Category>)ConvertCategoryToList(dt1), "CategoryID", "CategoryName");
ViewData["categories"] = ConvertCategoryToList(dt1);
List<Item> items = new List<Item>();
items.Add(new Item(){Id = 1});
items.Add(new Item(){Id = 2});
items.Add(new Item(){Id = 3});
items.Add(new Item(){Id = 4});
items.Add(new Item(){Id = 5});
return View(items);
}
[HttpPost]
public ActionResult Edit(FormCollection form)
{
// Turn form submission back into a compatible view model
List<Item> items = new List<Item>();
foreach (string key in form.Keys)
{
string val = form[key];
items.Add(new Item() { Id = int.Parse(val) });
}
// Recreate the select list
ViewData["categories"] = ConvertCategoryToList(dt1);
return View(items);
}
List<Category> ConvertCategoryToList(IEnumerable<Category> dt)
{
return dt.ToList();
}
}
Note: The post version of Edit simply recreates the list of data (using the selected values posted back) and returns to the Edit view. This is just for testing.
Screen shot
Dummy category class
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
Full test View
#model List<MyApplication.Item>
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
SelectList newSelectList = new SelectList((IEnumerable<MyApplication.Category>)ViewData["categories"], "CategoryID", "CategoryName", Model[i].Id);
#Html.DropDownListFor(m => Model[i].Id, newSelectList, "Select an item")
}
<input type="submit" value="Submit"/>
}

Generate parameter list with userdefined types at runtime (using C#)

As part of my project, I am trying to build a web UI where user will select a method and pass the values. My program should be able to call the method dynamically and build a parameter list on runtime to pass it to the method.
I have created a comma separated list (string) of key and value pairs. This key/value pair is nothing but the parameter name and value of my method (methodname stored in a variable). Example: string params = "ID:123;Name:Garry;Address:addressObject;AddressLine:108 Plaza Lane;City:Avenel;State:NJ;Zip:07001;". Where ID and Name are simple string varaibles while Address is user defined type. What follows after Address i.e. AddressLine, City, State and Zip is elements of Address object. And my method definition is
public string GetInfo(string ID, string Name, Address addressObject)
{
//return something;
}
I am dynamically calling the method (GetInfo) that is stored in sMethodName variable using DynamicProxy like :
string sMethodName = "GetInfo";
object result = (object) proxy.CallMethod(sMethodName, arguments);
Challenge is how to pass the argument list dynamically? Till now I am just able to extract the values from the csv variable into NamedValueCollection. Here is the code:
public static void StoreParameterValues(string param)
{
nvc = new NameValueCollection();
param = param.TrimEnd(';');
string[] parameters = param.Split(new char[] { ';' });
foreach (string val in parameters)
{
string[] keyValue = val.Split(new char[] { ':' });
nvc.Add(keyValue[0], keyValue[1]);
}
}
..and here is the code that tries to build the parameter:
string methodName = "GetInfo";
DynamicProxyFactory factory = new DynamicProxyFactory("http://../myservice.svc");
string sContract = "";
foreach (ServiceEndpoint endpoint in factory.Endpoints)
{
sContract = endpoint.Contract.Name;
}
DynamicProxy proxy = factory.CreateProxy(sContract);
string[] values = null;
// Create the parameter list
object[] arguments = new object[nvc.Count];
int i = -1;
foreach (string key in nvc.Keys)
{
values = nvc.GetValues(key);
foreach (string value in values)
{
arguments[++i] = value;
}
}
object result = (object) proxy.CallMethod(methodName, arguments);
The above code works if I have simple primitive types but not sure how can I build the logic for any other userdefined types. How can I create a object dynamically of type stored in a variable? Not sure if I was able to put my question correctly. I hope so :)
Edit: 01/19/2011: Applied the suggestion from Chris - using Reflection instead of ComponentModel.
I have converted the code to make it more generic. This works now for all primitive and custom types (resursion). Code snippet below:
private object BuildParameterList(Type type)
{
object item = new object();
item = Activator.CreateInstance(type);
PropertyInfo[] propArray = type.GetProperties(BindingFlags.Public|BindingFlags.Instance);
for (int i = 0; i < propArray.Length; i++)
{
PropertyInfo pi = (PropertyInfo)propArray[i];
////Check for custom type
if (IsCustomType(pi.PropertyType))
{
object item1 = BuildParameterList(pi.PropertyType);
pi.SetValue(item, item1, null);
}
else
{
if (property.ContainsKey(pi.Name))
{
pi.SetValue(item, Convert.ChangeType(property[pi.Name], pi.PropertyType), null);
}
}
}
return item;
}
But if one of the property is Color (I just tested with Color type, will fail with other system types aswell-i guess), then it fails at the following line. Not sure how to handle system types - Color or something similar.
pi.SetValue(item, Convert.ChangeType(property[pi.Name], pi.PropertyType), null);
Can you not find what types are expected by the method, by inspecting its ParameterInfos:
endpoint.Contract.ContractType.GetMethod(methodName).GetParameters();
and then instantiating the custom types using:
Activator.CreateInstance(parameterType);

Silverlight 4 Overriding the DataForm Autogenerate to insert Combo Boxes bound to Converters

I've been working towards a solution for some time and could use a little help. I know I've seen an example of this before, but tonight I cannot find anything close to what I need.
I have a service that provides me all my DropDownLists, either from Cache or from the DomainService. They are presented as IEnumerable, and are requested from the a repository with GetLookup(LookupId).
I have created a custom attribute that I have decorated my MetaDataClass that looks something like this:
[Lookup(Lookup.Products)]
public Guid ProductId
I have created a custom Data Form that is set to AutoGenerateFields and I am intercepting the autogenerate fields.
I am checking for my CustomAttribute and that works.
Given this code in my CustomDataForm (standard comments removed for brevity), what is the next step to override the field generation and place a bound combobox in its place?
public class CustomDataForm : DataForm
{
private Dictionary<string, DataField> fields = new Dictionary<string, DataField>();
public Dictionary<string, DataField> Fields
{
get { return this.fields; }
}
protected override void OnAutoGeneratingField(DataFormAutoGeneratingFieldEventArgs e)
{
PropertyInfo propertyInfo = this.CurrentItem.GetType().GetProperty(e.PropertyName);
foreach (Attribute attribute in propertyInfo.GetCustomAttributes(true))
{
LookupFieldAttribute lookupFieldAttribute = attribute as LookupFieldAttribute;
if (lookupFieldAttribute != null)
{
// Create a combo box.
// Bind it to my Lookup IEnumerable
// Set the selected item to my Field's Value
// Set the binding two way
}
}
this.fields[e.PropertyName] = e.Field;
base.OnAutoGeneratingField(e);
}
}
Any cited working examples for SL4/VS2010 would be appreciated.
Thanks
Update - Here's where I am at. I get my combo now, but it's always empty even though itemsSource is not.
if (lookupFieldAttribute != null)
{
ComboBox comboBox = new ComboBox();
Binding newBinding = e.Field.Content.GetBindingExpression(TextBox.TextProperty).ParentBinding.CreateCopy();
newBinding.Mode = BindingMode.TwoWay;
newBinding.Converter = new LookupConverter(lookupRepository);
newBinding.ConverterParameter = lookupFieldAttribute.Lookup.ToString();
comboBox.SetBinding(ComboBox.SelectedItemProperty,newBinding);
comboBox.ItemsSource = lookupRepository.GetLookup(lookupFieldAttribute.Lookup);
e.Field.Content = comboBox;
}
I found a solution.
if (lookupFieldAttribute != null)
{
ComboBox comboBox = new ComboBox();
Binding newBinding = e.Field.Content.GetBindingExpression(TextBox.TextProperty).ParentBinding.CreateCopy();
var itemsSource = lookupRepository.GetLookup(lookupFieldAttribute.Lookup);
var itemsSourceBinding = new Binding { Source = itemsSource };
comboBox.SetBinding(ItemsControl.ItemsSourceProperty, itemsSourceBinding);
newBinding.Mode = BindingMode.TwoWay;
newBinding.Converter = new LookupConverter(lookupRepository);
newBinding.ConverterParameter = lookupFieldAttribute.Lookup.ToString();
comboBox.SetBinding(ComboBox.SelectedItemProperty,newBinding);
e.Field.Content = comboBox;
}