My viewmodel contains a list of objects that I'm iterating through, and each one has a certain class associated with them. My goal is on click of that item to open it up to view, but I'm unclear on how to get the id of that row in my jquery click function.
foreach (var item in Model.PatientViewModel)
{
<div class="patientBox patientBox-unselected">
<h7>
<div class="pvb-mrn">MRN: #Html.DisplayFor(modelItem => item.MRN)</div>
<div class="pvb-dob">DOB: #Html.DisplayFor(modelItem => item.DOB)</div>
<br />
<div class="pvb-link">
#Html.ActionLink("Update Patient >", "Edit", new { id = item.PatientID })
</div>
</h7>
</div>
}
and then my script with a test alert just to ensure i was hitting the function, which works fine, but how can I get the ID of the clicked item here?
$('.patientBox').click(function () {
window.location.href("/View/" + #item.ID);
})
view model:
public class PatientScreenViewModel
{
public List<PatientDTO> PatientViewModel { get; set; }
public PatientSearchDTO SearchViewModel { get; set; }
}
Put the item.ID in html Attribute and get it with jQuery like so:
foreach (var item in Model.PatientViewModel){
<div class="patientBox patientBox-unselected" data-item-id="<%= item.ID %>">
...
...
</div>
}
jQuery:
$('.patientBox').click(function () {
window.location.href("/View/" + this.getAttribute('data-item-id');
})
Related
I have this ViewModel which incorporates 3 other viewmodels and a list:
public class GroupPageViewModel{
public string GroupName { get; set; }
public GroupSelectViewModel _groupSelectVM {get; set;}
public List<User> _users { get; set; }
public ViewModelStudent _studentVM { get; set; }
public ViewModelGroupMembers _groupMembersVM { get; set; }
}
In the view I can access each of these sub-ViewModels by Model._groupSelectVM, each of the sub-ViewModels are associated with a partial view. The problem arises when I need to refresh just one or two partial views, I'm not sure how to access the inner ViewModels returned in an Ajax success, and as I'm relatively new to MVC and asp.net in general. And I literally know next to nothing about JavaScript, jquery or Ajax.
How would I go about getting a specific ViewModel from the main ViewModel in an Ajax success?
This is just one example for the clarification requested all the others are pretty much the same (although some of them might need to update mutliple partial views -
From the controller:
[HttpPost]
public ActionResult Index(string groupChoice = "0", string newGroup = "")
{
string groupName = "";
if (groupChoice == "0" && newGroup != "")
{
if (ModelState.IsValid)
{
Group group = new Group
{
GroupName = newGroup,
Active = true
};
db.Groups.Add(group);
db.SaveChanges();
PopulateLists();
}
}
else if (groupList == null)
{
groupList = (List<SelectListItem>)Session["groupList"];
Session["groupName"] = groupName = groupList.Where(m => m.Value == groupChoice).FirstOrDefault().Text;
MembersInSpecificGroup(groupName, groupMembers, groupMembersList);
groupPageVM._groupMembersVM = groupMembers;
}
return View("GroupSelection", groupPageVM);
}
The script:
$(document).ready(function () {
$('#selectedGroup').change(function () {
var data = {
groupChoice: $('#selectedGroup').val()
};
var groupChoice = $('#selectedGroup').val();
$.ajax({
url: '/Group/Index/',
type: 'POST',
data: { groupChoice: groupChoice },
success: function (data) {
setTimeout(function () {
delayGroupSuccess(data);
}, delay);
}
});
})
});
function delayGroupSuccess(data) {
$("#groupSelect").html(data);
}
The main page:
#model EMBAProgram.ViewModels.GroupPageViewModel
#{ Layout = "~/Views/Shared/_Layout.cshtml"; }
<h2>Group Selection</h2>
<div class="row" id="groupSelect">
#{ Html.RenderPartial("_GroupSelect", Model._groupSelectVM);}
</div>
<hr size="5" />
<div style="display: flex;">
<div>
#{Html.RenderPartial("_Students", Model._studentVM);}
</div>
<div>
#{ Html.RenderPartial("_GroupMembers", Model._groupMembersVM);}
</div>
<div>
#{ Html.RenderPartial("_Users", Model._users);}
</div>
<br style="clear: left;" />
</div>
The partial view:
#model EMBAProgram.ViewModels.ViewModelGroupMembers
<div class="table-responsive" id="groupResults">
<table class="table table-condensed table-responsive">
<thead>
<tr>
<th>#Html.DisplayName("M-Number")</th>
<th>#Html.DisplayName("Name")</th>
<th>#Html.DisplayName("Student")</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model._groupVM) {
<tr>
<td>#Html.DisplayFor(m => item.MNumber)</td>
<td>#Html.DisplayFor(m => item.Name)</td>
<td>#Html.DisplayFor(m => item.Student)</td>
</tr>
}
</tbody>
</table>
</div>
Basically I need to be able pull the ViewModel for the partial view from the main ViewModel (which I believe is what is being returned in the Ajax,) and refresh the partial view.
I removed the original answer, it's available in the edit log if folks want to see it I think. But it was taking up too much space and was incorrect.
You can return multiple partial views, I thought it was a built in way to get them to a string (I was in a rush in my comment), but I've got a working example.
In the controller I have the following:
public ActionResult Index()
{
var model = new TestViewModel
{
Students = GetStudents(),
Categories = GetCategories(),
Groups = GetGroups()
};
return View("Index", model);
}
// Returns multiple partial views as strings.
public ActionResult StudentsAndGroups()
{
return Json(new
{
Students = RenderRazorViewToString("_Students", GetStudents()),
Groups = RenderRazorViewToString("_Groups", GetGroups())
}, JsonRequestBehavior.AllowGet);
}
// Creates a string from a Partial View render.
private string RenderRazorViewToString(string viewName, object model)
{
ControllerContext.Controller.ViewData.Model = model;
using (var stringWriter = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
var viewContext = new ViewContext(ControllerContext, viewResult.View, ControllerContext.Controller.ViewData, ControllerContext.Controller.TempData, stringWriter);
viewResult.View.Render(viewContext, stringWriter);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return stringWriter.GetStringBuilder().ToString();
}
}
I have my main index view that looks like the following:
<button class="refresh">Refresh</button>
<div class="row">
<div class="col-md-4 students">
#{
Html.RenderPartial("_Students", Model.Students);
}
</div>
<div class="col-md-4">
#{
Html.RenderPartial("_Category", Model.Categories);
}
</div>
<div class="col-md-4 groups">
#{
Html.RenderPartial("_Groups", Model.Groups);
}
</div>
</div>
#section scripts
{
<script type="text/javascript">
$(".refresh").click(function () {
$.get("/Home/StudentsAndGroups", function (d) {
$(".students").html(d.Students);
$(".groups").html(d.Groups);
})
});
</script>
}
The controller action StudentsAndGroups turns two partial views into strings. From there, the javascript calls that view and accesses the elements and returns them.
Helper method for rendering a view as a string was found here: https://stackoverflow.com/a/34968687/6509508
This is my first ASP.NET MVC application, and I'm really struggling with some stuffs, right now I have big issue and I'm stucked here for over 5 hours allready, I'm trying to filter my dropdown with selection from another dropdown, before I post my code I want to say that I've followed this post:
How to filter the options of a drop down list using another drop down list
So let's start:
Regardless of the others fields, I have a lets say two dropdowns also, one represent MAIN CATEGORY, another represent SUB CATEGORY, and on MAIN CATEGORY selection, SUB CATEGORY should be loaded in dropdown and user should be able to choose it.
I want to create view where user should be able to fill some date and post it back to server, but before he post it back he need to choose date properly MAINCATEG -> SUBCATEG so this is how I did it so far:
My action result 'Create' method:
public ActionResult Create()
{
// I did not wrote other stuffs because they are not important in my question and code will be clearer.
//First I'm filling MAIN CATEGORY dropdown with data from my database
List<Groups> articleGroups = GroupController.GetActiveMainGroups();
// Attach list on ViewBag, because this view Bag will be used to populate main dropdown
ViewBag.articleGroups = articleGroups;
//Here is second list which should populate second dropdown, right now I get all subgroups from database, because it didn't let me
//run my application if list was empty (probably I don't need this in future because I will filter second dropdown by selecting something from dropdown above)
List<SubGroups> subGroups = GroupController.GetAllSubGroups();
// Attach list on ViewBag, it will be used for generating dropdown list.
ViewBag.subGroups = subGroups;
return View(model);
}
Here is also one method which I thought I can call throught javascript by triggering event 'change' on first (main) dropdown:
public ActionResult GetSubgroupByMainGroup(Guid id)
{
List<SubGroups> subGroups = GroupController.GetAllSubGroupsByMainGroup(id);
return Json(subGroups, JsonRequestBehavior.AllowGet);
}
Here is my VIEW:
#model MyProject.Web.Models.ArticleNewViewModel
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
#using MyProject.Model
#{
ViewBag.Title = "Add new Article";
}
<h3>Adding new article to database</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.MainGroupID, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.MainGroupID, new SelectList(ViewBag.articleGroups , "MainGroupID", "Group.Name"))
#Html.ValidationMessageFor(model => model.MainGroupID)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SubGroupID, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SubGroupID, new SelectList(ViewBag.subGroups , "SubGroupID", "SubGroup.Name"))
#Html.ValidationMessageFor(model => model.SubGroupID)
</div>
</div>
//I don't understand this code really, because I have so little experience with javascript&jquery
<script type="text/javascript">
$(function () {
$("#MainGroupID").change(function () {
var val = $(this).val();
var subItems="";
$.getJSON("#Url.Action("GetSubgroupByMainGroup", "Article")", {id:val} ,function (data) {
$.each(data,function(index,item){
subItems+="<option value='"+item.Value+"'>"+item.Text+"</option>"
});
$("#SubGroupID").html(subItems)
});
});
});
</script>
}
<div>
#Html.ActionLink("Go back", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
It is interesting that when I set breakpoint in my method public ActionResult GetSubgroupByMainGroup(Guid id) it's not being hitted, that means this code is not executed, and here is my
ArticleNewViewModel
:
public class ArticleNewViewModel
{
[Required]
[Display(Name = "Article code")]
public string Code { get; set; }
[Required]
[Display(Name = "Article Title")]
public string Title { get; set; }
//Here is ID's which should represent value from MAIN and value from SUBGROUP
[Required]
[Display(Name = "Main group")]
public Guid MainGroupID { get; set; }
[Required]
[Display(Name = "Sub Group")]
public Guid SubGroupID { get; set; }
}
I probably did few mistakes here but I really don't know where and what, because I'm not familiar with javascript & jquery, and I don't know is there another way to do it :/
Whatever I would like to fix this so if someone of you guys might help me I would appreciate so much!
Thanks guys
Cheers
Currently have a custom EditorTemplate which dynamically populates based on the incomming Model () in the Razor page.
The aim is to be able to hide the individual div 'Sub_Text' in the editor template based on the radio value.
Model: Prime.cs
public class Prime{
public List<QuestionModel> Questions { get; set; }
}
Model: QuestionModel.cs
public class QuestionModel{
public int Id { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
public string SubText { get; set; }
}
Main View: _Reporting.cshtml
#model ViewModels.Prime
#for (int i = 0; i < Model.Questions.Count(); i++) //Dynamically generate and model bind database PolicyHolderKeyQuestions
{
#Html.EditorFor(x => x.Questions[i], "QuestionModel")
}
EditorTemplate: QuestionModel.cshtml
#model ViewModels.QuestionModel
#{
<div class="col-lg-2">
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.Yes)
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.No)
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.NA)
</div>
<div class="col-lg-9">
<div class="row">
<p>
<strong>#Model.Question</strong>
</p>
</div>
<div class="row" name="**Sub_Text**"> #* **Hide Me!** *#
#Model.SubText
</div>
</div>
}
So far the closest idea I have found is to add a script something like this to the bottom of the template:
<script type="text/javascript">
$(':radio[name=Answer').change(function () {
// read the value of the selected radio
var value = $(this).val();
var doc
if (value == 1) {
$('#Sub_Text').show();
}else{
$('#Sub_Text').hide();
}
});
</script>
Which seems to be able to work for something simpler without using #Html.EditorFor() in a loop.
It looks as if the script does not follow the same automatic naming changes as those that happen to the RadioButtonFor elements. Resulting in things like this:
Radio:
<input id="Questions_0__Answer" name="Questions[0].Answer" type="radio" value="No" />
While the divs and scripts keep referencing only what was directly entered.
How can you dynamically hide the "Sub_Text" div based on the radiobutton when it is nested in this way?
If there is a way to do this without feeding in a script per EditorFor radio group that would be even better, but all solutions are welcome.
Wrap the html generated by the EditorTemplate in a container so that you can use relative selectors
#model ViewModels.QuestionModel
<div class="question"> // container
<div class="col-lg-2">
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.Yes)
....
</div>
<div class="col-lg-9">
....
<div class="row">#Model.SubText</div>
</div>
</div>
and then the script can be
$(':radio').change(function () {
// get the associated element containing the SubText value
var row = $(this).closest('.question').find('.row');
if ($(this).val() == 1) {
row.show();
} else {
row.hide();
}
});
Side note: If your QuestionModel.cshtml is in the /Views/Shared/EditorTemplates or /Views/yourControllerName/EditorTemplates folder (which it should be) then the code in _Reporting.cshtml should be just
#model ViewModels.Prime
#Html.EditorFor(x => x.Questions)
No loop is required. The EditorFor() accepts IEnumerable<T> and generates the correct html for each item in the collection.
Im working with a project and i need to filter my second dropdownlistfor based on my first dropdownlistfor value. Its simple to understand but hard to code it since i dont know jquery or javascript and im working in mvc asp.net, aswell as using a database in sql server where the data is located.
I need to filter my dropdown for project based on my dropdown for customer.
here is some of the code:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>TimeEntry</legend>
<div class="editor-label">
#Html.Label("Customer")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.TimeEntry.CustomerId, #customerSelectList)
#Html.ValidationMessageFor(model => model.TimeEntry.CustomerId)
</div>
<div class="editor-label">
#Html.Label("Project")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.TimeEntry.ProjectId, #projectSelectList, "[ - No project - ]")
#Html.ValidationMessageFor(model => model.TimeEntry.ProjectId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
public IEnumerable<Customer> Customers { get; set; }
public IEnumerable<Project> Projects { get; set; }
here is a code which i think is the code that is calling from the database but not really sure:
var customers = service.GetAllCustomers().ToList();
model.Customers = new SelectList(customers, "CustomerId", "Name");
var projects = service.GetAllProjects().ToList();
model.Projects = new SelectList(projects, "ProjectId", "Name");
Okay so you have a controller with a method that gives you the filtered projects like so:
public class FilterController:Controller {
public ActionResult Projects(int customerId) {
// I expect this call to be filtered
// so I'll leave this to you on how you want this filtered
var projects = service.GetAllProjects().ToList();
// at this point, projects should already be filtered with "customerId"
return Json(new SelectList(projects, "ProjectId", "Name"),
JsonRequestBehavior.AllowGet);
}
}
Then you call that method on the client like this:
// when the customer dropdown changes, you want to use the selected value
// and filter the projects dropdown - more like refresh it
$("#TimeEntry_CustomerId").change(function(){
refreshProjects($(this).val());
});
function refreshProjects(id) {
var projects = $("#TimeEntry_ProjectId");
$.get('#Url.Action("projects","filter")', {customerId:id},
function (result) {
// clear the dropdown
projects.empty();
// rebuild the dropdown
$.each(result, function (i, e) {
projects.append($('<option/>').text(e.Text).val(e.Value));
});
});
}
In this project we have two list, one for the dealer and the second for his products.
So far if you check one dealer we get back all the product for this specific dealer, it implemented in javascript (Json).
Html (5 :)
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>DealerProduct</legend>
<div class="editor-label">
#Html.LabelFor(model => model.DealerID)
</div>
<div class="editor-field">
#Html.DropDownList("DealerID", String.Empty)
#Html.ValidationMessageFor(model => model.DealerID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ProductID)
</div>
<div class="editor-field">
#Html.DropDownList("ProductID", String.Empty)
#Html.ValidationMessageFor(model => model.ProductID)
</div>
<p>
<input type="submit" value="#Shared.Add" />
</p>
</fieldset>
}
JavaScript (Json :)
<script type="text/javascript">
$(document).ready(function()
{
$("#DealerID").change(function ()
{
var self = $(this);
var items="";
var url = "";
url = "#Url.Action("GetDealerProducts","DealerProduct")/"+self.val();
$.ajaxSetup({ cache: false });
$.getJSON(url,function(data)
{
$.each(data,function(index,item)
{
items+="<option value='"+item.Value+"'>"+item.Text+"</option>\n";
});
$("#ProductID").html(items);
$.ajaxSetup({ cache: true });
});
});
});
</script>
Controller :
public ActionResult GetDealerProducts(int id)
{
Dealer currentDealer = db.Dealers.Single(p => p.UserName == User.Identity.Name);
Dealer subDealer = db.Dealers.Single(s => s.DealerID == id);
List<Product> productOpenToSale = new List<Product>();
foreach (var item in currentDealer.ProductToSale)
if (!subDealer.ProductToSale.ToList().Exists(e => e.ProductID == item.ProductID))
productOpenToSale.Add(item.Product);
List<SelectListItem> productOpenToSaleList = new List<SelectListItem>();
productOpenToSale.ForEach(item => productOpenToSaleList.Add(new SelectListItem { Value = item.ProductID.ToString(), Text = item.ProductName }));
return Json(productOpenToSaleList, JsonRequestBehavior.AllowGet);
}
What I really need is adding (a pairing of) products dealer, which he can sell in the future.
Current option is to add products one by one, the desire is to give the possibility of multiple selection of all products.
Maybe something like dynamic checkBoxList or an foreach on a List from the ViewModel who add input - checkbox like this, but I don't know how to fill it after the dealer has selected on the first list and receive all the selected product back on submit..
10X for any help!! (&& sorry for my bad English :)
you can change this line of code
#Html.DropDownList("ProductID", String.Empty)
with something like this
<select id="SelectedItemIds" multiple="multiple" name="SelectedItemIds">
and having a viewModel on the server like this
class MyViewModel
{
public int[] SelectedItemIds { get; set; }
public int DealerID {get;set;}
}
and having a controller like this
[HttpPost]
public ActionResult Index(MyViewModel myViewModel)
{
return View();
}
I have similar situation and made it works here:
enter link description here
but I don't know how to pass the actual text back. I can only pass the index of selected items back to the controller. If you figure it out let me know.
Make sure your select name matches your variable name in the model.