ASP.NET MVC - Check Box List for Link Table Values - asp.net-mvc

Hoping someone can help me out, what I am trying to achieve a checkbox list (populated from a database table) which then inserts into a link table.
I'm not sure how best to achieve this, this is what I have so far which displays correctly, but I'm not sure how I can get this to save.
#using (Html.BeginForm("Create", "ReviewChecklistsController"))
{
foreach (var item in ViewBag.ChecklistId)
{
<div class="checkbox">
<label>
<input type="checkbox"
name="#item.Value"
value="#item.Value" /> #item.Text
</label>
</div>
}
<p></p>
<div class="form-group">
<input type="submit" class="btn btn-success" value="Save Checklist" />
</div>
}
Below is how I have set it up in the database, if you need any more information please let me know. I am using Entity Framework.
What I want is ReviewChecklist\ChecklistId to map to List_Checklist\ChecklistId and then State is just a boolean so if the checkbox is checked or not.

I've managed to get it working using the below. Is this okay, or is there a better way to do it?
#using (Html.BeginForm("Create", "ReviewChecklistsController"))
{
int i = 0;
foreach (var item in ViewBag.ChecklistId)
{
var nameStatus = "reviewChecklist[" + i + "].Status";
var nameReviewId = "reviewChecklist[" + i + "].ReviewId";
var nameChecklistId = "reviewChecklist[" + i + "].ChecklistId";
#Html.HiddenFor(model => model.ReviewId, new { Name = nameReviewId })
#Html.HiddenFor(model => model.ChecklistId, new { Name = nameChecklistId, Value = item.Value })
<p>
#Html.CheckBoxFor(model => model.Status, new { Name = nameStatus })
#item.Text
</p>
i++;
}
<p></p>
<div class="form-group">
<input type="submit" class="btn btn-success" value="Save Checklist" />
</div>
}

Related

Multiple forms in one view page

I'm working on an application that handles employee's profile.
I have 3 forms (all in the same controller) in a single view page, but it only saves the 1st form. And when i save the 2nd form, it clears the values of the 1st and 3rd form.
Here is my code:
Views/EMPs/Index:
#using (Html.BeginForm("Edit", "EMPs", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
<div class="pull-right">
<input type="submit" value="Update" name="personalsubmit" class="btn btn-success" />
</div>
</div>
}
#{ Html.RenderAction("Index", "EMP_REFERENCE", new { id = Model.eMP.lineno });}
#using (Html.BeginForm("Edit", "EMPs", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
<div class="pull-right">
<input type="submit" value="Update" name="jobsubmit" class="btn btn-success" />
</div>
</div>
}
#{ Html.RenderAction("Index", "EMP_BENEFITS", new { id = Model.eMP.lineno });}
#using (Html.BeginForm("Edit", "EMPs", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
<div class="pull-right">
<input type="submit" value="Update" name="otherssubmit" class="btn btn-success" />
</div>
</div>
}
EMPsController
public ActionResult Edit([Bind(Include = "lineno,EMPNO,IDNO..")] EMP eMP)
{
if (ModelState.IsValid)
{
if (Request.Form["personalsubmit"] != null)
{
db.Entry(eMP).State = EntityState.Modified;
db.SaveChanges();
}
if (Request.Form["jobsubmit"] != null)
{
db.Entry(eMP).State = EntityState.Modified;
db.SaveChanges();
}
if (Request.Form["otherssubmit"] != null)
{
db.Entry(eMP).State = EntityState.Modified;
db.SaveChanges();
}
return Redirect(Request.UrlReferrer.PathAndQuery);
}
return View(eMP);
}
I couldn't put them all in one form, because i used an ajax beginForm between them for another crud method. Since I've read that nested forms are not recommended.
Is there a way to save one form without it clearing the values of the other forms?
Is there a way to save one form without it clearing the values of the other forms?
You could simply use ajax.beginform for each of those forms;
How to use Simple Ajax Beginform in Asp.net MVC 4?
Or you could make your own ajax implementation
https://www.c-sharpcorner.com/blogs/using-ajax-in-asp-net-mvc
Or you could just go ahead and bind everything on your model;
// don't need to specify which properties to bind, all of the available properties in your view will be bound to the model on POST
public ActionResult Edit(EMP eMP)
{
if(eMP.FirstName!=null ...){
// ... do some checking depending on what values are submitted
}
// save profile here
// when you return the view
return View(eMP);
}
but for this method you need to only have 1 form for Personal,Job, and Others.
#{ Html.RenderAction("Index", "EMP_REFERENCE", new { id = Model.eMP.lineno });}
#{ Html.RenderAction("Index", "EMP_BENEFITS", new { id = Model.eMP.lineno });}
#using (Html.BeginForm("Edit", "EMPs", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<!--put all your employee input fields here-->
<div class="form-group">
<div class="pull-right">
<input type="submit" value="Update" name="submit" class="btn btn-success" />
</div>
</div>
<!--put all your job input fields here-->
<div class="form-group">
<div class="pull-right">
<input type="submit" value="Update" name="submit" class="btn btn-success" />
</div>
</div>
<!--put all your others input fields here-->
<div class="form-group">
<div class="pull-right">
<input type="submit" value="Update" name="submit" class="btn btn-success" />
</div>
</div>
}

