Combine 2 TextBoxFor bound to one property MVC - c#

I need to save the Contact Number in a registration form wherein i'm having 2 TextBox, one for Country Code and another for Number. Now i need to combine both and bind into a single property which i have in my class. How can i do that?
View:
<div class="form-group">
#Html.LabelFor(m => m.Phone, "Contact Number:")
#Html.TextBoxFor(m => m.xxxx,new { #class = "form-control", #id = "txtContactCode", required="required", type ="number" })-
#Html.TextBoxFor(m => m.Phone,new { #class = "form-control", #id = "txtContactNumber", required="required", type ="number" })
</div>
Property,
public string Phone { get; set; }
Now what should i bind the property in the code of the phone number field to concatenate as one? Is there any way or i should declare another property named Code and then proceed?

In general, you should not try to split/join things. You're just introducing a potential point of failure into your application. If you only care about storing a single combined Phone, then let the user enter their phone number directly in a field for Phone. If you care about ensuring that every phone number has a country code, you can use a phone number validation library like this port of Google's libphonenumber library, to parse the user entered phone numbers and standardize how they're stored in the database.
The problem with trying to combine two fields into one is that you then have to split that one field back into two. Especially with something like a country code that can be variable length, that's going to be really difficult to do reliably. However, if you insist on going down this path, I'd recommend using a view model like:
public string Phone
{
get { return String.Format("{0} {1}", CountryCode, Number); }
set
{
CountryCode = null;
Number = null;
if (value != null)
{
var parts = value.Split(new[] { ' ' }, 2);
if (parts.Length == 2)
{
CountryCode = parts[0];
Number = parts[1];
}
}
}
}
public string CountryCode { get; set; }
public string Number { get; set; }
Then, you would bind to CountryCode and Number, respectively, in your view. The Phone custom getter and setter will take care of translating back and forth between combined and constituent parts.

You can easily do this by using the BindModel() method which is available in the IModelBinder interface.
IModelBinder.BindModel: Binds the model to a value by using the specified controller context and binding context.
Also see this explanation with real-time example.
Note: In the above example, first_name, middle_name and last_name were bound to the full name property. You can bind your required two properties to the one property in the same way.

Related

ASP.net MVC/EF/C# add none related table records to query in controller

I am trying to add records from table position for positionName(s) to let user select a position for employee when editing.My last attempts is to add a navigation property like field in company model
public virtual ICollection<Position> Mpositions { get; set; }
But all I got so far is null ref exception or no element in viewModel with property "PositionName" ass per viewbag didn't bother using everybody keeps recommending to avoid it so not going to do so either.
public ActionResult Edit([Bind(Include = "CompanyID,CompanyName,EntityForm,Address,Dissolute,CreationDate,FiscaleYear,Description")] Company company)
{
var GlbUpdate = db.Companies.Include(c => c.Members).Include(p => p.Mpositions);
List<Company> mdlCompanies = new List<Company>();
foreach (var item in GlbUpdate)
{
if ((item.Mpositions==null) || (item.Mpositions.Count() == 0))
{
item.Mpositions = (ICollection<Position>)new SelectList(db.Positions.Except((IQueryable<Position>)db.Positions.Select(xk => xk.Members)), "PositionID", "PositionName");
}
mdlCompanies.Add(item);
//I tried first to edit the Mpositions property directly in gblUpdate
//item.Mpositions = (IEnumerable<Position>)db.Positions.Select(p => new SelectListItem { Value = p.PositionID.ToString(), Text = p.PositionName}) ;
//(ICollection<Position>)db.Positions.ToListAsync();
}
In the view I have this
List<SelectListItem> mPositionNames = new List<SelectListItem>();
#*#this yields no results if I try gettign it from the compani record itself it gives a logic error where all id match all positionNames impossible to select an item and only positions already registered are available on the dropDownlist*#
#{foreach (var item in Model.Mpositions)
{
mPositionNames.Add(new SelectListItem() { Text = item.PositionName, Value = item.PositionID.ToString(), Selected = (false) ? true : false });
#*#selected attribute set to false not an issue, no data to select from :p so far*#
}
}
#*#null exception(if i try to midify Mpositions directly in controler) here or empty list if modify it then put it with original query in a new list*#
<div class="SectionContainer R-sectionContainerData" id="MwrapperDataRight">
#Html.DropDownListFor(mpos => item.PositionID, (SelectList)Model.Mpositions)
</div>
All I want to do is pull the positions table to create a drop downList so users can change the position of an employee but since position has a 1>many relation with employee not companies it is not bound automatically by EF nor I seem to be able to use Include() to add it.
Your query for editing positions are complex. This query must edit person's info only. Using Edit action for formalizing position's edit are not correct.It's againts to Single Responsibility Principle. Use ViewComponents for this situation. Load positions separately from person info.
I found a suitable solution using a model that encapsulate the other entities then using Partialviews/RenderAction so each part handles one entity/operation.

