Here's my cshtml code:
#model pedidosOnlineMVC.Models.Administrador
#{
Layout = "~/Views/SuperUser/_LayoutSU.cshtml";
}
#using (var f = Html.Bootstrap().Begin(new Form()))
{
#f.FormGroup().CustomControls(Html.AntiForgeryToken())
#f.FormGroup().TextBoxFor(model=>model.nome)
#f.FormGroup().TextBoxFor(model=>model.cpf).Data(new {mask="999.999.999-99"})
#f.FormGroup().TextBoxFor(model=>model.telefone).Data(new {mask="(99)99999-9999"})
#f.FormGroup().TextBoxFor(model=>model.login)
#f.FormGroup().PasswordFor(model=>model.senha)
#f.FormGroup().TextBoxFor(model => model.fim_gerencia).Data(new { provide = "datepicker", date_format = "mm/dd/yyyy" })
#f.FormGroup().CustomControls(#Html.Bootstrap().SubmitButton().Text("Cadastrar"))
}
And here's view's controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult cadAdmin([Bind(Include = "Administrador_Id, nome, cpf, telefone, login, senha, fim_gerencia")] Administrador adm)
{
if (ModelState.IsValid)
{
if (Helpers.Helpers.validaCPF(adm.cpf))
if (db.Administrador.ToList().Where(x => x.cpf == adm.cpf).ToArray().Length == 0)
{
adm.senha = System.Text.Encoding.Default.GetString(SHA1.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(adm.senha)));
db.Administrador.Add(adm);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
ModelState.AddModelError("cpf", "CPF já cadastrado");
return View("Index", "Index");
}
else
{
ModelState.AddModelError("cpf", "CPF inválido");
return View(adm);
}
}
Type type = adm.GetType();
PropertyInfo[] props = type.GetProperties();
for (int i = 2; i < props.Length; i++)
if (ModelState.Values.ToList()[i-2].Errors.Count>0)
ModelState.AddModelError(props[i].Name, props[i].Name + " inválido");
return PartialView(adm);
}
The problem that I have is that the date value from the field fim_gerencia is not passing through. Everything else works fine, excepet the Date.
I'm using the datepicker found here: http://bootstrap-datepicker.readthedocs.org/en/release/
It shouldn't be a problem though, beacause I'm using date on another class and it works fine with he exact same code.
Anyone know what's wrong?
In your situation, first thing I would check is the id of the textbox of the date field. Does it contain the expected id value? e.g.
<input ..... id="fim_gerencia"......
If that's correct, then open the Network window in the browser dev tools. When you submit the page, have a look at the request by clicking on it in the Network page. Take a look at the request details, a section of which will be the form values passed to the server. In that section look for fim_gerencia.
Do those first.
If it's still not being passed, try removing the [Bind(Include=.... bit, as you don't need that in your example. It's worth removing that attribute and checking the result.
Related
I have this form with a lot of input fields in page including dropdownlist, textboxes and textarea. And at the end of page, I have file uploading field.
The problem is when I entered all the data in the fields and I attached a file at the end, all the data I entered disappears and I need to retype again.
I have this code below. Here I use a Session to hold the data to retain the values entered in fields when uploading a file, but still the data disappears after a file has uploaded.
Can someone help me resolve this? Thank you so much.
CONTROLLER
[HttpGet]
[Authorize]
public ActionResult Create()
{
All_Issues all_Issues = new All_Issues();
ViewBag.StatusID = new SelectList(db.issue_status_ref, "StatusID", "StatusName");
ViewBag.IncLevelID = new SelectList(db.incident_level_ref, "IncLevelID", "Description");
ViewBag.DeptID = new SelectList(db.all_department_ref, "department_id", "department_name");
ViewBag.CatID = new SelectList(db.category_ref, "CatID", "Category");
ViewBag.NocID = new SelectList(db.nature_of_occurrence_ref, "NocID", "Title");
ViewBag.UsersID = new SelectList(db.ad_users, "user_id", "display_name");
if (Session["ir_session"] != null)
{
return View("Create", (All_Issues)Session["ir_session"]);
}
return View(new All_Issues());
}
FILE UPLOAD
[HttpPost]
public ActionResult FileUpload(Guid? IRID, All_Issues all_Issues)
{
Session["ir_session"] = all_Issues;
HttpFileCollectionBase ir_files;
List<files_ref> ir_uploadFileModel = new List<files_ref>();
ir_files = Request.Files;
string mapPath = "~/App_Data/UploadedFiles/";
FileUploads ir_fileupload = new FileUploads();
ir_fileupload.UploadFiles(null, null, IRID, ir_files, mapPath, "IR");
if (IRID == null)
{
return RedirectToAction("Create");
}
else
{
return RedirectToAction("Edit", new { id = IRID });
}
}
Already found a solution to this. Just took a long time to post an update.
What I did is still the same. I use session to store the data in my fields and I call this session in every action so that whenever I made a lot of action in the form, the data will retain until the page is submitted.
if (Session["ir_session"] != null)
{
IMRDTO model = (IMRDTO)Session["ir_session"];
return View("Create", (IMRDTO)Session["ir_session"]);
}
And with this line of code, which I call in every action, I retain all the data in fields even when the page reloaded.
Session["ir_session"] = imr;
Hoping it would also help someone.
I have already looked at these links for references.
Link 1: ASP.Net MVC and state - how to keep state between requests
Link 2: ASP.NET MVC: Keeping last page state
I have a few pages that a user will be filling out. We will call these pages Page 1. If they get to a field that they need to select from, drop down, but need to create a new item to be included in the drop down, because it will be used again later, they go to a new page, Page 2, to create the item. After create they create the item they are returned to Page 1 to finishing filling out the form. The problem is that the Page 1 is now erased because is a new page load. I would like for this to persist for when they come back so they don't have to refill out fields.
The route I am currently Link2 using a cookie. I don't know how to set the cookie's info before it gets to the next page, or how to pass it to that page before since it is going to a GET method and not a POST.
GET method for Page 1:
public ActionResult Create()
{
var courseTitles = (from title in db.CourseTitles
join type in db.CourseTypes on title.Type equals type.CourseTypeID
select new
{
CourseTitleID = title.CourseTitleID,
Title = title.Title + " - " + type.Type
});
Course course = new Course();
if (Request.Cookies["CourseInfo"] != null) //If it's not null, set the model.
{
HttpCookie cookie = Request.Cookies["CourseInfo"];
course.ClassNumber = Convert.ToInt32(cookie.Values["ClassNumber"]);
course.CourseStartDate = Convert.ToDateTime(cookie.Values["StartDate"]);
course.CourseEndDate = Convert.ToDateTime(cookie.Values["EndDate"]);
ViewBag.CourseList = new SelectList(courseTitles, "CourseTitleID", "Title", cookie.Values["CourseTitle"]);
return View(course);
}
ViewBag.CourseList = new SelectList(courseTitles, "CourseTitleID", "Title");
return View();
}
GET and POST method for Page 2:
public ActionResult NewCourseTitle()
{
ViewBag.Type = new SelectList(db.CourseTypes, "CourseTypeID", "Type");
return View();
}
//
//Post:
[HttpPost]
public ActionResult NewCourseTitle(CourseTitle courseTitle)
{
if (ModelState.IsValid)
{
db.CourseTitles.AddObject(courseTitle);
db.SaveChanges();
return RedirectToAction("Create", "Course");
}
return View();
}
Let me know if you need more code.
You can use TempData to store objects between requests:
public ActionResult Create()
{
var courseTitles = (from title in db.CourseTitles
join type in db.CourseTypes on title.Type equals type.CourseTypeID
select new
{
CourseTitleID = title.CourseTitleID,
Title = title.Title + " - " + type.Type
});
Course course = new Course();
if (TempData["CourseInfo"] != null) //If it's not null, set the model.
{
course = TempData["CourseInfo"] as Course;
ViewBag.CourseList = new SelectList(courseTitles, "CourseTitleID", "Title", course.Title);
return View(course);
}
ViewBag.CourseList = new SelectList(courseTitles, "CourseTitleID", "Title");
return View();
}
In order to store the Course simply use TempData["CourseInfo"] = course
TempData exposes couple of options that define for how long its content is going to be persisted. You can read about it here
You could use some JavaScript to modify the GET request to NewCourseTitle so that it will contain the course data that the user entered.
With jQuery it could look roughly like this:
$(function () {
var newCourseTitleLink = $('#new-course-title-link');
newCourseTitleLink.on("click", function ()
{
document.location.href = newCourseTitleLink.attr('href') + '?' + $('#course-data-form').serialize();
});
});
Then you can create a cookie in your action method NewCourseTitle:
public ActionResult NewCourseTitle(int classNumber, ... /*other form values*/)
{
var cookie = new HttpCookie("CourseInfo");
cookie.Values.Add("ClassNumber", classNumber.ToString());
...
Response.SetCookie(cookie);
ViewBag.Type = new SelectList(db.CourseTypes, "CourseTypeID", "Type");
return View();
}
Update I have saved my problem a long time ago. The problem was that I was trying to call the view model on the wrong view method! I was calling the base view method (Document), instead of one of it's derived method (like NewDocument, PDFDocument, etc.) Thus it was only giving me the Documents data, which didn't change. I was looking and using the wrong view method all the time... Stephen, when you asked me
"Why do you create derived classes in a method but then return only the base class"
I couldn't answer the question at the time because I didn't even know myself, until I remember that originally, the method wasn't returning the base class. I only changed it so that it can work with the base view method, which was wrong in the first place!
That's what I get for only getting 3-4 hours of sleep in 3 days. Everything works right now. Thanks.
I'm having a hard time trying to figure out why the data in my view isn't changing after I do a post. Originally I was doing it via return View() and it worked, but since it was a partial view, the page didn't look great, so I was reading up and saw that it was better to do it by Post-Redirect-Get pattern (PRG) and to use an id value to retrieve the values instead of sending the entire model via Tempdata. I even used ModelState.Clear() and that didn't even work. When I debugged the code, the model only has the values from when I first called it.
Here's part of my Get controller:
NewDocument Get Controller
[DocumentAuthenticationFilter]
public ActionResult NewDocument(int? id = null)
{
// This doesn't work. The view keeps on showing the data from View(Services.CreateNewDocument()).
if (id != null)
{
return View(Services.GetdocumentViewModelData(DocEnum.Section.NEW_DOC_INDEX, (int)id));
}
// This works fine
return View(Services.CreateNewDocument());
}
And here's the post that calls the redirect:
NewDocument Post controller
[HttpPost]
[ValidateAntiForgeryToken]
[MultipleButton(Name = "action", Argument = "AddDocuments")]
//[OutputCache(Duration = 30, VaryByParam = "*")]
public ActionResult AddDocumentViewModel(FormCollection frm, DocumentViewModel dvm)
{
try
{
if (ModelState.IsValid)
{
int? DocID = Services.AddingNewDocument(dvm);
// See, I even tried to clear it.
ModelState.Clear();
return base.RedirectToAction("NewDocument", new { id = DocID });
}
else
{
// Display errors in the modal
}
return base.RedirectToAction("NewDocument");
}
And here's the old way I did it:
NewDocument Post controller
[HttpPost]
[ValidateAntiForgeryToken]
[MultipleButton(Name = "action", Argument = "AddDocuments")]
//[OutputCache(Duration = 30, VaryByParam = "*")]
public ActionResult AddDocumentViewModel(FormCollection frm, DocumentViewModel dvm)
{
try
{
if (ModelState.IsValid)
{
Services.AddingNewDocument(ref dvm);
dvm.NewRecordMode = DocEnum.Action.UPDATE;
// It worked, but only the partial view showed, and not the entire view.
return PartialView("_NewDocument", dvm);
}
else
{
// Display errors in the model
}
return base.RedirectToAction("NewDocument");
}
Could it be because I'm using a custom model binding?
My Custom Model Binding
public class BaseClassModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var modelType = bindingContext.ModelType;
var modelTypeValue = controllerContext.Controller.ValueProvider.GetValue("ViewModel");
if (modelTypeValue == null)
throw new Exception("View does not contain the needed derived model type name");
var modelTypeName = modelTypeValue.AttemptedValue;
var type = modelType.Assembly.GetTypes().SingleOrDefault(x => x.IsSubclassOf(modelType) && x.Name == modelTypeName);
if (type == null)
{
throw new Exception(String.Format("Derived model type {0} not found", modelTypeName));
}
var instance = bindingContext.Model ?? base.CreateModel(controllerContext, bindingContext, type);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, type);
return base.BindModel(controllerContext, bindingContext);
}
}
EDIT: And here's the GetDocumentViewModelData code:
GetDocumentFromViewModelData
public static DocumentViewModel GetDocumentViewModelData(DocEnum.Section docType, int id)
{
switch (docType)
{
case DocEnum.Section.NEW_DOCUMENT_INDEX:
// NewDocumentTypeViewModel is a child to DocumentTypeViewModel
DocumentTypeViewModel nd = NewDocumentService.GetViewModelByID(id);
return nd;
case DocEnum.Section.PDF_DOCUMENT:
DocumentTypeViewModel pdfvm = PDFDocumentService.GetViewModelByID(id);
return pdfvm;
case DocEnum.Section.XLS_DOCUMENT:
DocumentTypeViewModel xlsvm = XLSDocumentService.GetViewModelByID(id);
return xlsvm;
}
return null;
}
Edit: Also adding the GetViewModelByID function
GetViewModelByID
public static DocumentTypeViewModel GetViewModelByID(int id)
{
docEntities db = new docEntities();
NewDocumentTypeViewModel vm = new NewDocumentTypeViewModel();
// Calls a stored procedure called Select_Documents_ByID(id) to get the note entry
// that was submitted.
List<Select_Documents_ByID_Result> prevNotes = db.Select_Documents_ByID(id).ToList();
StringBuilder sNotes = new StringBuilder();
foreach (var note in prevNotes)
{
sNotes.AppendFormat("{0} - {1}: {2}\n\n", note.CreatedDate.ToString("yyyy-MM-dd HH:mm"), note.username, note.Entry);
}
vm.PreviousNotes = sNotes.ToString();
return vm;
}
Edit: I did a direct creation of the view model inside the Get controller, and it's the same result. when i debugged the view itself, the values from the new view model don't show up. Instead, the values from the initial view model, View(Services.CreateNewDocument()), shows.
[DocumentAuthenticationFilter]
public ActionResult NewDocument(int? id = null)
{
// Right here I created the view model to test thing, but I'm getting the same results. Nothing has changed.
if (id != null)
{
var d = new NewDocumentTypeViewModel(1, "Help!");
// This property is from the base class, DocumentTypeViewModel
d.DocumentTitle = "Testing!";
return View(d);
// Inside the view itself, none of the values in the view model, including the one
// belonging to the base class. It still shows the initial values.
}
// This works fine
// Or maybe not...
return View(Services.CreateNewDocument());
}
Edit: I wanted to see if it was also doing the same thing for the initial call to the view return View(Services.CreateNewDocument()), and decided to change the value for documentTitle in the base class from New Document to a randomly-generated number, after the object has been created.
Here's the code for DocumentTypeViewModel's default constructor:
public DocumentTypeViewModel()
{
DocumentTitle = "New Document";
NewRecordMode = DocEnum.Action.ADD;
DocumentID = 0;
}
And here's the Services.CreateNewDocument() code where I change the DocumentTitle after the View Model has been created.
public DocumentTypeViewModel CreateNewDocument()
{
DocumentTypeViewModel dtvm = new DocumentTypeViewModel();
Random r = new Random();
dtvm.DocumentTitle = r.Next(5, Int32.MaxValue).ToString();
return dtvm;
}
Now in the View, when I call DocumentTitle:
<div class="label-text-group">
#Html.LabelFor(model => model.DocumentTitle)
#Html.EditorFor(model => model.DocumentTitle)
</div>
You would expect to see a randomly-generated number every time the View gets called. Nope, what you would see is "New Document". Weird.
It's seems that Services.GetDocumentViewModelData() is not exactly working correctly. It only carries the values created by the base class' constructor when a view is created, not any values that have been added or changed within GetDocumentViewModelData() itself. Why is that? What's going on? Please help anybody!
I have solved it. Look at the Update section on top. Thanks Stephen.
I am setting an error Message in the viewbag to show to the user after each postback how ever I do not want to show this error message on page reload or refresh. I have tried to set it to null but it still is shown because the json parameter still contains the values of the first submit.
[HttpPost]
[CustomAuthorize(Definitions.RoleAnalystManager, Definitions.RoleProjectManager)]
public ActionResult ExportReportAllMediaDetailsCsv(string json)
{
ViewBag.Error = null;
var serializer = new JavaScriptSerializer();
var reportParams = serializer.Deserialize<ReportAllMediaDetailsParams>(json);
var rows = uow.Items.Report_AllMediaDetails(reportParams.profileID, reportParams.organisationID, reportParams.startDate, reportParams.endDate).ToList();
if (rows.Count <= 1)
{
ViewBag.Error = "There were no results for the provided parameters, please adjust the parameters and try again.";
return View("AllMediaDetails");
}
This is because refreshing the page actually resubmits the previous request, so your POST request is resubmitted by the browser. Can't test this at the minute; however, perhaps try setting a bool - TempData["FirstLoad"] - to true on the GET request and then do something like this in the POST method:
if (TempData["FirstLoad"] != null && TempData["FirstLoad"] == true)
{
if (rows.Count <= 1)
{
ViewBag.Error = "...";
}
}
else
{
ViewBag.Error = null;
return View();
}
TempData["FirstLoad"] = false;
return View("AllMediaDetails");
I'm basing this on the fact that TempData is stored in the session, so its values should be retained on a refresh (rather than resubmitted as they were originally as if the value was passed as, for example, a hidden field).
I have this
<%=Model.StartDate%>
<%=Html.Hidden("StartDate", Model.StartDate)%>
it outputs:
2010-05-11 11:00:00 +01:00
<input type="hidden" value="2010-03-17 11:00:00 +01:00" name="StartDate" id="StartDate">
What the...
It's a paging mechanism so the hidden value was valid on the first page and I've been able to move forward to the next page. But since the values won't update properly it ends there.
What do I need to do?
Using firefox.
Update - more code
using (Html.BeginForm("Program", "Activities", null, FormMethod.Get, new { #name = "ProgramForm", id = "ProgramForm" }))
{
.
viewModel.StartDate = pagingService.StartDate;
return View(viewModel);
Update - complete action
[Authorize]
public ActionResult Program(string[] submit)
{
var viewModel = new ActivityProgramViewModel { UserID = LoggedInUser.UserID };
viewModel.Fresh = true;
TryUpdateModel(viewModel);
var pagingService = new OccurencePagingService(LoggedInUser.AllActivities.Where(a => a.StartTime != null));
if (!viewModel.Fresh)
{
pagingService.StartDate = ((DateTimeOffset)viewModel.StartDate);
pagingService.EndDate = ((DateTimeOffset)viewModel.EndDate);
}
if (submit != null)
if (submit.Contains("MoveBack"))
pagingService.MoveBack();
else if (submit.Contains("MoveForward"))
pagingService.MoveForward();
ViewData.Model = viewModel;
viewModel.Occurrences = pagingService.GetOccurences();
viewModel.Fresh = false;
viewModel.HasLess = pagingService.HasLess;
viewModel.HasMore = pagingService.HasMore;
viewModel.StartDate = pagingService.StartDate;
viewModel.EndDate = pagingService.EndDate;
return View();
}
First one uses Model object, second one uses existing ModelState. Look at ModelState values before generating view. It propably holds value for this field. Html helpers priveded by MVC use ModelState to generate form fields. It helps in recreating values after post back.
To get rid of this kind of problems, use POST-REDIRECT-GET pattern or just pass query parameters through GET.
I think the <%=Html.Hidden("StartDate", Model.StartDate)%> is out of place here.
Html Helpers try to keep data in the UI like they where entered by examining the post/route data. Please dont ask me how someone would ever enter data in a hidden field.
You want something different: You want to set the data to Model.StartDate and dont care what is in the post/route.
I would use <input value="<%=Model.StartDate%>" name="StartDate" /> .