Below is code I found online sometime back. It refreshes section of form based on link click. I want to change this to have links in a DropDownList. Then based on its selection and a button click I want to perform the same action as link click.
I am having hard time figuring out how to read dropdownlist selected value. I tried searching here on SO, but not finding any simple example. Looks like most of them are based on javascript. I am hoping that there must be some simple solution without using javascript.
Controller
namespace WebApplication2.Controllers
{
public class HomeController : Controller {
DBEntities db = new DBEntities();
// GET: /AllUsers/
public ActionResult Index()
{
return View();
}
// Return all students
public PartialViewResult All()
{
List<AspNetUser> model = db.AspNetUsers.ToList();
return PartialView("_Users", model);
}
// Return Top3 students
public PartialViewResult Top3()
{
List<AspNetUser> model = db.AspNetUsers.OrderByDescending(x => x.UserName).Take(3).ToList();
return PartialView("_Users", model);
}
}
}
Partial View
#model IEnumerable<WebApplication2.Models.AspNetUser>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.PhoneNumber)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.PhoneNumber)
</td>
</tr>
}
</table>
View
#{
ViewBag.Title = "Home Page";
}
<div style="font-family:Arial">
<script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
<h2>Students</h2>
#Ajax.ActionLink("All", "All",
new AjaxOptions
{
HttpMethod = "GET", UpdateTargetId = "divStudents", InsertionMode = InsertionMode.Replace
})
<span style="color:Blue">|</span>
#Ajax.ActionLink("Top 3", "Top3",
new AjaxOptions
{
HttpMethod = "GET", UpdateTargetId = "divStudents", InsertionMode = InsertionMode.Replace
} )
<br /><br />
<div id="divStudents" style="height: 600px; overflow: auto;"></div>
</div>
You need to replace you Ajax.ActionLink()'s with a single Ajax.BeginForm() containing the dropdownlist
#model StudentSearchVM
<h2>Students</h2>
#using (Ajax.BeginForm("Filter", new AjaxOptions { HttpMethod = "GET", UpdateTargetId = "divStudents", InsertionMode = InsertionMode.Replace }))
{
#Html.DropDownListFor(m => m.Filter, Model.FilterList)
<input type="submit" value="Search" />
}
<div id="divStudents" style="height: 600px; overflow: auto;"></div>
Note the above assumes you have the following view model
public class StudentSearchVM
{
public string Filter { get; set; }
public SelectList FilterList { get; set; }
}
And that in the GET method that generate this view
StudentSearchVM model = new StudentSearchVM
{
FilterList = new SelectList(new List<string>(){ "All", "Top 3" })
}
return View(model);
Then you would have a single controller method
public ActionResult Filter(string filter)
{
if (filter == "All")
{
List<AspNetUser> model = db.AspNetUsers.ToList();
return PartialView("_Users", model);
}
else
{
....
}
}
Related
I build this code for select all checboxes and pass to controller, I using button when click it check all checkboxes and pick up all variables like (idtip, idemployee) trought array send to controller to update database table.
<tr>
<th>name</th>
<th>tips</th>
<th>
<button id="btnClick" class="btnClick">Select all</button>
</th>
</tr>
Here is my input and script.
#foreach (var item in (IEnumerable<cit.Models.getCheIdTip_Result>)Model)
{
<tr>
<td>#item.idtip</td>
<td>#item.tipname</td>
<td>
<div class="pure-checkbox" idtip="#item.idtip">
<input type="checkbox" idtip="#item.idtip" class="checktip"
checked="#(item.idemployee == ViewBag.idemployee ? true : false)"
name="#item.id.ToString()" id="#item.id.ToString()" />
<label for="#item.id.ToString()"></label>
</div>
</td>
</tr>
}
</table>
<input type="hidden" value="#ViewData["idemployee"]" name="idemployee" id="idemployee" class="idemployee" />
<script>
$('.pure-checkbox').click(function () {
$(this).parents('td').toggleClass('chked')
})
var wantedids = [idemployee,idtip]
$("#btnClick").click(function () {
for (var i = 0; i < $('.pure-checkbox').length; i++) {
if ($('.pure-checkbox').eq(i).parents('td').hasClass('chked')) {
wantedids.push(
$('.pure-checkbox').eq(i).attr('idtip')
)
}
}
$.post("UrlSettingsDocument.Tips", { ids: wantedids },
)
})
I using button when click it check all checkboxes and pick up all
variables like (idtip, idemployee) trought array send to controller to
update database table.
You could refer the following sample code:
Create a ViewModel to display records:
public class TestViewModel
{
public int id { get; set; }
public int idtip { get; set; }
public string idemployee { get; set; }
public bool isChecked { get; set; }
}
In the Controller, add the following actions:
//Set the initial data and return to view.
public IActionResult Default()
{
List<TestViewModel> items = new List<TestViewModel>()
{
new TestViewModel(){ id=101, idtip=1001, idemployee="AAA" },
new TestViewModel(){id=102,idtip=1002, idemployee="BBB" },
new TestViewModel(){id=103, idtip=1003, idemployee="CCC" },
new TestViewModel(){ id=104,idtip=1004, idemployee="DDD" },
new TestViewModel(){id=105, idtip=1005, idemployee="EEE" }
};
ViewBag.idemployee = "CCC"; //set the default checked item.
return View(items);
}
public IActionResult AddItems(IEnumerable<TestViewModel> items)
{
//insert the items into database.
return Ok("OK");
}
Then, in the View page (Default.cshtml), using the following code to display the content:
Here we can use a select all checkbox, after checking it, will select all items.
#model IEnumerable<WebApplication.Models.TestViewModel>
#{
ViewData["Title"] = "Default";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<table class="table">
<thead>
<tr>
<th>
<input type="checkbox" id="btnSelectAll" class="btnClick" /> <label for="btnSelectAll">Select All</label>
</th>
<th>
#Html.DisplayNameFor(model => model.idtip)
</th>
<th>
#Html.DisplayNameFor(model => model.idemployee)
</th>
<th>
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
<div class="pure-checkbox" idtip="#item.idtip">
<input type="checkbox" idtip="#item.idtip" data-idemployee="#item.idemployee" class="checktip"
checked="#(item.idemployee == ViewBag.idemployee ? true : false)"
name="#item.id.ToString()" id="#item.id.ToString()" />
<label for="#item.id.ToString()"></label>
</div>
</td>
<td>
#Html.DisplayFor(modelItem => item.idtip)
</td>
<td>
#Html.DisplayFor(modelItem => item.idemployee)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</tbody>
</table>
<button id="btnSubmit" class="btnClick">Submit</button>
At the end of the Default.cshtml page, using the following script to achieve the select all function and submit the records to the controller.
#section Scripts{
<script>
$(function () {
//If checked the select all checkbox, select all items. else unchecked.
$("#btnSelectAll").click(function () {
if ($(this).is(":checked")) {
$(".checktip").each(function (index, item) {
$(item).prop("checked", true);
});
}
else {
$(".checktip").each(function (index, item) {
$(item).prop("checked", false);
});
}
});
$("#btnSubmit").click(function () {
var testViewModels = [];
//using the class selector to loop through the checkbox list and get all items, if you want to get the checked items, add an if...else statement in the each function.
$(".checktip").each(function (index, item) {
var TestViewModel = {};
TestViewModel.idtip = $(this).attr("idtip");
TestViewModel.idemployee = $(this).attr("data-idemployee");
TestViewModel.isChecked = $(this).is(":checked");
testViewModels.push(TestViewModel);
});
$.ajax({
type: "Post",
url: "/Home/AddItems", //remember change the controller to your owns.
data: { items: testViewModels }, //the name ("items") should be the same with the parameter's name in the controller.
success: function (data) {
console.log(data)
},
error: function (response) {
console.log(response.responseText);
}
});
});
});
</script>
}
The result as below:
When I am saving my data for the first time (when clicked on save button of my view) then I am getting value of submitButton variable in my controller action. But when I am editing my view and then click on save then I am getting null value in submitButton variable in my controller action.
My View Model
public class TermiViewModel : ViewModelBase
{
public long Id { get; set; }
public string Name { get; set; }
}
My View
#model TermiViewModel
#using (Html.BeginForm("MyActionMethod", "MyController", FormMethod.Post))
{
#Html.HiddenFor(model => model.Id)
<div>
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
</div>
<button name="submitButton" value="Save" type="submit"
onclick="return JavaScriptFunction();">Save</button>
<button name="submitButton" value="Cancel" type="submit"
onclick="return JavaScriptFunction();">Cancel</button>
}
Below is the Javascript I am using in my view.
<script language="javascript" type="text/javascript">
function JavaScriptFunction() {
return true;
}
</script>
Below is my Controller class.
public class MyController : CoreMvcController
{
private readonly ITermiRepositoryService _termiRepository;
public MyController(ITermiRepositoryService termiRepository)
{
_termiRepository = termiRepository;
}
}
Below is my action Method where I am getting values from my view.
[HttpPost]
public ActionResult MyActionMethod(TermiViewModel termiViewModel, string submitButton)
{
try
{
voucherViewModel =_termiRepository.Save(termiViewModel);
switch (submitButton)
{
case "Cancel":
return RedirectToAction("Edit",termiViewModel.Id);
default:
return RedirectToAction("Index");
}
}
catch (Exception exception)
{
}
return RedirectToAction("Index");
}
In my above Controller method I get the null value for my submitButton variable while editing my view. I don't understand why I am getting null value because while creating for the first time, I am getting values of submitButton from the submit button.
Thanks for any help!
For the solution, I need to change following classes:
My View Model:
// A new property "SaveButtonValue" added to my view model.
public class TermiViewModel : ViewModelBase
{
public long Id { get; set; }
public string Name { get; set; }
public string SaveButtonValue { get; set; }
}
My View:
// Added a hidden field for "SaveButtonValue" and passing this keyword in
// Javascript function for onclick of submit button.
#model TermiViewModel
#using (Html.BeginForm("MyActionMethod", "MyController", FormMethod.Post))
{
#Html.HiddenFor(model => model.Id)
#Html.HiddenFor(model => model.SaveButtonValue)
<div>
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
</div>
<button name="submitButton" value="Save" type="submit"
onclick="return JavaScriptFunction(this);">Save</button>
<button name="submitButton" value="Cancel" type="submit"
onclick="return JavaScriptFunction(this);">Cancel</button>
}
Javascript:
// Populating my property "SaveButtonValue" through javascript
<script language="javascript" type="text/javascript">
function JavaScriptFunction(submitButton)
{
if (objButton) {
$('#SaveButtonValue').val(submitButton.value);
}
return true;
}
</script>
My action method:
[HttpPost]
public ActionResult MyActionMethod(TermiViewModel termiViewModel)
{
try
{
voucherViewModel =_termiRepository.Save(termiViewModel);
switch (termiViewModel.SaveButtonValue)
{
case "Cancel":
return RedirectToAction("Edit",termiViewModel.Id);
default:
return RedirectToAction("Index");
}
}
catch (Exception exception)
{
}
return RedirectToAction("Index");
}
I am using an ajax.beginform to create a partial view within another view.
I the user enters a correct sn everything works fine.
But if the user enters an invalid number, I want to redirect to the index view.
Now the index page is submitted as a partial view in itself.
How can I avoid that.
Here is a part of my view and 2 simplified actionresults.
#using (Ajax.BeginForm("MachineInfo", "QrCreate", new AjaxOptions() {
HttpMethod = "POST", UpdateTargetId = "form-content", InsertionMode =
InsertionMode.ReplaceWith }))
{
#Html.AntiForgeryToken()
<input type="text" id="sn" name="sn" class="inputsn"
placeholder="Enter your serial number here..." />
<input type="submit" value="Search" class="search btn btn-success btn-lg" />
}
</div>
</div>
<div id="form-content"></div>
my Controller
public ActionResult Index(bool? isValidMachine = null)
{
ViewBag.invalidSerialNumber = isValidMachine;
return View();
}
[HttpPost]
public ActionResult MachineInfo(string sn)
{
if(string.IsNullOrEmpty(sn))
RedirectToAction("Index", new { isValidMachine = false });
QrCreateViewModel qrCreateVM;
using (var machineService = new MachineApiService())
{
var machine = machineService.GetMachineFromSerialNumber(sn);
if (machine == null)
return RedirectToAction("Index", new { isValidMachine = false });
else
qrCreateVM = new QrCreateViewModel(machine, GetBasePath());
}
if (qrCreateVM.IsValid())
{
qrCreateVM.Viewurl = qrCreateVM.QrCreateUrlOrDefaultNull();
return PartialView(qrCreateVM);
}
else
return RedirectToAction("Index", new { isValidMachine = false });
}
Ajax calls do not redirect (the purpose of making them is to stay on the same page).
In your controller method, replace the instances of return RedirectToAction(...) to return a HttpStatusCodeResult indicating an error, which you can then handle in the OnFailure option to redirect to the Index() method.
For example
[HttpPost]
public ActionResult MachineInfo(string sn)
{
if (string.IsNullOrEmpty(sn))
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Bad Request");
}
....
Then in the Ajax.BeginForm()
#using (Ajax.BeginForm("MachineInfo", "QrCreate", new AjaxOptions() {
HttpMethod = "POST",
UpdateTargetId = "form-content",
InsertionMode = InsertionMode.ReplaceWith,
OnFailure = "redirect"
}))
{
....
and add the following script to redirect
function redirect(ajaxContext) {
location.href = '#Url.Action("Index")';
}
I am attempting to using knockout to create a client side model so client side validation can be done on the needed attributes, some of which are nested and or in nested lists of other models.
In following some guides and patterns, I have tried to map a test list from the main view model and send it back to the controller when the form submits, with validation that would prevent the form from being submitted if the value is null.
When the form is submitted, not only does it fail to validate with the current set up, the edited values (which are correctly populated in the view on load, so some type of binding is correctly working) return as null in the controller.
namespace KnockoutDemo.Models
{
public class XmlParameter
{
public HttpPostedFileBase XmlValue;
public string Name;
}
}
public class TestStepViewModel
{
public int TestStepId { get; set; }
public string TestStepName { get; set; }
public string Message { get; set; }
public List<XmlParameter> XmlParameters { get; set; }
}
View
#using System.Web.Mvc.Ajax
#using System.Activities.Expressions
#using System.Web.Script.Serialization
#model KnockoutDemo.Models.TestStepViewModel
#{ string data = new JavaScriptSerializer().Serialize(Model);}
#section scripts
{
<script src="~/Scripts/knockout-3.4.0.js"></script>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/teststepviewmodel.js"></script>
<script type="text/javascript">
var testStepViewModel = new TestStepViewModel(#Html.Raw(data));
ko.applyBindings(testStepViewModel);
</script>
}
<form>
<div>
<div class="form-group">
<label class="control-label" for="TestStepName">Test Step Name:</label>
<input class="form-control" name="TestStepName" id="TestStepName" data-bind="value: TestStepName"/>
</div>
<div class="form-group">
<label class="control-label" for="TestStepName">Test Step Id:</label>
<input class="form-control" name="TestStepId" id="TestStepId" data-bind="value: TestStepId" disabled="disabled"/>
</div>
<table class="table table-striped">
<tr>
<th>Product Code</th>
</tr>
<tbody data-bind="foreach: XmlParameters">
<tr>
<td class="form-group"><input name="Name" class="form-control input-sm" data-bind="attr: {'id': 'Name_' + $index()}, value: Name"/></td>
</tr>
</tbody>
</table>
</div>
<p><button class="btn btn-primary" data-bind="click: save" type="submit" >Save</button></p>
</form>
teststepviewmodel.js + validation
TestStepViewModel = function(data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.save = function () {
$.ajax({
url: "/Home/Save/",
type: "POST",
data: ko.toJSON(self),
contentType: "application/json"
});
}
}
var XmlParameter = function(data) {
var self = this;
ko.mapping.fromJS(data, mapping, self);
}
var mapping = {
'XmlParameters': {
key: function (xmlParameters) {
return ko.utils.unwrapObservable(xmlParameters.Name);
},
create: function (options) {
return new XmlParameter(options.data);
}
}
};
$("form").validate({
submithandler: function () {
testStepViewModel.save();
},
rules: {
TestStepName: {
required: true,
maxlength: 30
},
Value: {
required: true
},
XmlValue: {
required: true
}
},
messages: {
TestStepName: {
required: "A Test Step must have a non-null value, please enter a name"
},
Value: {
required: "The parameter can't be null/empty"
}
}
});
The JsonResult Save() controller correctly populates the Id and Test Step Name, however the XmlParameters are both null.
Controllers (Like I said, this is simply a test to return knockout model with client side validation, so I'm simply populating a view model on load and setting a breakpoint on the JsonResult to see the contents of the model)
public ActionResult Index(TestStepViewModel ts)
{
TestStepViewModel testStepViewModel = new TestStepViewModel
{
TestStepName = "Editing A Test Step",
TestStepId = 10,
Message = "Hello, this is a message"
};
testStepViewModel.XmlParameters = new List<XmlParameter>();
testStepViewModel.XmlParameters.Add(new XmlParameter
{
Name = "Xml P1"
});
testStepViewModel.XmlParameters.Add(new XmlParameter
{
Name = "Xml P2"
});
return View("Index", testStepViewModel);
}
public JsonResult Save(TestStepViewModel testStepViewModel)
{
return null;
}
To preface this question, I will admit that I know nothing about javascript and related topics. I am trying to have a table be created and filled out based on a button push. If I pass the data directly into the ViewModel, it displays correctly, so I know the table is working right. Here is the JQuery request:
<input type="button" id="RootsBtn" value="Go"/>
<script language="javascript" type="text/javascript">
$(function () {
$("#RootsBtn").click(function () {
$.ajax({
cache: false,
type: "GET",
url: "#(Url.RouteUrl("GetApplications"))",
data: {},
success: function (data) {
alert(data.length);
$('#AppTableID').show();
},
error: function (xhr, ajaxOptions, throwError) {
alert("Error");
$('#AppTableID').hide();
}
});
});
});
</script>
I'm basing this code loosely on code I'm using to populate a dropdown list. I know the data is being grabbed properly because the alert(data.length); line shows the proper number of objects in my list.
The dropdown code included a $.each line. I have tried using variants of this and nothing has worked for me.
How would I get the data saved into my ViewModel so that it can be displayed?
EDIT: Adding more details
This is the Table display in my view:
<div id="AppTableID">
<table id="dashboard">
<thead>
<th>
#Html.LabelFor(model => model.apps.FirstOrDefault().AppStringID)
</th>
<th>
#Html.LabelFor(model => model.apps.FirstOrDefault().ApplicationCategoryID)
</th>
<th>
#Html.LabelFor(model => model.apps.FirstOrDefault().Description)
</th>
</thead>
#foreach (var item in Model.apps ?? new List<Application> { null })
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.AppStringID)
</td>
<td>
#Html.DisplayFor(modelItem => item.ApplicationCategoryID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</table>
</div>
This is my viewmodel which is passed into the view:
public class HomeViewModel
{
public HomeViewModel()
{
apps = new List<Application>();
}
public IEnumerable<Application> apps { get; set; }
}
This is the Application class:
public class Application
{
public long ID { get; set; }
public string AppStringID { get; set; }
public int? ApplicationCategoryID { get; set; }
public string Description { get; set; }
}
This is GetApplications: (appService.ToList() correctly gets the list of data. This has been well tested.)
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetApplications()
{
var apps = appService.ToList();
if (apps == null)
{
return Json(null, JsonRequestBehavior.AllowGet);
}
return Json(apps, JsonRequestBehavior.AllowGet);
}
In the success function of your ajax call
$.ajax({
....
success: function (data) {
$.each(data, function(index, item) {
var row = $('<tr></tr>'); // create new table row
row.append($('<td></td>').text(item.AppStringID));
row.append($('<td></td>').text(item.ApplicationCategoryID));
row.append($('<td></td>').text(item.Description));
$('#dashboard').append(row); // add to table
});
$('#AppTableID').show();
},
....
});
Notes: You should probably include a tbody element as a child of your table and add the rows to that. Your foreach loop only needs to be #foreach (var item in Model.apps) {.. (the collection has been initialized in the constructor). You also don't need the if (apps == null) {..} condition in the GetApplications method