Limit the number of characters in DropDownList

I'd like to limit the number of displayed characters in DropDownList :
#Html.DropDownList("domaines", Model.Domaines, new { #class = "form-control", #id = "domaines", autocomplet = "autocomplet",maxlength = 21 })
this is the scenario :
if the number of characters <= 18 : the whole word is displayed
Else if number of characters > 18 : the first 18 characters will be displayed concatenated to an ellipsis (...).
How can I do this?
You need to prepare your model before you send it to the view. You need to pass an IEnumerable<SelectListItem> to DropDownList(), not your own type. You can use the SelectList(IEnumerable, string, string) constructor for that.
How to truncate strings with ellipsis has been answered in How do I truncate a .NET string? and Ellipsis with C# (ending on a full word).
In your controller:
// ... initialize model.
foreach (var domainModel in model.Domaines)
{
// Assuming the display member you want to truncate is called `DisplayString`.
// See linked questions for Truncate() implementation.
domainModel.DisplayString = domainModel.DisplayString.Truncate(18);
}
// Assuming the `Domaines` type has a `Value` member that indicates its value.
var selectList = new SelectList(model.Domaines, "Value", "DisplayString");
// Add a `public SelectList DomainSelectList { get; set; }` to your model.
model.DomainSelectList = selectList;
return View(model);
In your view:
#Html.DropDownList("domaines", Model.DomainSelectList, new { ... })

Binding a complex model to a drop down list in MVC

I'm trying to bind a model that has two properties - one Int, and one Boolean - to a drop-down list in MVC. The boolean is a discriminator and the integer an ID. It is not possible to split the drop down list in two.
Here is my code so far.
<select class="col-md-3 form-control" name="Model.ID" id="model-select">
<option value="0" selected>Select an Option</option>
#foreach (var m in models.OrderBy(x => x.Id))
{
<option value="#m.ID" data-discriminator="#m.Discriminator">
#m.Name
</option>
}
</select>
The model looks something like this
class MyModel
{
int ID { get; set; }
string Name { get; set; }
boolean Discriminator { get; set; }
}
The aim is to provide a set of models to the View, then the user can pick one of these. Unfortunately each model has two properties which are used to identify which model was selected in the database - the Id, which mirrors the Id in the database, and the Discriminator. The two types are otherwise incompatible in the database, hence the discriminator. For the sake of design, I only want to have these two in the same drop-down list, as you can only select one at a time anyway.
My idea of a solution was to create 2 hidden fields which would be bound to the model like so
<input type="hidden" name="Model.ID" />
<input type="hidden" name="Model.Discriminator" />
These would be updated via JavaScript and then bound to the model (as far as I know, using names like that will bind it correctly, providing that the destination property on the model passed to the POST is Model in this example).
Are there any other alternatives I could pursue?
EDIT: Also worth noting that this 'Model' is part of a more complex model and is not the only field being POSTed, so if that makes any difference...
A select box is only going to be able to post one thing, and using JavaScript to populate hidden fields, while perhaps a workable solution, seems very brittle. Your best bet would like be creating an intermediary property that you can bind to and include both sets of information as the option value:
public string SelectedThing
{
get { return string.Format("{0},{1}", ID, Discriminator); }
set
{
if (value != null)
{
var parts = value.Split(',');
if (parts.Length == 2)
{
Int32.TryParse(parts[0], out ID);
Boolean.TryParse(parts[1], out Discriminator);
}
}
}
}
Then you would need to compose your select list in a similar way:
ViewBag.MyModelChoices = myModels.Select(m => new SelectListItem
{
Value = string.Format("{0},{1}", m.ID, m.Discriminator),
Text = m.Name
});
And finally, you would bind to this new property in your view:
#Html.DropDownListFor(m => m.SelectedThing, ViewBag.MyModelChoices)

