I would like to enable the update button after form submittal. Here's my code:
VIEW:
#using (Html.BeginForm("ProcessTech", "Home", FormMethod.Post))
{
#Html.TextBoxFor(m => m.techNo, new { #class = "form-control maintain-text", placeholder = "Technician No..." })
<span class="input-group-btn">
<button type="submit" id="search" name="SubmitButton" value="search" class="btn btn-default">
<i class="fa fa-search"></i>
</button>
</span>
<td>First Name :</td>
<td class="display-field">#Html.TextBoxFor(m => m.firstName, new { #class = "form-control", style = "width:380px;", disabled = "disabled" })</td>
<td>Last Name :</td>
<td class="display-field">#Html.TextBoxFor(m => m.lastName, new { #class = "form-control", style = "width:380px;", disabled = "disabled" })</td>
<button name="SubmitButton" value="update" id="update" type="submit" style = "float:right;margin-right:10px; border-radius:5px;" class="btn btn-default" disabled><i class='fa fa-edit fa-fw'></i>Update</button>
}
The update button, firstname & lastname textboxes has a 'disabled' attribute.
After searching the technician number, the form will be updated with the firstname & lastname values that corresponds to the tech number.
Now I want to remove the disabled attribute of the update button, firstname and lastname so that it can be edited and updated. What's the best way to do this?
I tried this:
SCRIPT:
$(document).ready(function () {
$("#search").click(function () {
$("#update,#firstName,#lastName").removeAttr("disabled");
});
});
It enables the elements while the form is submitting but as soon as the form is submitted the page reloads with the values already in the textboxes and disables back the elements.
When you post the form to the controller you can return a value in the model to the view, which will determine if the button will be disabled or enabled, or you can also use #Viewbag.disableUpdate so that after post the button renders correctly
<button name="SubmitButton" value="update" id="update" type="submit" class="btn btn-default" #ViewBag.disableUpdate ><i class='fa fa-edit fa-fw'></i>Update</button>
From the controller pass #ViewBag.disableUpdate="" // to make it enable
and #ViewBag.disableUpdate="disable"; // to make it enabled
I've modified my code based on Maneesh's answer and here's what I've come up:
MODEL:
public bool setEnable { get; set; }
public IndexModel() { setEnable = false; } //constructor
CONTROLLER:
public ActionResult Index()
{
return View(new IndexModel());
}
[HttpPost]
public ActionResult ProcessTech(string SubmitButton)
{
IndexModel _oTechModel = new IndexModel();
switch (SubmitButton)
{
case "search": //search technician
{
_oTechModel.setEnable = true;
}
break;
}
return View("Index", _oTechModel);
}
VIEW:
#model Maintenance_.Models.IndexModel
#{
ViewBag.Title = "Technician";
if(Model.setEnable==true)
{
ViewBag.disableUpdate = "";
}
else{
ViewBag.disableUpdate = "disabled";
}
}
//HTML codes goes here..
Related
I am having a hard time figuring out how to make Html.BeginForm to return the current Instance of Model instead of a new instance.
To explain what is wrong, when i write somthing in the TextBoxFor() and click on the submit button in the html.beginform(), it correctly does the AddStatus() and places it in the statusDict with the right key and is displayed on the right side in the view in the foreach loop. When i then click on the "fortsæt" button on the right side, it corrects loads the value into the TextBoxFor since i have it default to Model.MailTitel. Now i want to change what is in the Model.Mailtitel and when i click submit i want it to return this specific instance of the model to the controller but with a new value for MailTitel and since this would be a instance of the model already in the statusDict, it should just update the #status.Value.MailTitel. However since Html.BeginForm() returns a new instance of the model and thus is not in the statusDict which leads to it being added to it and thus shows as a new card on the right side.
So my question is: How to make Html.BeginForm() return the same instance of Model as the controller gave to the view?
Code:
View:
#using DS_Prototype.Models
<!--Left side - Info filling -->
<div class="split left">
#using (Html.BeginForm("Submit", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken() // helps mitigate against cross-site request forgery
#Html.TextBoxFor(Model => Model.MailTitel, new { #Value = Model.MailTitel })
<button type="submit" class="btn btn-block btn-login">Submit</button>
}
</div>
<!--Right side - Status overview -->
<div class="split right">
#foreach (KeyValuePair<string, DriftStatus> status in (Dictionary<string, DriftStatus>)Session["statusDict"])
{
<div class="card">
<div class="card-body">
#status.Value.MailTitel
<div class="btn-group btn-group-justified">
#Html.ActionLink("Fortsæt", "ContinueStatus", "Home", new { status_id = status.Key }, new { #class = "btn btn-primary" })
#Html.ActionLink("Afslut", "EndStatus", "Home", new { #class = "btn btn-primary" })
</div>
</div>
</div>
}
</div>
Controller:
public ActionResult Submit(DriftStatus driftstatus) {
AddStatus(driftstatus);
ModelState.Clear();
return View("Index", new DriftStatus());
}
public ActionResult ContinueStatus(string status_id)
{
return View("Index",FindStatus(status_id));
}
private DriftStatus FindStatus(string key)
{
Dictionary<string, DriftStatus> statusDict = Check_statusDict();
DriftStatus driftstatus = statusDict[key];
if (driftstatus == null)
{
return new DriftStatus();
}
return statusDict[key];
}
private void AddStatus(DriftStatus driftstatus)
{
Dictionary<string, DriftStatus> statusDict = Check_statusDict();
if (!statusDict.ContainsKey(driftstatus.Created))
{
driftstatus.Created = DateTime.Now.ToString();
statusDict.Add(driftstatus.Created, driftstatus);
}
}
I have two buttons but I'm only able to validate one. When the user clicks add and the entire form is not filled out then they get error message but if they click finish instead of giving error messages, it goes to another page but I want to give the error before going to that page. This is what I have so far for one:
#model student.Models.Student
<h2>Student Record</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Issue</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.studentNumber, htmlAttributes: new { #class = "col-md-2" })
#Html.EditorFor(model => model.studentNumber, new { htmlAttributes = new { #readonly = "readonly", #id = "reqnum", #class = "form-control" } })
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "col-md-2" })
#Html.ValidationMessageFor(model => model.name, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.Label("Processed by:", htmlAttributes: new { #class = "col-md-2" })
#Html.DropDownListFor(model => model.processedbyDetails.employeeNum, new SelectList(ViewBag.StoresReps, "Value", "Text"), new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.processedbyDetails.employeeNum, "", new { #class = "text-danger" })
</div>
#* -- MANY OTHER INPUTS -- *#
<div class="form-group">
<div class="col-md-offset-4 col-md-12">
<input type="submit" value="Add" name="Add" class="btn btn-default" width="89" />
<input type="button" value="Finish" name="Issue" margin="50px" onclick="location.href='#Url.Action("ViewIssue", "Issue")' " class="btn btn-default" />
<input type="button" value="Cancel" name="Cancel" margin="50px" onclick="location.href='#Url.Action("Cancel", "Issue")' " class="btn btn-default" />
</div>
</div>
</div>
}
Edit
#{
ViewBag.Title = "Student Item";
}
<!-- JS includes -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/mvc/4.0/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript">
<script type="text/javascript">
function onFinishClick() {
if ($('form').valid()) {
location.href = '#Url.Action("ViewIssue", "Issue")';
}
return false;
}
</script>
<input type="button" value="Finish" name="Issue" margin="50px" onclick="onFinishClick()" class="btn btn-default" />
You're using MVC, so just annotate your ViewModel and submit the form with the built in functionality that the framework supplies for you.
public class Student
{
[StringLength(100)]
[DisplayName("Student Name")]
[Required(ErrorMessage = "Please enter a Student Name")]
public string Name { get; set; }
[StringLength(100)]
[DisplayName("Student Number")]
[Required(ErrorMessage = "Please enter a Student Number")]
public string StudentNumber { get; set; }
// etc...
}
Your form should also have the name of the Action you're trying to POST to...
#using (Html.BeginForm("AddOrFinish", "HomeController", FormMethod.Post, new { role = "form" }))
You can't validate against the data annotations on your viewmodel in MVC from a button that's not of type submit (well, maybe you can, but probably more work).
You should then mark both buttons as type submit, then interrogate the name of the button that was clicked once it is sent over.
<div class="form-group">
<div class="col-md-offset-4 col-md-12">
<input type="submit" value="Add" name="add" class="btn btn-default" width="89" />
<input type="submit" value="Finish" name="issue" margin="50px" class="btn btn-default" />
<input type="button" value="Cancel" name="Cancel" margin="50px" onclick="location.href='#Url.Action("Cancel", "Issue")' " class="btn btn-default" />
</div>
</div>
Then in your controller, create a method with this signature. Since you have two submit buttons, the values of the button will be sent along in the request and you can interrogate it. It will look something like this...
[HttpPost]
public ActionResult AddOrFinish(Student model, string add, string issue)
{
if (!ModelState.IsValid)
{
return RedirectToAction("PageImOnNow", model);
}
if (!string.IsNullOrEmpty(add))
{
// do your add logic
// redirect to some page when user clicks "Add"
return RedirectToAction("WhateverPageYouWant");
}
else
{
// do your finish logic
// redirect to ViewIssue page when user clicks "Finish"
return RedirectToAction("ViewIssue");
}
}
More information here -
Handling multiple submit buttons on a form in MVC
Best Practices for ViewModel validation in MVC
I have a main index page that loads a partial view that contains a dropdownfor list. The selection of an item from the ddl populates controls in a separate partial view for display. Clicking Edit pops open a model with a Form of EditorFor controls bound to the model properties for the selected item. When the submit button for the modal is clicked. It posts back the form for updating to the database...at which point I want to basically refresh the partial view that contains the dropdownlist so that it reflects the changes is appropriate.
The code I have performs all the basic mechanics without issue EXCEPT for refreshing the partial view that contains the dropdownlistfor control. I could just do a redirecttoaction for the index page and refresh the entire page but I would prefer to only refresh the partial view. I can not figure out how to make this happen and am wondering if someone has a suggestion.
The code div code for the index page is:
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<br />
<div class="partialContent" data-url="/Database/GetDatabases">
#Html.Partial("_GetDatabases")
</div>
<br />
<div class="modal fade" id="modalEditDBInfo" role="application" aria-labelledby="modalEditDBInfoLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modalEditDBInfoContent" style="background-color:white; border-radius:10px; box-shadow:10px;">
#Html.Partial("_EditDatabaseInfo")
</div>
</div>
</div>
The code for the EditDatabase partial view
#model Hybridinator.WebUI.Models.DatabaseModel
<br />
<br />
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="editModelTitle">Edit Database Info</h4>
</div>
#if(Model != null)
{
using (Html.BeginForm("EditDatabaseInfo", "Database", FormMethod.Post, new { #class = "modal-form" }))
{
<div class="modal-body">
#Html.HiddenFor(m => m.database_pk, new { htmlAttributes = new { #class = "form-control" } })
<div class="form-group">
<div id="databaselabel">#Html.LabelFor(m => m.database_name, "Database")</div>
<div id="databaseedit">#Html.EditorFor(m => m.database_name, new { htmlAttributes = new { #class = "form-control" } })</div>
</div>
<div class="form-group">
<div id="databaseserverlabel">#Html.LabelFor(m => m.database_server, "Database Server")</div>
<div id="databaseserveredit">#Html.EditorFor(m => m.database_server, new { htmlAttributes = new { #class = "form-control" } })</div>
</div>
</div>
<div class="form-group">
<div id="editsqltypelabel">#Html.LabelFor(m => m.sql_type_pk, "Sql Type")</div>
<div id="editsqltypeddl">#Html.DropDownListFor(m => m.sql_type_pk, Model.sqlTypes)</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button class="btn btn-inverse btn-primary" type="submit">Save</button>
</div>
}
}
The code for the GetDatabases partial view
#model Hybridinator.WebUI.Models.DatabaseListModel
#if(Model != null)
{
<div id="databasedropdown" class="container-fluid">
#Html.Label("Databases: ")#Html.DropDownListFor(m => m.database_pk, Model.databases, "Select one...", new { #id = "database_pk", onchange = "changeDatabase()" })
</div>
}
The Controller code for GetDatabases
public ActionResult GetDatabases()
{
DatabaseListModel databaseListModel = new DatabaseListModel
{
databases = databaseService.GetUndeletedDatabaseList().
Select(d => new SelectListItem
{
Value = d.database_pk.ToString(),
Text = d.database_name
}).ToList()
};
return PartialView("_GetDatabases",databaseListModel);
}
and last the code for both the Get and Post for the EditDatabase modal
[HttpGet]
public ActionResult EditDatabaseInfo(int database_pk)
{
DatabaseModel databaseModel = FillDatabaseModelByDatabasePK(database_pk);
return PartialView("_EditDatabaseInfo", databaseModel);
}
[HttpPost]
public ActionResult EditDatabaseInfo(DatabaseModel databaseModel)
{
string[] result = databaseService.Update(new Database
{
database_pk = databaseModel.database_pk,
database_name = databaseModel.database_name,
database_password = databaseModel.database_password,
database_username = databaseModel.database_username,
database_server = databaseModel.database_server,
hist_database_name = databaseModel.hist_database_name,
hist_database_server = databaseModel.hist_database_server,
hist_database_password = databaseModel.hist_database_password,
hist_database_username = databaseModel.hist_database_username,
sqlType = new SQLType { sql_type_pk = databaseModel.sql_type_pk }
});
return RedirectToAction("GetDatabases");
}
As I said the RedirectToAction("Index) returned in the Post EditDatabase controller method works in a pinch..but I really dont want to have to refresh the whole page. I assume there is something I can do differently in the return on that method to just reload the GetDatabases partial but I can't figure it out. Any help would be appreciated.
Carl who comments up above provided the solution. Buts since he just commented Ill post the code modifications here so if someone is looking for a similar issue they can see the code.
As per Carl's suggestion I used the Ajax.BeginForm rather than the HTML.BeginForm and IM updating the partial view controller through the onsuccess handler.
I replaced this line in the EditDatabase partial
using (Html.BeginForm("EditDatabaseInfo", "Database", FormMethod.Post, new { #class = "modal-form" }))
with this
using (Ajax.BeginForm("EditDatabaseInfo", "Database", new AjaxOptions{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnSuccess = "editDatabaseSuccess"
}, new { #id = "editDatabaseForm" }))
Then in my scripts I made a function for the editDatabaseSucess
<script type="text/javascript">
function editDatabaseSuccess(data)
{
//alert(data);
$('#modalEditDBInfo').modal('hide');
loadDatabases();
}
</script>
The alert(data; commented out line was just for testing to make sure the function was being called.
the loadDatabases(); line calls the function I use on page load to load the partial view.
<script type="text/javascript">
function loadDatabases()
{
$(".partialContent").each(function (index, item) {
var url = $(item).data("url");
if (url && url.length > 0) {
$(item).load(url)
}
});
}
</script>
Works perfectly now. Much thanks to Carl for the answer.
The controller file in the application HomeController.cs, defines the two controls SetPowerOff and [HttppPost] SetPowerOff.
public ActionResult SetPowerOff(int ID, string deepness)
{
.............
if (Request.IsAjaxRequest())
{
var viewModel = new HomeSetPowerOffViewModel()
{
//List of devices
Devicelist = list,
age = 18
};
return PartialView("_SetPowerOff", viewModel);
}
else
{
return HttpNotFound();
}
}
[HttpPost]
public ActionResult SetPowerOff(HomeSetPowerOffViewModel homeSetPowerOffViewModel)
{
}
The Partial View returns the devices in a list.
#using (Html.BeginForm("SetPowerOff", "Home", FormMethod.Post, new { #class = "form-horizontal" }))
{
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">X</button>
<h3 id="myModalLabel">Devices information</h3>
</div>
<div class="modal-body ">
<div class="row-fluid">
<div class="span12">
<ul>
#foreach (var devices in Model.Devicelist)
{ <li>
#devices.Name;
</li>
}
</ul>
</div>
</div>
</div>
<div class="modal-footer">
#Html.ActionLink("Cancel", "Index", "Home", new { #class = "btn btn-danger" })
<button type="submit" class="btn btn-success">
Ok
</button>
</div>
}
After I press the Ok button on the Partial View it goes to the HttpPost request. Here the homeSetPowerOffViewModel received is null and the age is 0. I would very much like to know why is resetting them.
Thanks for your time!
you dont have any inputs in your form so there is nothing to submit
Your view<form>does not contain the form field like <input><select><textarea> for the age field.
So when you submit, it will be set to default integer value 0
Assuming age property of HomeSetPowerOffViewModel is a type of integer (int)
On post you receive hidden or any other input fields ( dropdowns, textbox and so on ). There is no such fields in your form. ( you are not filling the model in any way )
Althought, you can submit with ajax and you can send whatever you want to your controller
I am dynamically populating form(s) in my view (MVC) and I can have one or many forms on the same page. Each form is uniquely named, however the field variables in each form remain the same.
It works a treat with each form having its own submit button and passing the input to my Post Controller method, but now I need to add the option to submit all or one form by clicking the "next page" link. As I already have JQuery loading, I am trying to do this with Ajax and Json but I am stuck.
View
#using Microsoft.AspNet.Identity
#model IEnumerable<Template.Models.GetViewModel>
#{
ViewBag.Title = "About me";
ViewBag.Page = Model.First().PageNumber;
}
#Html.AntiForgeryToken();
#foreach (var q in Model.OrderBy(o => o.QuestionRanking))
{
var qtype = q.QuestionTypeId;
Html.BeginForm("ViewQuestion", "Question", FormMethod.Post, new { #class = #q.ShowHide + " form-horizontal", id = #q.FormNumber, role = "form" });
<div>
<h1>#q.QuestionRanking. #q.Question1</h1>
</div>
<div class="form-group">
#Html.TextArea("Answer", q.Answer, new { #class = "form-control", rows = "4", cols = "10" })
</div>
<div class="form-group">
<input type="submit" name="#q.FormNumber" class="btn btn-primary" value="Save answer" />
</div>
<hr />
Html.EndForm();
}
<p>
#Html.ActionLink("Previous", "ViewQuestion", new { page = ViewBag.Page - 1 }) |
#Html.ActionLink("Next", "ViewQuestion", new { page = ViewBag.Page + 1 })
</p>
#section Scripts {
#Scripts.Render("~/bundles/jquery")
}
The controller
[HttpPost]
public ActionResult ViewQuestion([Bind(Include = "QuestionId, UserId")] ResponseViewModel responseViewModel)
{
var page = System.Web.HttpContext.Current.Request["page"];
var newAnswer = System.Web.HttpContext.Current.Request["Answer"];
var re = new Response
{
Answer = newAnswer,
UserId = responseViewModel.UserId,
QuestionId = responseViewModel.QuestionId,
};
_db.Responses.Add(re);
_db.SaveChanges();
}
I haven't gotten very far with my script and I am lost as to how to get the values to my controller;
<script>
function postValues() {
var str = $( "form" ).serialize();
$( "#results" ).text( str );
}
</script>
Any advice or examples would be greatly appreciated.
To use ajax you can convert your forms using the following
#using(Ajax.BeginForm("ViewQuestion","Question",null,new AjaxOptions{ options here },
new { #class = #q.ShowHide + " form-horizontal", id = #q.FormNumber, role = "form"
}))
{
#Html.AntiForgeryToken();
<div>
<h1>#q.QuestionRanking. #q.Question1</h1>
</div>
<div class="form-group">
#Html.TextArea("Answer", q.Answer, new { #class = "form-control", rows = "4",
cols = "10" })
</div>
<div class="form-group">
<input type="submit" name="#q.FormNumber" class="btn btn-primary"
value="Save answer" />
</div>
<hr />
}
then you can use jquery to submit each form
$('form').each(function(){
$(this).submit();
});
with regards to #Html.AntiForgeryToken(); this should be within each form, and if you want to use it you need to add [ValidateAntiForgeryToken] to your controller action