I have the following code populate for dropdownlist. Is there any way i can add an item called "Select Value" in the following
private void PopulateCustStatus()
{
ViewData["custStatus"] = new HEntities().COptions
.Select(e => new ConfOptModel
{
OptID = e.OptID,
OptName = e.OptName,
ConfigTypeID = e.ConfigTypeID
})
.Where(e => e.ConfigTypeID == 2)
.OrderBy(e => e.OpName);
}
The problem with what you're trying to do, I think, is that your "no selection" option (e.g. "Select Value") doesn't have the same "shape" as the model being created in PopulateCustStatus().
You probably want to use an IEnumerable<SelectListItem>:-
var selectList =
new HEntities().COptions
.Where(e => e.ConfigTypeID == 2)
.OrderBy(e => e.OpName)
.Select(e => new SelectListItem()
{
Text = e.OptName,
Value = e.OptID,
Selected = false
});
This gives you a little bit more flexibility. Then you can insert a "Select value" item on top like:-
var noSelection = new SelectListItem()
{
Text = "Select value",
Value = 0,
Selected = true
};
ViewData["selectedCustStatus"] =
new[] { noSelection }.Concat(selectList);
Note: If you want to preserve a previously selected value, you'll have to pass it into the function and make sure the matching SelectListItem gets its Selected property set to true.
Hope this helps!
You're returning a list of ConfOptModel object so unless there's a property to indicate a "selected" value then you can't.
If I don't create models specifically for the View (i.e. use domain objects as the "Model" instead of a "ViewModel") I usually add the selected item to the view state :
ViewData["selectedCustStatus"] = selectedID;
And then use that value when creating the DropDownList in the markup.
Another option is to return a list of SelectListItem objects instead of domain (ConfOptModel) objects. That puts a little of the view logic in the controller so use whichever you're more comfortable with.
Related
I want to generate a strongly typed list of Roles in my controller along with two other lists which will be used in my view as various filters for sending an email. I'm aware I can generate the Roles list using the following:
var viewModel = new ListViewModel
{
Roles = db.Roles.OrderBy(r => r.Name).ToList().Select(rr => new SelectListItem { Value = rr.Id.ToString(), Text = rr.Name }).ToList(),
};
However as I am also wanting to pass two other lists to my controller I would prefer to attain the list of roles by writing the query in the following way:
var viewModel = db.Roles
.Select(x => new SendGroupEmailViewModel
{
Roles = x.Select(rr => new SelectListItem { Value = rr.Id.ToString(), Text = rr.Name }).ToList(),
};
That way I can then attain my other two lists as part of the same query, as opposed to the previous method where they would have to be effectively separate queries to the db. Obviously what is above doesn't work, I am unable .Select on the role table by writing Roles = x.Select.
My question is, why am I unable to do this and what is the correct way to query the Roles table when writing it in a similar way to the above?
Just to be clear, the reason it has to be var viewModel = db.Roles is because for whatever reason I can't access the ID/Name Roles list otherwise due to how Identity is setup in MVC. I know there are other ways of attaining the list, I would just like to know how it can be done this specific way?
edit - I should add that Roles in my viewModel is as follows:
public IEnumerable<SelectListItem> Roles { get; set; }
controller
var oList = db.Roles.Select(x => new SendGroupEmailViewModel
{
Roles = x.Roles.Select(rr => new SelectListItem { Value = rr.Id.ToString(), Text = rr.Name }).ToList();
ViewData.myList = new SelectList(oList,
},
"Value", "Text", 15); // 15 = selected item or you can omit this value
View
<%=Html.DropDownList("myList") %>
I have a page that contains a list a companies. Each company is appart of a group, like such:
But here's the catch, groups can be disabled, if they are, that would not change the display of the list but it does have an impact on my edition page.
As you can see, there is a DropDownList containing my groups. But if a group is disabled it does not show up on the list because I retrieve said list like such:
public IEnumerable<SelectListItem> ListGroupEnabled()
{
List<SelectListItem> X = _entities.Groups.Where(p => p.IsEnabled).ToList().Select(c => new SelectListItem { Value = c.GroupId.ToString(), Text = c.Name }).ToList();
return X;
}
But here's what I wish to achieve:
If I were to edit a company that was appart of a disabled group, I still want that group (and only that group) to appear in the DDList among enabled groups.
This is for the sake of logic, it wouldn't make sense to simply not have the group a company is appart off in its list.
How may I change the code I showed up above in order to keep the group the company is appart off in my list?
Hello SelectListItem have Properties such as Disabled you can set it before send. referrence
fix your code at below.
public IEnumerable<SelectListItem> ListGroupEnabled()
{
List<SelectListItem> X = _entities.Groups.Select(c => new SelectListItem { Value = c.GroupId.ToString(), Text = c.Name , Disabled = c.IsEnabled }).ToList();
return X;
}
You need to pass in the current group id and include that in your where clause:
public IEnumerable<SelectListItem> ListGroupEnabled(int? currentGroupId = null)
{
return _entities.Groups.Where(
p =>
p.IsEnabled ||
(currentGroupId.HasValue && p.GroupId == currentGroupId.Value)
).Select(c => new SelectListItem { Value = c.GroupId.ToString(), Text = c.Name }).ToList();
}
You also don't need to call ToList before selecting. That actually makes the query less optimized as without that, Entity Framework can just select the columns it needs (GroupId and Name).
I have this:
// Load changelog types
ChangeLogType[] Types = ChangeLogFunctions.GetAllChangelogTypes();
foreach(ChangeLogType Rec in Types){
ListItem N = new ListItem();
N.Text = Rec.Type;
N.Value = Rec.ID.ToString();
LstChangeLogType.Items.Add(N);
}
It calls a function that returns an array of ChangeLogTypes, and then adds each one into a list control. Is there a more elegant way of doing this? I feel I'm repeating code each time I do this or something similar.
Yup, LINQ to Objects is your friend:
var changeLogTypes = ChangeLogFunctions.GetAllChangelogTypes()
.Select(x => new ListItem {
Text = x.Type,
Value = x.ID.ToString() })
.ToList();
The Select part is projecting each ChangeLogType to a ListItem, and ToList() converts the resulting sequence into a List<ListItem>.
This is assuming you really wanted a new list with all these entries. If you need to add the results to an existing list, you'd do that without the ToList call, but calling AddRange on an existing list with the result of the Select call.
It's well worth learning more about LINQ in general and LINQ to Objects in particular - it can make all kinds of things like this much simpler.
var range = Types.Select(rec =>
new ListItem { Text = rec.Type, Value = rec.ID.ToString() });
LstChangeLogType.AddRange(range);
Linq?
LstChangeLogType.Items = Types.Select(x => new ListItem()
{ Text = x.Type, Value = x.ID.ToString() }).ToList();
using System.Linq;
var items = Types
.Select (rec => ListItem
{
Text = Rec.Type;
Value = Rec.ID.ToString();
}
LstChangeLogType.Items.AddRange(items);
Using some LINQ extension methods:
LstChangeLogType.AddItems.AddRange(
Types.Select(t =>
new ListItem() { Text = t.Type, Value = t.ID.ToString() }).ToArray());
I have the following class:
public static IEnumerable<SelectListItem> GetDatastore()
{
return new[]
{
new SelectListItem { Value = "DEV", Text = "Development" },
new SelectListItem { Value = "DC1", Text = "Production" },
};
}
What I need is to execute a function to return the Datastore name. Something like
var abc = getDatastoreName("DEV").
Do I need to do this with LINQ or is there some easy way? How could I code this function?
public static string getDatastoreName(string name)
{
var result = GetDatastore().SingleOrDefault(s => s.Value == name);
if (result != null)
{
return result.Text;
}
throw /* some exception */
}
The Value property of SelectListItem is usually unique and hence I have SingleOrDefault(). If that is not the case then you can switch to using FirstOrDefault().
A simple LINQ query can find the value you want:
var val = dataStore.Where(d => d.Value == "DEV").FirstOrDefault();
//`val` will be the item, or null if the item doesn't exist in the list
But this is only good for small lists of items -- it's worst-case Order N.
If you wanted a better search, you could store your data as a dictionary with the keys being used as item values, for example, and databind against that rather than against a list of SelectListItems. That would allow you to look up the values constant time.
For most cases, simple LINQ will be fine. If you have a big list, or you're querying that list frequently... consider an alternative.
Maybe you are searching something like this
i have "Details" page that works perfectly:
#Html.DisplayFor(model => model.Code1dItems.SingleOrDefault(m => m.Value == model.Code1Id.ToString()).Text, new { #class = "Width100P" })
In my model :
Code1Id is int value and it comes from database Code1dItems is IEnumerable
value like 'GetDatastore' and returns ID->string, ID value matches with Code1d and Text->string
depending on your question you should use :
string abc = GetDatastore.SingleOrDefault(m => m.Value == "DEV").Text
if you get value from database you should use my code example.
I have an IQueryable I selected from a database that contains a field called "NewValue". This field will either contain a 0, 1, or 2. I want to replace the value with a string based of which number it is.
i.e 0 = "Active". I know IQueryables aren't used to change values mostly just for querying but I need to use it in the next line to add to the ViewModel
var AssessmentList = assessment
.Select(p => new LogManagementViewModel
{
newValue = p.NewValue,
});
How can I change all the values in assement.NewValue to a string?
var dictionary = new Dictionary<int, string>
{
{ 0, "Active" },
{ 1, "Inactive" },
// etc
};
var AssessmentList = assessment
.Select(p => new LogManagementViewModel
{
newValue = dictionary[p.NewValue],
});
This would work for mapping between other types as well.
var values = new [] {"StrValue1", "StrValue2", "StrValue"};
var AssessmentList = assessment
.AsEnumerable()
.Select(p => new LogManagementViewModel
{
newValue = values[p.NewValue],
});
Easiest and cleanest would be with a mapping method:
string MapToString(int value)
{
//..
}
var AssessmentList = assessment
.Select(p => new LogManagementViewModel
{
NewValue = MapToString(p.NewValue),
});
One way:
Add a new computed property onto your class (assuming you have a partial class outside of any generated code). Then that computed class can do the translation however it needs to. Your view model can reference this computed value.
I would make a constructor overload in your LogManagementViewModel that does that work for you, something like this:
public LogManagementViewModel(int NewValue)
{
switch(NewValue)
{
case 0:
this.NewValue = "Active";
break;
// etc...
}
}
IMO, this places the logic in it's proper place, let the your view model translate it as it should be, it's not the responsibility of your LINQ/Database queries.