C# MVC DropDownListFor List of Strings

I am working with a list of string items in mvc that needs to be selected from a drop down list. The drop down list is binding fine, and value's are setting fine, but even though the current item being iterated matches an item in the drop down list it isn't being pre-selected as it's value, can anyone point me in the right direction?
#for (var i = 0; i < Model.StringList.Count; i++)
{
if (BL.Helpers.StringHelpers.Validate(Model.DisplayStringSegments[i]))
{
<div id="editor-field">
#Html.DropDownListFor(m => m.StringList[i], Model.PosterOptions, String.Empty, new { })
</div>
}
else
{
<div id="editor-label">#Model.StringList[i]</div>
#Html.HiddenFor(model => model.StringList[i])
}
}
So for this case, the Options is a list of strings holding only one value, "Test" -> set both as Text and Value;
PosterOptions.Add(new SelectListItem() { Text = "Test", Value = "Test" });
Can anyone tell me why the current StringList[i] isn't being pre selected, even though it has the value of "Test" ?
For anyone that comes across this;
I had to "Hack" a solution, I did this by:
Changing my ViewModel's (Model.Options)
List<SelectListItem> to a List<string>
Changing my drop down list selection to the following, forcing the selected value;
<div id="editor-field">
#{
string currentString = Model.StringList.ElementAt(i).ToString();
}
#Html.DropDownListFor(m => m.StringList[i], new SelectList(Model.Options, currentString), String.Empty, new {})
</div>
Perhaps there is a better way, but this works!
Another way could be setting the current selected item during the list creation, like this:
PosterOptions.Add(new SelectListItem() { Text = "Test", Value = "Test", Selected = true });
I had the same issue and your response helped me. I don't think that's a "hack" though. Because in your question you were using the same SelectList for all the dropdownlists so even though you mention you didn't want to create multiple lists for the drop downs I can't see another way when you have multiple drop downs as you need to specify different selected values.
As a small refactoring you can get rid of the temp variable and access the selected value directly like this:
#Html.DropDownListFor(m => m.StringList[i], new SelectList(Model.Options, Model.StringList[i]), String.Empty, new {})
In your example you don't need to distinguish between text and value but in my case it was required. When that's necessary it can be accomplished by providing the value and text field names for the SelectList. For example, say you need multiple dropdowns with Country values such as:
Country class:
public class Country
{
public string Code { get; set; }
public string Name { get; set; }
}
Model:
public List<string> CustomerCountryList { get; set; }
public IEnumerable<Country> CountryList { get; set; }
and the View:
#Html.DropDownListFor(m => m.CustomerCountryList[i], new SelectList(Model.CountryList, "Code", "Name", Model.CustomerCountryList[i]))

Using System.Web.Helpers.WebGrid

I'm trying to use a WebGrid to display data in my model and am having a huge number of issues. My model contains among other things this:
public IEnumerable<Auction> Auctions { get; set; }
What I have done is:
#{
var grid = new WebGrid(Model.Auctions, rowsPerPage: Model.PagingInfo.ItemsPerPage, defaultSort: "Title", canPage: true, canSort: true)
{SortDirection = SortDirection.Ascending};
grid.Pager(WebGridPagerModes.NextPrevious);
}
I want to display some text in the first column depending on the type of the auction in the current row, so I have written a method in the model:
public string GetAuctionType(Auction auction)
{
var type = string.Empty;
if (auction is LubAuction)
{
type = "Lowest unique wins";
}
else if (auction is EsfAuction)
{
type = "Highest wins";
}
return type;
}
Now, my view also contains:
#grid.GetHtml(
columns: grid.Columns(
grid.Column("OwnerReference", header: "Owner reference")
)
);
Question is how do I add a grid.Columns line in the above to display the text in GetAuctionType?
Also, the other issue is that there is no pager appearing and sorting does not work.
I would appreciate all help.
Thanks,
Sachin
I would move GetAuctionType logic to a Partial Class so you can access it like a normal property on each object in your collection. You may also want to take a look at question ASP.NET MVC3 WebGrid format: parameter that is covering usage of WebGrid's column format syntax.
Regarding your other issues, do you see any errors in javascript console ?

Categories