Concatenation of strings in Razor MVC 5 for "class" attribute

I'm building an ASP.NET MVC 5 application for a local inventory. This app shows items on a page with buttons to deliver the items.
I want the "Scarica" buttons to be greyed-out when items are not available, so I thought I could just delete the btn-info attribute and that should've done the trick, so I changed the relevant lines of code in the view from this
<div class="col-sm-2">
#using (Html.BeginForm("ScaricaItem", "Scarico"))
{
string Disabilitato = "";
if (i.Qty == 0)
{
Disabilitato += "disabled";
}
<div class="pull-right">
#Html.HiddenFor(x => #i.Item.Modello)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class="btn btn-info" value="Scarica" #Disabilitato />
</div>
}
</div>
to this:
<div class="col-sm-2">
#using (Html.BeginForm("ScaricaItem", "Scarico"))
{
string Disabilitato = "";
string Classe = "";
if (i.Qty == 0)
{
Disabilitato += "disabled";
Classe = "btn";
}
else
{
Classe = "btn btn-info";
}
<div class="pull-right">
#Html.HiddenFor(x => #i.Item.Modello)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class=#Classe value="Scarica" #Disabilitato />
</div>
}
</div>
but now I have all the buttons greyed-out because the btn-info attribute value is treated as if it was an attribute itself
<input type="submit" class="btn" btn-info="" value="Scarica">
I also tried
<input type="submit" class=#(Classe) value="Scarica" #Disabilitato />
and
<input type="submit" class=#(String.Format("{0}", Classe)) value="Scarica" #Disabilitato />
but nothing changes.
Thanks,
Davide.

mvc radiobuttonfor in editortemplate keyboard navigation does not set model

