Telerik MVC DatePicker Doesn't Bind to Model - asp.net-mvc-3

I am trying to use Telerik MVC DatePicker in my project. Here is the situation:
I have a model which have :
...
[DataType(DataType.Date)]
public System.Nullable<DateTime> EndDate { get; set; }
...
My ProjectCreate view has strong type of the model given above
Between
#using (Html.BeginForm(null, null, FormMethod.Post, new { Class="ym-form ym-columnar" }))
{
...
}
I have:
#(Html.Telerik().DateTimePickerFor(c => c.EndDate)
.Name("EndDatePicker")
Within my action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ProjectCreate(ProjectView view)
{
...
}
the
view.EndDate
value is always null whichever date I choose.
I have googled a lot but couldn't find what the problem is.

That's because you are setting the Name of your datepicker. You don't need that when using DatePickerFor:
#(Html.Telerik().DateTimePickerFor(c => c.EndDate))

Related

How to keep DropDownList values between a server call in ASP.NET MVC3

I have an ASP.NET MVC3 application. I have the following ViewModel:
public class MyViewModel
{
public string Year { get; set; }
public string Month {get; set; }
public IEnumerable<SelectListItem> Years
{
get
{
return Enumerable.Range(2000, DateTime.Now.Year - 2000).Select(x => new SelectListItem
{
Value = x.ToString(),
Text = x.ToString()
});
}
}
}
And the following View:
#model MyNamespace.MyViewModel
#Html.DropDownListFor(
x => x.Year,
new SelectList(Model.Years, "Value", "Text"),
"-- select year --"
)
#Html.DropDownListFor(
x => x.Month,
Enumerable.Empty<SelectListItem>(),
"-- select month --"
)
I fill the DropDownList for Month with a jQuery function that is triggered onchange from the DropDownList for Year, which works perfectly. When the form is posted to the server and then the view is rendered back I want to keep the values in the 'Month' DropDownList as it happens correctly for Year. Therefore I tried (besides the jQuery script):
public class MyViewModel
{
public string Year { get; set; }
public string Month {get; set; }
public IEnumerable<SelectListItem> Months
{
get
{
if(Year != null)
{
return Enumerable.Range(1, 12).Select(x => new SelectListItem
{
Value = x.ToString(),
Text = x.ToString()
});
}
}
}
And in the View:
#Html.DropDownListFor(
x => x.Month,
new SelectList(Model.Months, "Value", "Text"),
"-- select month --"
)
I left Years out of the code to make things shorter. This code throws a NullReferenceException at the first run because the IEnumerable is empty. how can I achieve my goal?
You have to repopulate the month list in your action.
The POST is stateless is not like asp.net webforms.
Just do something like this in your code:
public ViewResult MyAction(MyViewModel model)
{
if (ModelState.IsValid)
{
//.. do your stuff ...
//return redirect to index if everything went ok
}
//something went wrong return the model
model.Years = new SelectList(/* code to populate years */, "Value", "Text", Model.Year);
model.Months = new SelectList(/* code to populate months */, "Value", "Text", Model.Month);
}
As a side note I prefer to use SelectList instead of IEnumerable<SelectListItem> beacuse I can set the default value in the controller (a better fit for the controller responsibility in my opinion) and not in the View.

MVC 3 Html.DropDownList error

