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
Related
I am trying to store the employeeIds from the selected row of the table into the model column EmployeeReinstateVM.selectedEmployeeId from the click event of 'btnUpdate', each id must be stored to EmployeeReinstateVM.selectedEmployeeId. Currently the Ids are stored in to selectedEmployeeId hidden column as array string "23,24,25" So I am trying to store each employee id of the selected rows into the EmployeeReinstateVM.selectedEmployeeId from javascript to send the model into controller post method with selected employeeIds. I am looking for the help from someone. Here is the code
Model Class
public class EmployeeReinstateVM
{
public int EmployeeID { get; set; }
public string EmployeeName { get; set; }
public List<string> selectedEmployeeId { get; set; }
public IEnumerable<EmployeeModel> employees { get; set; }
}
Views
<style>
.selectable-row.selected {
background-color: #ddd;
}
</style>
#model EmployeeReinstateVM
foreach (var item in Model.employees)
{
<tr class="selectable-row
#(Model.selectedEmployeeId.Contains(item.EmployeeID.ToString()) ? "selected" :"")"
employee-id="#item.EmployeeID">
<td>#item.EmployeeID</td>
<td>#item.EmployeeName</td>
</tr>
}
<input hidden id="selectedEmployeeId" asp-for="selectedEmployeeId" name="selectedEmployeeId" value="">
<button type="submit" class="btn btn-primary form-control" id="btnUpdate" name="btnActivate" value="update">
Update
</button>
<script type="text/javascript">
$(document).ready(function() {
var employeeIds = [];
$(".selectable-row").click(function() {
$(this).toggleClass("selected");
var employeeId = $(this).attr('employee-id');
if ($(this).hasClass("selected")) {
employeeIds.push(employeeId);
//employeeIds.push($(this).attr('employee-id'));
} else {
employeeIds = employeeIds.filter(function(id) {
return id !== employeeId;
});
}
});
$("#btnUpdate").click(function() {
$("#selectedEmployeeId").val(employeeIds);
console.log($("#selectedEmployeeId").val());
});
})
This seems to be simpler - you need to store the result
$(".selectable-row").click(function() {
$(this).toggleClass("selected");
$("#selectedEmployeeId")
.val(
$("tr[employee-id].selected")
.map(function() { return $(this).attr("employee-id") })
.get()
.join(",")
);
});
store each employee id of the selected rows into the
EmployeeReinstateVM.selectedEmployeeId from javascript to send the
model into controller post method with selected employeeIds
Do you want to try the below code?
$("#btnSave").click(function () {
$("#selectedEmployeeId").val(employeeIds);
console.log($("#selectedEmployeeId").val());
$.ajax({
type: "POST",
url: "/Keepselected/ReinstateEmployee",
data: { "selectedEmployeeId": employeeIds },
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function (response) {
alert(response);
}
});
});
result:
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:
I'm trying to remove or hide items from a list and I'm facing two problems, 1- the newly cannot be removed, 2- Tried to tag the deleted items as isDeleted = true using Javascript then later delete them in the controller following this answer https://stackoverflow.com/a/40572625/10773318 but it didn't work.
Here's my view models
public class CreateEditParentViewModel
{
public int Id { get; set; }
public IList<ChildViewModel> ChildrenLists { get; set; }
}
public class ChildViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool isDeleted { get; set; }
}
In the main view
<div id="editorRows">
#foreach (var item in Model.ChildrenLists)
{
<partial name="_RowPartial" model="item" />
}
</div>
<a id="addItem" asp-action="BlankRow" asp-controller="Home">Add Row...</a> <br />
<input type="submit" value="Finished" />
The javascript in the main view
#section scripts {
<script>
$("#addItem").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) { $("#editorRows").append(html); }
});
return false;
});
$("a.deleteRow").click(function () {
$(this).parents("div.editorRow:first").remove(); //does not work with newly added
return false;
}); //what it should do: hide and set isDeleted = true if id is not null - remove if null
</script>
Finally the partial view
<div class="editorRow">
#using (Html.BeginCollectionItem("ChildrenLists"))
{
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.isDeleted)
<span>Name: </span> #Html.EditorFor(m => m.Name);
}
delete
1- the newly cannot be removed
You can manually bind click event handler for the new generated <a href="#" class="deleteRow"> element, like below.
success: function (html) {
$("#editorRows").append(html);
$("a.deleteRow").bind("click", function () {
//...
//code logic here
});
}
2- Tried to tag the deleted items as isDeleted = true using Javascript
To achieve the requirement, you can refer to the following code snippet.
<script>
$("#addItem").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) {
$("#editorRows").append(html);
$("a.deleteRow").bind("click", function () {
del_row($(this));
});
}
});
return false;
});
$("a.deleteRow").click(function () {
del_row($(this));
return false;
});
function del_row(el) {
console.log("del");
console.log($(el).siblings("input[id$='__Id']").val());
var childitem_id = $(el).siblings("input[id$='__Id']").val();
if (childitem_id == 0 || childitem_id == "") {
$(el).parent("div.editorRow").remove();
} else {
$(el).siblings("input[id$='__isDeleted']").val("true");
$(el).parent("div.editorRow").hide();
}
return false;
}
</script>
Test Result
Newbie ALERT
Basically I have a web application that has a dropdown list. When you select an item in the drop-down list the table is drawn to show all the credentials that are tied to that drop-down option.
Problem: When running, everything functions properly except for the JavaScript piece that does not remove the line in the table, but deletes the record on the back-end. So once i refresh and go back to that credential type the one I deleted is gone.
I've tried a lot of different stuff, but i pretty new to JavaScript and C#, don't know if there is a better way of doing this. Probably supplied too much information but i rather too much than not enough! :)
Any help, tips, ideas are greatly appreciated.
Credential API Controller: Delete Function
[HttpDelete]
public IHttpActionResult DeleteCustomer(int id)
{
var credentialInDb = _context.Credentials.SingleOrDefault(c => c.Id == id);
if (credentialInDb == null)
return NotFound();
_context.Credentials.Remove(credentialInDb);
_context.SaveChanges();
return Ok();
}
Model for Credential
public class Credentials
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Required]
[StringLength(255)]
public string Username { get; set; }
[Required]
[StringLength(255)]
public string Password { get; set; }
public string Website { get; set; }
public string Notes { get; set; }
public CredentialType CredentialType { get; set; }
[Display(Name = "Credential Type")]
public int CredentialTypeId { get; set; }
}
ViewModel for CredentialFormViewModel
This allows the selectedCredential variable for the page below
public class CredentialFormViewModel
{
public IEnumerable<CredentialType> CredentialTypes { get; set; }
public Credentials Credentials { get; set; }
public int SelectedCredentialTypeId { get; set; }
}
View that displays the DataTable:
#model Appp.ViewModels.CredentialFormViewModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Select a Credential Type</h2>
#Html.DropDownListFor(m => m.SelectedCredentialTypeId, new SelectList(Model.CredentialTypes, "Id", "Name"), "Select Credential Type", new { #class = "form-control", onchange = "SelectCredType()" })
<br/>
<table id="credentials" class="table table-bordered table-hover">
<thead>
<tr>
<th>Credential</th>
<th>Username</th>
<th>Password</th>
<th>Website</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
#section scripts
{
<script>
function SelectCredType() {
var credId = $('#SelectedCredentialTypeId').val();
if ($.fn.dataTable.isDataTable("#credentials")) {
if (credId == "") {
var table = $("#credentials").DataTable();
table.destroy();
} else {
var table = $("#credentials").DataTable();
table.destroy();
SelectCredType();
}
} else {
$(document)
.ready(function() {
var table = $("#credentials")
.DataTable({
ajax: {
url: "/api/credentials?credentialTypeId=" + credId,
dataSrc: ""
},
columns: [
{
data: "name",
},
{
data: "username"
},
{
data: "password"
},
{
data: "website"
},
{
data: "id",
render: function(data, type, credentials) {
return "<button class='btn btn-primary btn-xs js-delete' data-credential-id=" + credentials.id + ">Delete</button>";
}
}
]
});
}
);
}
};
$("#credentials")
.on("click",
".js-delete",
function() {
var button = $(this);
bootbox.confirm("Are you sure you want to delete this?",
function(result) {
if (result) {
$.ajax({
url: "/api/Credentials/" + button.attr("data-credential-id"),
method: "DELETE",
sucess: function() {
table.row(button.parents("tr")).remove().draw();
}
});
}
});
});
</script>
}
First issue
Your JavaScript code does not work because the table variable is undefined within your delete function.
There are many ways you could approach to fix that. But first you will need to get your head around variable scopes in JavaScript.
Your simplest solution is to make table a globally-scoped variable that way you can access the instance from any function you create. So instead of defining it here:
...
$(document)
.ready(function() {
var table = $("#credentials")
...
Move it up to the top of your script file:
var table;
function SelectCredType() {
...
$(document)
.ready(function() {
table = $("#credentials")
...
}
Now when you access it from your Delete function, it will be defined.
Note: I would also change the name of the table variable to something else as global variables in JavaScript will conflict with any script you import which can lead to a debugging nightmare. Best to name it something that will be most likely unique, eg. coberlinTable.
Second Issue
I don't know if you did a cut and past error, but you have misspelled success in your ajax Delete function.
I'm trying to push an ajax response array into MVC table. This is how my script looks like:
<script type="text/javascript">
$(document).ready(function () {
$('#form1').submit(function (event) {
event.preventDefault();
event.returnValue = false;
var selectValue = $('#selectValue').val();
$.ajax({
url: "/api/Admin/GetDepotDetails/",
type: "POST",
data: { "selectValue": selectValue },
dataType: "json",
success: function (data) {
$("#Grid").html($(data).children());
},
error: function (jqXHR, textStatus, errorThrown) {
debugger;
alert(textStatus, errorThrown, jqXHR);
}
});
});
});
</script>
This is how my partial view looks like:
#model IEnumerable<SampleApp.DepotDetail>
<table class="table table-condensed" id="Grid">
<tr>
<th>
#Html.DisplayNameFor(model => model.DepotID)
</th>
<th>
#Html.DisplayNameFor(model => model.ColumnName)
</th>
<th>
#Html.DisplayNameFor(model => model.Country)
</th>
<th>
#Html.DisplayNameFor(model => model.CountryCode)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr class="warning">
<td>
#Html.DisplayFor(modelItem => item.DepotID)
</td>
<td>
#Html.DisplayFor(modelItem => item.ColumnName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Country)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountryCode)
</td>
</tr>
}
</table>
This is how the WebApi method looks like:
[HttpPost]
public IEnumerable<DepotDetail> GetDepotDetails(Selected selectValue)
{
var model = depotsDetails.Where(x => x.ColumnName == selectValue.SelectValue) as IEnumerable<DepotDetail>;
var viewModel = new SearchViewModel{ DepotDetailsList = model, ActionLists = new ActionList()} ;
return model;
}
This is how the View looks like:
#model IEnumerable<SiemensSampleApp.DepotDetail>
<div class="row">
<div class="col-md-4">
<form id="form1">
#*#Html.DropDownListFor(model => model.DepotListSelectValue, Model.DepotLists, new { #class = "form-control" })*#
#Html.DropDownList("selectValue", new List<SelectListItem>
{
new SelectListItem() {Text = "Depot ID", Value="Depot ID"},
new SelectListItem() {Text = "Depot Name", Value="Depot Name"},
new SelectListItem() {Text = "Address", Value="Address"}
}, new { #class = "selectValue", #id = "selectValue" })
#*//, new { #class = "chzn-select", #id = "chzn-select" }*#
<input type="submit" value="submit" />
</form>
<br /><br /><br />
<table id="records_table" style="width:100%;"></table>
<div id="tableHere">
#{
if (Model == null)
{
Html.RenderPartial("_SearchResult", new List<DepotDetail>() { });
}
}
</div>
</div>
</div>
Question: Through WebApi i'm trying to get a List of details and bind it to a MVC table. What is the best way to do this?
I have used
$("#Grid").html($(data).children());
To fill the Grid. But the table doesn't have any data. can someone please give me an idea how to fill the grid using above Partial view.
Thank you in advance!
Your web api endpoint return data ( in json format), not the HTML markup from your partial view. You have 2 options.
1) Create an mvc action method which gets the data and pass it to your partial view and return the partial view response and use that to update your UI
[HttpPost]
public IEnumerable<DepotDetail> GetDepotDetails(Selected selectValue)
{
var model = depotsDetails.Where(x => x.ColumnName == selectValue.SelectValue)
as IEnumerable<DepotDetail>;
return PartialView(model);
}
Now make sure you have a partial view called GetDepotDetails.cshtml in ~/Views/Shared or ~/View/YourControllerName/. This view should be strongly typed to a collecction of DepotDetail.
#model IEnumerable<DepotDetail>
<p>Here loop through each item in Model and render the table</p>
<p> Same as your partial view in the question </p>
And in your success event,
success: function (data) {
$("#Grid").html(data);
},
2) Use your current web api endpoint and read the data in your ajax method's success event and dynamically build the html markup for the table rows and set that as the content of your Grid table.
success: function (data) {
var tblHtml="";
$.each(data.DepotDetailsList,function(a,b){
tblHtml+= "<tr><td>"+b.DepotID+"</td>";
tblHtml+= "<td>"+b.ColumnName+"</td>";
tblHtml+= "<td>"+b.Country+"</td>";
tblHtml+= "<td>"+b.CountryCode+"</td>M/tr>";
});
$("#Grid > tbody").html(tblHtml);
},
Since you already have the partial view which build the table, you can do this.
In your ajax success method call a controller action by passing this data received from the API. The controller will just return the existing partial view by passing the same model.
$.ajax({
url: "/api/Admin/GetDepotDetails/",
type: "POST",
data: { "selectValue": selectValue },
dataType: "json",
success: function (data) {
//$("#Grid").html($(data).children());
$.get("controller/Action",data.DepotDetailsList ,function(response){
$('#tableHolder').html(response) //have a div in your main view which will hold the table. Now the partial view has to be replaced into this div.
});
},
error: function (jqXHR, textStatus, errorThrown) {
debugger;
alert(textStatus, errorThrown, jqXHR);
}
});
So as I said, Create a new MVC action method and return a the same partial view by passing the model sent from ajax.
OR you can user Jquery and build the table again - But this is a pain if the table HTML is large (with css, attributes, dynamic arributes etc). - I think the other answer already has the details on this