Sion Christian
Sion Christian

Reputation: 65

Set an automatic DateTime.Now value for an @Html.HiddenFor

I would like to ask is there any way to set an automatic DateTime.Now value for properties ENTRY_DATE and AUDIT_TIME in the Create() HttpPost method? The form is created and it works fine. If the DateTime is inserted manually. But, it won't work if I set an automatic value and would run into a

"One or more validation Error's"..

This is my model (I don't understand how to make a viewmodel) :

public partial class TRRESPONDENT
{
    public TRRESPONDENT()
    {
        this.TRFOLLOWUPRESPONDENTs = new HashSet<TRFOLLOWUPRESPONDENT>();
    }

    [Required(ErrorMessage = "Respondent ID is required!")]
    [Display(Name = "Respondent ID")]
    public string RESPONDENT_ID { get; set; }
    [Required(ErrorMessage = "Please select a BINUS Center!")]
    [Display(Name = "Binus Center")]
    public string BC_ID { get; set; }
    [Required(ErrorMessage = "Name cannot be empty!")]
    [Display(Name = "Name")]
    [StringLength(100,ErrorMessage = "Name length cannot be more than 100 characters!")]
    public string FULL_NAME { get; set; }
    .... // more properties
    [Required(ErrorMessage = "Please pick a City Location!")]
    [Display(Name = "City")]
    public int CITY_ID { get; set; }
    // The following 2 properties need to be set
    [Display(Name = "Entry Date")]
    public DateTime ENTRY_DATE { get; set; }
    public DateTime AUDIT_TIME { get; set; }
    .... 
    public virtual LTCITY LTCITY { get; set; }
    public virtual LTSOURCERESPONDENT LTSOURCERESPONDENT { get; set; }
    public virtual MSBINUSCENTER MSBINUSCENTER { get; set; }
    public virtual ICollection<TRFOLLOWUPRESPONDENT> TRFOLLOWUPRESPONDENTs { get; set; }
}

This is my view

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    @Html.LabelFor(model => model.RESPONDENT_ID)
    @Html.EditorFor(model => model.RESPONDENT_ID)
    @Html.ValidationMessageFor(model => model.RESPONDENT_ID)

    @Html.LabelFor(model => model.BC_ID, "Binus Center")
    @Html.DropDownList("BC_ID", null)
    @Html.ValidationMessageFor(model => model.BC_ID)

    @Html.LabelFor(model => model.FULL_NAME)
    @Html.EditorFor(model => model.FULL_NAME)
    @Html.ValidationMessageFor(model => model.FULL_NAME)

    .... // more form controls

    @Html.LabelFor(model => model.CITY_ID, "City")
    @Html.DropDownList("CITY_ID", null)
    @Html.ValidationMessageFor(model => model.CITY_ID)

    @Html.HiddenFor(model => model.ENTRY_DATE)
    @Html.HiddenFor(model => model.AUDIT_TIME)

    <input type="submit" value="Create" class="btn btn-default" />
}

This is my controller :

public class RespondentController : Controller
{
    private RespondentBINUSEntities db = new RespondentBINUSEntities();

    public ActionResult Create()
    {
        ViewBag.CITY_ID = new SelectList(db.LTCITies, "CITY_ID", "CITY_NAME", 1);
        var entry = new Models.TRRESPONDENT
        {
            ENTRY_DATE = DateTime.Now,
            AUDIT_TIME = DateTime.Now,
        };
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "RESPONDENT_ID,BC_ID,BINUSIAN_ID,FULL_NAME,EMAIL,PHONE_NUMBER,ADDRESS,CITY_ID,ZIP_CODE,SOURCE_ID,ENTRY_DATE,PACKAGE,AUDIT_USER_NAME,AUDIT_TIME,AUDIT_ACTIVITY")] TRRESPONDENT tRRESPONDENT)
    {
        if (ModelState.IsValid)
        {
            db.TRRESPONDENTs.Add(tRRESPONDENT);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        ViewBag.CITY_ID = new SelectList(db.LTCITies, "CITY_ID", "CITY_NAME", tRRESPONDENT.CITY_ID);
        return View(tRRESPONDENT);
    }
}

Upvotes: 1

Views: 1145

Answers (1)

user3559349
user3559349

Reputation:

You have not stated the details of the error message, but no doubt this is because you saving a values of 01/01/0001 to a field which which is DATETIME (which only accepts dates between 01/01/1753 to 12/31/9999) and not DATETIME2.

The reason the values of you dates are 01/01/0001 (which is the default for DateTime) is because you do not pass a model to the view so default values are used. The code in your GET needs to be

public ActionResult Create()
{
    ViewBag.CITY_ID = new SelectList(db.LTCITies, "CITY_ID", "CITY_NAME", 1);
    var entry = new Models.TRRESPONDENT
    {
        ENTRY_DATE = DateTime.Now,
        AUDIT_TIME = DateTime.Now,
    };
    return View(entry); // return your model
}

However you should not use your data model in the view, and instead create a view model containing only the properties you need. Values such as ENTRY_DATE should only be set immediately before you save the data model to the database. For information on a creating a view model, refer What is ViewModel in MVC?.


The basic steps for creating a view model are

  1. Create a new folder (say) ViewModels and copy you data model to and and rename it (say)RespondentVM
  2. Delete all the [Display] attributes from you data model (they are view specific attributes)
  3. Delete all the properties which the user will not be editing in the view (e.g ENTRY_DATE and AUDIT_TIME) except the property which is the objects ID which should be renamed to ID so its automatically bound assuming your using the default routes (note its not clear if you even have an ID property - I assume its RESPONDENT_ID, but that should be an auto-incremented int in the database -i.e. [Key]public int RespondentId { get; set; }). I also recommend you rename all your properties to follow naming conventions - EntryDate, not ENTRY_DATE.
  4. Change all value types to be nullable and add the [Required] attribute to protect against under-posting attacks (e.g. public int CITY_ID { get; set; } becomes public int? CityID { get; set; }
  5. Add additional properties for SelectList's etc that you are currently assigning to ViewBag properties, e.g. public IEnumerable<SelectListItem> CityList { get; set; }

You controller methods will then be

public ActionResult Create()
{
    RespondentVM model = new RespondentVM();
    ConfigureViewModel(model);
    return View(model);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(RespondentVM model) // note a [Bind]` attribute is not required
{
    if (!ModelState.IsValid)
    {
        ConfigureViewModel(model);
        return View(model);
    }
    // Initialize an instance of your data model and set its properties based on the view model
    TRRESPONDENT respondent = new TRRESPONDENT()
    {
        FULL_NAME = model.FullName,
        CITY_ID = model.CityID,
        ....
        // Set default values
        ENTRY_DATE = DateTime.Now,
        ....
    }
    db.TRRESPONDENTs.Add(respondent);
    db.SaveChanges();
    return RedirectToAction("Index");
}

// Common code for populating SelectLists etc - DRY!
private void ConfigureviewModel(RespondentVM model)
{
    // Note - delete the 4th parameter of the SelectList constructor
    model.CityID = new SelectList(db.LTCITies, "CITY_ID", "CITY_NAME");
}

And a few extra notes on your view code.

  1. You do not need a hidden input for the ID property if its named ID and your using the default routing
  2. Since you have [Display(Name = "..")] attributes, then in the view its just @Html.LabelFor(m => m.PropertyName), not @Html.LabelFor(m => m.PropertyName, "some text")
  3. To generate your dropdownlists, use @Html.DropDownListFor(m => m.CityID, Model.CityList, "Please select", new { ... }); - you current implementation will not give correct 2-way model binding or client side validation.

Upvotes: 1

Related Questions