I have that error
The ViewData item that has the key 'BookAttributesDDL' is of type 'System.String' but must be of type 'IEnumerable<SelectListItem>'.
in that code:
#Html.DropDownList("BookAttributesDDL", Model.BookAttributes_Items)
but the Model.BookAttributes_Items is type of the IEnumerable<SelectListItem> ! What's wrong ?
The ViewData.Keys property from the Immediate Window:
ViewData.Keys
Count = 2
[0]: "FCoookie"
[1]: "Title"
Try to avoid dynamic variables like ViewBag and ViewData. It will make your code unreadable and painful to maintain in future as it grows. ViewBag is like Magic strings !
Switch to the ViewModel approach.
Example, If you are creating a View to Create a Book, Create a Viewmodel (it is just a plain Class) for that like this
public class BookViewModel
{
public int BookId { set;get;}
public string BookName {set;get;}
public IEnumerable<SelectListItem> Attributes{ get; set; }
public int SelectedAttribute{ get; set; }
}
Now in your GET Action, Simply create an object of this class, Set the BookAttribbutes proeprties to your Dropdown items and pass this ViewModel object to the View
public ActionResult Create()
{
BookViewModel vm=new BookViewModel();
//The below code is hardcoded for demo. you mat replace with DB data.
vm.Attributes=new[]
{
new SelectListItem { Value = "1", Text = "F Cookie" },
new SelectListItem { Value = "2", Text = "Title" },
}
return View(vm);
}
Now in We will make our view strongly typed to this ViewModel class
#model BookViewModel
#using(Html.BeginForm())
{
#Html.TextBoxFor(x=>x.BookName)
#Html.DropDownListFor(x => x.SelectedAttribute,
new SelectList(Model.Attributes, "Value", "Text"), "Select Attribute")
<input type="submit" value="Save" />
}
Now you will get the Selected Dropdown value and the textbox value in your HttpPost action by accessing the corresponding properties of your ViewModel
[HttpPost]
public ActionResult Create(BookViewModel model)
{
if(ModelState.IsValid)
{
//check for model.BookName / model.SelectedAttribute
}
//validation failed.TO DO : reload dropdown here
return View(model);
}
Fully agree with View Model approach response to you (and its me who selected it as useful).
However, if you don't want to switch, but remain as is I bet your answer lays in this article.
Hope this help you.

Trying to Extend ProDinner Chef class with collection of Phone Numbers

I am trying to extend ProDinner by adding phone numbers to Chef.
ChefInput view model:
public class ChefInput :Input
{
public string Name { get; set; }
public ChefInput()
{
PhoneNumberInputs = new List<PhoneNumberInput>(){
new PhoneNumberInput()
};}
public IList<PhoneNumberInput> PhoneNumberInputs { get; set; }
}
PhoneInput view model:
public class PhoneNumberInput :Input
{
public string Number { get; set; }
public PhoneType PhoneType { get; set; } <-- an enum in Core project
}
Chef Create.cshtml file:
#using (Html.BeginForm())
{
#Html.TextBoxFor(o => o.Name)
#Html.EditorFor(o => o.PhoneNumberInputs)
}
PhoneNumberInput.cshtml in EditorTemplate folder:
#using (Html.BeginCollectionItem("PhoneNumberInputs"))
{
#Html.DropDownListFor(m => m, new SelectList(Enum.GetNames(typeof(PreDefPhoneType))))
#Html.TextBoxFor(m => m.Number)
}
When debugging and I stop it at Create in Crudere file, the Phone collection is null.
Anyone have any ideas?
Thanks in Advance.
Joe,
You don't show your controller logic but I've got a feeling you're getting null because you're not populating the PhoneNumberInputs ViewModel. From what I can see, all you're doing is newing up the list in the model. Ensure that you fill this 'list' in your controller from the database (with the appropriate values) and i'm certain all will work as planned.
[edit] - in answer to comment. don't know what the prodinner controllers etc look like but something alsong these lines:
public ActionResult Edit(int id)
{
var viewModel = new ChefInput();
viewModel.ChefInput = _context.GetById<ChefModel>(id);
viewModel.PhoneNumberInputs = _context.All<PhoneNumberInput>();
return View(viewModel);
}
as i said, not sure of the prodinner setup, but this is what i meant.

ASP.NET MVC 3 Viewmodel Pattern