Context:
Model generating some RadioButtonFor groupings as input to answer questions.
What is happening:
Case 1. When mouse click on a radio option the display looks correct. When the [HttpPost] ActionResult(model) for the page is triggered the Model.Answer comes through with the correct value. Which is good and desired.
Case 2. When navigating with the keyboard to the radio group and selecting one with arrow keys the display looks correct. But when the [HttpPost] ActionResult (model) is triggered the Model.Answer value is unchanged from what it was loaded as on page load.
Here is the code that makes the radio group:
#model NexusPWI.ViewModels.Wizard.QuestionModel
#* Dynamically generate and model bind controls for QuestionModel *#
#{
<div class="row d-contents">
<div class="form-group">
<div class="question">
<div class="col-lg-2 d-contents">
<div class="btn-group btn-toggle group-sm d-contents" data-toggle="buttons">
<label class="btn QuestionRadio btn-default #(Model.Answer == YesNoNAOptions.Yes ? "active" : "")" for="#Model.Answer">
#YesNoNAOptions.Yes.ToString().ToUpper()
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.Yes, new { #onfocus = "radiofocus(event)", #onblur = "radioblur(event)" })
</label>
<label class="btn QuestionRadio btn-default #(Model.Answer == YesNoNAOptions.No ? "active" : "")" for="#Model.Answer">
#YesNoNAOptions.No.ToString().ToUpper()
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.No, new { #onfocus = "radiofocus(event)", #onblur = "radioblur(event)" })
</label>
#if (!Model.NaInvalid)
{
<label class="btn QuestionRadio btn-default #(Model.Answer == YesNoNAOptions.NA ? "active" : "")" for="#Model.Answer">
N/A
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.NA, new { #onfocus = "radiofocus(event)", #onblur = "radioblur(event)" })
</label>
}
</div>
</div>
<div class="col-lg-9 d-contents">
<div class="row">
<p>
<strong>#Model.Question</strong>
</p>
</div>
#Html.HiddenFor(x => Model.Question_IdentityMarker, new { #class = "Question_IdentityMarker" })
</div>
</div>
</div>
</div>
}
Here is an example of the html that is generated:
<div class="form-group">
<div class="question">
<div class="col-lg-2 d-contents">
<div class="btn-group btn-toggle group-sm d-contents" data-toggle="buttons">
<label class="btn QuestionRadio btn-default " for="No">
YES
<input data-val="true" data-val-required="The Answer field is required." id="Questions_0__Answer" name="Questions[0].Answer" onblur="radioblur(event)" onfocus="radiofocus(event)" value="Yes" type="radio">
</label>
<label class="btn QuestionRadio btn-default active" for="No">
NO
<input checked="checked" id="Questions_0__Answer" name="Questions[0].Answer" onblur="radioblur(event)" onfocus="radiofocus(event)" value="No" type="radio">
</label>
<label class="btn QuestionRadio btn-default " for="No">
N/A
<input id="Questions_0__Answer" name="Questions[0].Answer" onblur="radioblur(event)" onfocus="radiofocus(event)" value="NA" type="radio">
</label>
</div>
</div>
<div class="col-lg-9 d-contents">
<div class="row">
<p>
<strong>Do you charge sales tax?</strong>
</p>
</div>
<input class="Question_IdentityMarker" id="Questions_0__Question_IdentityMarker" name="Questions[0].Question_IdentityMarker" value="CUSTOMERSALESTAX" type="hidden">
</div>
</div>
</div>
EDIT Adding onFocus & onBlur at request:
onFocus & onBlur are css highlighting for the keyboard navigation to make it more clear for the user where they are in the page.
function radiofocus(event) {
// Get event object if using Internet Explorer
var e = event || window.event;
// Check the object for W3C DOM event object, if not use IE event object to update the class of the parent element
if (e.target) {
var addClass = focusClass(e.target.parentNode.parentNode.parentNode.parentNode.parentNode.className, "r");
e.target.parentNode.parentNode.parentNode.parentNode.parentNode.className = addClass;
} else {
var addClass = focusClass(e.srcElement.parentNode.parentNode.parentNode.parentNode.parentNode.className, "r");
e.srcElement.parentNode.parentNode.parentNode.parentNode.parentNode.className = addClass;
}
};
function radioblur(event) {
// Get event object if using Internet Explorer
var e = event || window.event;
var removeClass = focusClass("", "r").trim();
// Check the object for W3C DOM event object, if not use IE event object to update the class of the parent element
if (e.target) {
e.target.parentNode.parentNode.parentNode.parentNode.parentNode.className = e.target.parentNode.parentNode.parentNode.parentNode.parentNode.className.replace(removeClass, "");
} else {
e.srcElement.parentNode.parentNode.parentNode.parentNode.parentNode.className = e.srcElement.parentNode.parentNode.parentNode.parentNode.parentNode.className.replace(removeClass, "");
}
};
Why do the keyboard navigated changes not get back to the controller?
Anything to add to make this clearer?
Side note: For some reason before a value is chosen in the radio group the keyboard tab navigation is stopping for each radio answer for a question.

How do I update a specific database entry with a view model as controller method attribute

I have an input table in my website which is connected to a View Model. In the controller method, I pass this View Model to the controller and vice versa, meaning the controller populates the view model with data from the data base and the view returns a view model populated with form data the user might have entered.
The problem is that once the view received the view model object, the "ID" attribute from the database is no longer there. When the Post method is called, there is no way to know which database entry must be updated.
My question is: How do I update a specific database entry when I pass a view model to the controller method?
Example Controller Method:
[HttpPost]
public ActionResult method(ViewModel vm)
{
DataContext.Context.Where(x => x.ID == vm.Object.ID) // this is where vm.Object.ID always returns "0", not the actual ID from the database entry
Context.SaveChanges();
return View(vm);
}
If you need more information, please let me know. Also, using jquery is not a viable option for this project. Thanks a lot for your help!
Edit:
View:
#model MyANTon.ViewModels.Q4_Answer_VM
#{
ViewBag.Title = "myANTon Anforderungserfassung";
ViewBag.HideNavBar = false;
}
#using (Html.BeginForm())
{
<div class="container">
<div class="jumbotron">
<hr />
<table class="grid" id="datatable">
<tr>
<th>Nr.</th>
<th>Last</th>
<th>Quelle</th>
<th>Ziel</th>
<th>Frequenz [/h]</th>
<th>Abstand [m]</th>
<th></th>
<th></th>
#{int i = 1; }
#for (var a = 0; a < Model.Matrix.Count; a++)
{
<tr>
<td>#(i++)</td>
<td>#Html.TextBoxFor(x => Model.Matrix[a].Load)</td>
<td>#Html.TextAreaFor(x => Model.Matrix[a].Source)</td>
<td>#Html.TextAreaFor(x => Model.Matrix[a].Goal)</td>
<td>#Html.TextAreaFor(x => Model.Matrix[a].Frequency)</td>
<td>#Html.TextAreaFor(x => Model.Matrix[a].Distance)</td>
<td><input type="submit" name="+" class="btn btn-default" value="+" /></td>
<td><input type="submit" class="btn btn-default" value="-" /></td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" name="Speichern" value="Speichern" />
<input type="submit" class="btn btn-default" value="Speichern und weiter" />
<input type="button" class="btn btn-default" value="Weiter zu Schritt 5" onclick="#("window.location.href='" + #Url.Action("Q_Fifthpage", "Home") + "'");" />
</div>
</div>
</div>
</div>
}
GET Method:
[HttpGet]
public ActionResult Q_FourthPage()
{
// get current Questionnaire ID
int CurrentQstID = Convert.ToInt32(Session["qstid"]);
// create vm object. Capacity is a column in the table.
var Q4ViewModel = new ViewModels.Q4_Answer_VM();
// look for existing input data columns for this questionnaire in db
if (db.Capacities.Any(x => x.Questionnaire_ID == CurrentQstID))
{
// answers exist
Q4ViewModel.Matrix.AddRange(db.Capacities.Where(x => x.Questionnaire_ID == CurrentQstID));
}
else
{
// new capacity matrix
Q4ViewModel.TMatrix = db.QuestionTexts.Where(x => x.ID == 21).FirstOrDefault();
Q4ViewModel.Matrix = new List<Models.Capacity>();
}
var tmpcapacity = new Models.Capacity();
tmpcapacity.Questionnaire_ID = Convert.ToInt32(Session["qstid"]);
Q4ViewModel.Matrix.Add(tmpcapacity);
db.Capacities.Add(tmpcapacity);
db.SaveChanges();
return View(Q4ViewModel);
}
POST Method:
[HttpPost]
public ActionResult Q_FourthPage(ViewModels.Q4_Answer_VM vm)
{
int currentQst = Convert.ToInt32(Session["qstid"]);
if (Request.Form["+"] != null)
{
var tmpcapacity = new Models.Capacity();
tmpcapacity.Questionnaire_ID = currentQst;
vm.Matrix.Add(tmpcapacity);
db.Capacities.Add(tmpcapacity);
db.SaveChanges();
return View(vm);
}
if (Request.Form["Speichern"] != null)
{
// save data
if (!ModelState.IsValid) return View("~/Views/Shared/Error.cshtml");
var tmpcapacity = new Models.Capacity();
for (var a = 0; a < vm.Matrix.Count; a++)
{
var current = vm.Matrix[a];
current.ID = vm.Matrix[a].ID;
if (db.Capacities.Any(x => x.ID == current.ID))
// if clause never triggers true
// vm does not contain capacity ID
{
// column exists and is changed (or not)
tmpcapacity.Distance = vm.Matrix[a].Distance;
tmpcapacity.Frequency = vm.Matrix[a].Frequency;
tmpcapacity.Source = vm.Matrix[a].Source;
tmpcapacity.Goal = vm.Matrix[a].Goal;
tmpcapacity.Load = vm.Matrix[a].Load;
Models.Capacity c = db.Capacities.Where(x => x.ID == current.ID).FirstOrDefault();
c = tmpcapacity;
db.SaveChanges();
}
else
{
// new column
tmpcapacity.Distance = vm.Matrix[a].Distance;
tmpcapacity.Frequency = vm.Matrix[a].Frequency;
tmpcapacity.Source = vm.Matrix[a].Source;
tmpcapacity.Goal = vm.Matrix[a].Goal;
tmpcapacity.Load = vm.Matrix[a].Load;
tmpcapacity.Questionnaire_ID = currentQst;
db.Capacities.Add(tmpcapacity);
db.SaveChanges();
}
}
db.SaveChanges();
}
return View(vm);
}
If you need to bind the ID to the Model then you need to use hidden filed under the form when you are using Razor.
#Html.HiddenFor(model => model.Id)
For more details
#using (Html.BeginForm("method", "ControllerName", FormMethod.Post))
{
#Html.HiddenFor(Model=>Model.ID)
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Button" />
</div>
</div>
}
Now you can access ID at your controller action method.
If you want to "save" the object ID and get it back when the post occurs, you need to store it into a hidden field using the .HiddenFor() HTML helper - something like this:
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.Object.Id);
<div class="container">
<div class="jumbotron">
Then, upon your POST, you should get back the Object.ID in your post body and you should be able to tell which object this is for.

MVC: Display an input if two rows match in database using LINQ

I am trying to hide that input if in database current logged user have already a Job posted on website, if UserID doesn't have anything added in database I want that input to be displayed/
At this point in View is displayed only that '< span >' no matter what.
#{
var db = new JobSite3.Models.ApplicationDbContext();
var controller = new JobSite3.Controllers.BaseController();
}
#if (db.Jobs.Where(x => x.UserID == controller.LoggedUserId).Select(x => x.ID) != null)
{
<span>No input</span>
}
else
{
<div class="form-group">
<div class="col-md-offset-1 col-md-10">
<input type="submit" value="Create" class="btn btn-default"/>
</div>
</div>
}
As per Stephen Muecke suggestions I made my code work and here is the solution in case someone needs too:
Controller:
// GET: Jobs/Create
public ActionResult Create()
{
var query = db.Jobs.Where(x => x.UserID == LoggedUserId).Select(x => x.ID.ToString()).Any();
ViewBag.HasJobs = query;
return View();
}
View:
#if (ViewBag.HasJobs != true)
{
<div class="form-group">
<div class="col-md-offset-1 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
}
else
{
<div class="form-group">
<div class="col-md-offset-1 col-md-10">
<input type="submit" value="Create" class="btn btn-default" disabled="disabled" />
</div>
</div>
}
There isn't anymore a < span > but the last input have a disabled parameter, which was the first intention.

Resources