I am trying to work out the best way of using a viewmodel in the case of creating a new object.
I have a very simple view model that contains a contact object and a select list of companies.
private ICompanyService _Service;
public SelectList ContactCompanyList { get; private set; }
public Contact contact { get; private set; }
public ContactCompanyViewModel(Contact _Contact)
{
_Service = new CompanyService();
contact = _Contact;
ContactCompanyList = GetCompanyList();
}
private SelectList GetCompanyList()
{
IEnumerable<Company> _CompanyList = _Service.GetAll();
return new SelectList(_CompanyList, "id", "name");
}
I then have contact controller that uses this viewmodel and enable me to select a related company for my contact.
[Authorize]
public ActionResult Create()
{
return View(new ContactCompanyViewModel(new Contact()));
}
My issue is with the create method on the controller.
[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Contact _Contact)
{
try
{
_Service.Save(_Contact);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
The problem is that the view returns an empty contact object, but! the company id is populated, this is because the dropdown list explicitly declares its field name.
#Html.DropDownList("parent_company_id",Model.ContactCompanyList)
The standard html form fields pass the objects values back in the format of contact.forename when using the HTML.EditorFor helper...
#Html.EditorFor(model => model.contact.forename)
I can access them if I use a FormCollection as my create action method paremeter and then explicitly search for contact.value but I cannot use a Contact object as a parameter to keep my code nice and clean and not have to build a new contact object each time.
I tried passing the actual view model object back as a parameter but that simply blows up with a constructor error (Which is confusing seeing as the view is bound to the view model not the contact object).
Is there a way that I can define the name of the Html.EditFor field so that the value maps correctly back to the contact object when passed back to the create action method on my controller? Or Have I made some FUBAR mistake somewhere (that is the most likely explanation seeing as this is a learning exercise!).
Your view model seems wrong. View models should not reference any services. View models should not reference any domain models. View models should have parameterless constructors so that they could be used as POST action parameters.
So here's a more realistic view model for your scenario:
public class ContactCompanyViewModel
{
public string SelectedCompanyId { get; set; }
public IEnumerable<SelectListItem> CompanyList { get; set; }
... other properties that the view requires
}
and then you could have a GET action that will prepare and populate this view model:
public ActionResult Create()
{
var model = new ContactCompanyViewModel();
model.CompanyList = _Service.GetAll().ToList().Select(x => new SelectListItem
{
Value = x.id.ToString(),
Text = x.name
});
return View(model);
}
and a POST action:
[HttpPost]
public ActionResult Create(ContactCompanyViewModel model)
{
try
{
// TODO: to avoid this manual mapping you could use a mapper tool
// such as AutoMapper
var contact = new Contact
{
... map the contact domain model properties from the view model
};
_Service.Save(contact);
return RedirectToAction("Index");
}
catch
{
model.CompanyList = _Service.GetAll().ToList().Select(x => new SelectListItem
{
Value = x.id.ToString(),
Text = x.name
});
return View(model);
}
}
and now in your view you work with your view model:
#model ContactCompanyViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedCompanyId, Model.CompanyList)
... other input fields for other properties
<button type="submit">Create</button>
}

Form for a different model than the view page in ASP.NET MVC 3

I have Results page that contains an signup form. I'm trying to use client-side validation on the email model, but I can't because the model type is different than the type I'm posting.
class Results
{
... // some results data to display
}
class EmailSignup
{
public virtual int Id { get; set; }
[Required(ErrorMessage = "Please enter your email.")]
[DataType(DataType.EmailAddress)]
[RegularExpression(#"^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+#((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$", ErrorMessage = "Please enter a valid email address.")]
public virtual string Email { get; set; }
}
Results.cshtml
#model MyApp.Results
[display results]
...
#using (Html.BeginForm("SubmitEmail", "AnalysisResults", FormMethod.Post))
{
<fieldset>
#Html.TextBoxFor( model => model.???? )
</fieldset>
}
The type I want the user to submit is EmailSignup, not Results.
Move the form to a partial view that takes an EmailSignup model.
This can be done quite easily. You just have to do it like this:
var contactModel = new ContactModel();
#Html.TextBoxFor(m => contactModel.Title)
#Html.ValidationMessageFor(m => contactModel.Title)
The validation works like a charm.
I have find out 2 more ways
Override the Name attribute for TextBoxFor and set it as the property name.
var formModel = new ForgotPasswordFormModel();
#Html.TextBoxFor(m => formModel.UsernameOrEmail, new { Name = "UsernameOrEmail" })
Specify the same exact model name as the post method parameter.
var formModel = new ForgotPasswordFormModel();
#using (Html.BeginForm("ChangePassword", "LoginSurface")
{
#Html.TextBoxFor(m => formModel.UsernameOrEmail)
}
...
public virtual ActionResult ChangePassword(ForgotPasswordFormModel formModel)
You could create another HtmlHelper like this
var emailSignupHtml = new HtmlHelper<EmailSignup>(Html.ViewContext, new ViewDataContainer<EmailSignup>(new EmailSignup()));
and use it like this
#emailSignupHtml.TextBoxFor(m => m.Email)
For the ViewDataContainer I use following helper class
public class ViewDataContainer<TModel> : ViewDataDictionary<TModel>, IViewDataContainer
{
public ViewDataContainer(TModel model) : base (model)
{
ViewData = new ViewDataDictionary(model);
}
public ViewDataDictionary ViewData { get; set; }
}
I guess you can also try #HTML.Action("EmaialSignup")
and your controller will have a Function calling the partial view
if you have to render multiple model bounded View in this view

Resources