Bind json to html table in view - javascript

i am trying to bind my data to a html table in my view, how do i go about this
public ActionResult FlugTopAir()
{
DataModel db = new DataModel();
var test = db.Database.SqlQuery<FlugTopAirData>("exec sp_FlugTopAir").ToList();
return Json(test, JsonRequestBehavior.AllowGet);
}
public class FlugTopAirData
{
public string Airline { get; set; }
public double Spend { get; set; }
public double TA { get; set; }
}

That will depend on the client side framework that you use.
If you are looking for the native js here is the link:
https://www.w3schools.com/js/js_json_html.asp

You could use jQuery Ajax to call that controller action. Like below
<table class="table">
<thead>
<tr>
<td>Airline</td>
<td>Spend</td>
<td>TA</td>
</tr>
</thead>
<tbody id="tableBody"></tbody>
</table>
#section scripts{
<script type="text/javascript">
$.ajax({
url: '#Url.Action("FlugTopAir")',
type: 'GET',
cache: false,
success: function (result) {
var rows = result.map(function (record) {
var row = $("<tr></tr>");
var airline = $("<td></td>").html(record.Airline);
var spend = $("<td></td>").html(record.Spend);
var ta = $("<td></td>").html(record.TA);
row.append(airline, spend, ta);
return row;
});
$("#tableBody").append(rows);
}
});
</script>
}
You should probably consider using some template engine like JSRender for this to be honest.
Or the easiest way would be to return the view with model so you can use Razor syntax to iterate through Model from the view
View (Index.cshtml)
#using MVCTestApp.Models
<table class="table">
<thead>
<tr>
<td>Airline
<td>Spend</td>
<td>TA</td>
</tr>
</thead>
#foreach (TestModel testModel in Model)
{
<tr>
<td>#testModel.Airline</td>
<td>#testModel.Spend</td>
<td>#testModel.TA</td>
</tr>
}
</table>
In controller, instead of returning Json, return View
return View(test);

Related

Actionlink rowindex stored to a C# get set

I have an ActionLink that is deleting a row from a html table and should be updating the controller. The problem however is that the information of the row that the button is on isn't being shared with the controller once the button is clicked.
<table id="LansingData" class="table">
<thead>
<tr>
<th>Action</th>
<th>Row ID</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Records)
{
<tr id="#item.RowIndex">
<td>#Html.ActionLink("Delete", "Delete", new { id = item.RowIndex }, new { onclick = "return confirm('Are you sure you want to delete this user?');", #class = "delete-button" })</td>
<td>#item.RowIndex</td>
</tr>
}
</tbody>
</table>
This is my controller that is performing the delete.
public ActionResult Delete(int? rowID)
{
if (rowID == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
LansingMileage lansing = db.LansingMileages.Find(rowID);
if (lansing == null)
{
return HttpNotFound();
}
return View(lansing);
}
//POST:
[HttpPost, ActionName("Index")]
[OnAction(ButtonName = "Delete")]
//[ValidateAntiForgeryToken]
public ActionResult Delete(int rowID)
{
LansingMileage lansing = db.LansingMileages.Find(rowID);
db.LansingMileages.Remove(lansing);
db.SaveChanges();
return RedirectToAction("Index");
}
The desired result will be for the link to post to the controller with the rowID of the whatever link was selected.
Looks like a naming issue. The parameter is called id in the view and (most likely) in route definition, but the controller expects rowID. Just rename this last one to be id too:
public ActionResult Delete(int? id)
Model binding in MVC is done by name, so make sure posted parameters always match those expected on the server side.

How do I retrieve a viewmodel from another viewmodel?

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

Knockout - Instead of the data-bind value, javascript is displayed

I created a ASP.Net MVC 5 project and used Knockout.js library.
I have a View called Statement which basically shows the a table with a couple of Transaction items.
My complete Statement.cshtml is as follow:
#using Newtonsoft.Json;
#model IEnumerable<ATMMVCLearning.Models.Transaction>
#{
ViewBag.Title = "Statement";
}
<h2>Statement</h2>
<table class="table table-striped table-bordered">
<thead>
<tr>
<td><strong>Transaction ID</strong></td>
<td><strong>Amount</strong></td>
</tr>
</thead>
<tbody data-bind="foreach:currentTransactions">
<tr>
<td data-bind="text:Id"></td>
<td data-bind="text:formattedPrice"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2">
<span data-bind="click:previousPage" class="glyphicon glyphicon-circle-arrow-left"
style="cursor:pointer;"></span>
<span data-bind="text:currentPage"></span>
<span data-bind="click:nextPage"class="glyphicon glyphicon-circle-arrow-right"
style="cursor:pointer;"></span>
</td>
</tr>
</tfoot>
</table>
<script src="~/Scripts/knockout-3.4.0.js"></script>
<script>
function formattedPrice(amount) {
var price = amount.toFixed(2);
return price;
}
function StatementViewModel() {
var self = this;
//properties
//note that there is a ko.observableArray for making bindings for array
self.transactions = #Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore}));
//TODO: embed transactions from server as JSON array
self.pageSize = 5; //number of transactions to display per page
self.currentPage = ko.observable(1); //the first observable. If the page changes, then the grid changes
self.currentTransactions = ko.computed(function () {
var startIndex = (self.currentPage() - 1) * self.pageSize; //because currentPage is an observable, we get the value by calling it like a function
var endIndex = startIndex + self.pageSize;
return self.transactions.slice(startIndex, endIndex);
});
//methods to move the page forward and backward
self.nextPage = function () {
self.currentPage(self.currentPage() + 1);
};
self.previousPage = function () {
self.currentPage(self.currentPage() - 1);
};
};
ko.applyBindings(new StatementViewModel()); //note this apply bindings, used extensively in KnockOut
</script>
As you can see in the <tbody> I have two <td> elements which have data-bind attribute:
<tbody data-bind="foreach:currentTransactions">
<tr>
<td data-bind="text:Id"></td>
<td data-bind="text:formattedPrice"></td>
</tr>
</tbody>
And the formattedPrice can be referred to the script section below:
function formattedPrice(amount) {
var price = amount.toFixed(2);
return price;
}
Now, I expect the resulting View when it is rendered should show a table with 5 transactions each page, where each table row shows an Id as well as its transaction amount. I.e. something like:
1 100.00
2 150.00
3 -40.00
4 111.11
5 787.33
However, when I render the page, I got the following result:
Instead of Id and amount, I got Id and javascript.
Any idea?
Update:
The Transaction class is as follow:
public class Transaction {
public int Id { get; set; } //this is internally used, not need to have anything
[Required]
[DataType(DataType.Currency)]
public decimal Amount { get; set; }
[Required]
public int CheckingAccountId{ get; set; }
public virtual CheckingAccount CheckingAccount { get; set; } //this is to force the entity framework to recognize this as a foreign key
}
Since formattedPrice is not part of your view-model, Knockout won't automatically unwrap it, nor will it pass it the amount argument.
Try this instead:
<td data-bind="text: formattedPrice(Amount)"></td>
Price probably needs to be computed field and you need to bind to price (I think). It's been a while since I did Knockoutjs.

KnockoutJS code not outputting anything, but no error

I have this Knockout JavaScript code...
var bikesUri = '/api/bikes/';
function ajaxHelper(uri, method, data) {
self.error(''); // Clear error message
return $.ajax({
type: method,
url: uri,
dataType: 'json',
contentType: 'application/json',
data: data ? JSON.stringify(data) : null
}).fail(function (jqXHR, textStatus, errorThrown) {
self.error(errorThrown);
});
}
self.getBikeDetails = function (item) {
ajaxHelper(bikesUri + item.Index, 'GET').done(function (data) {
self.detail(data);
});
}
and this HTML..
<!-- ko if:detail() -->
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Bike Specifics</h2>
</div>
<table class="table table-striped">
<tr><td>Bike Name</td><td data-bind="text: detail().CycleName"></td></tr>
<tr><td>Manufacturer</td><td data-bind="text: detail().Manufacturer"></td></tr>
<tr><td>Shop Category</td><td data-bind="text: detail().Category"></td></tr>
<tr><td>Retail Price</td><td data-bind="text: detail().RRP"></td></tr>
<tr><td>Our Price</td><td data-bind="text: detail().OurPrice"></td></tr>
<tr><td>Stock Level</td><td data-bind="text: detail().Stock"></td></tr>
</table>
</div>
<!-- /ko -->
and this Data Transfer object.
public class BikeDetailsDTO
{
public int Index { get; set; } // ID
public string CycleName { get; set; }
public string Category { get; set; } // Pulled from Category Maps
public string Manufacturer { get; set; }
public double OurPrice { get; set; } // pulled from suppliers
public double RRP { get; set; } //pulled from suppliers
public int Stock { get; set; } // pulled from suppliers
}
The API works perfectly. when you access the API through the browser it returns exactly what I want it to do.. Return the relevant bike by its ID.. Wonderful.
When I go to access the view that the Interface is on, I get nothing. No error, when I click on the Show details button to execute the "getBikeDetails" it shows the table, but no data.. nothing. All other parts of the API are perfectly fine apart from this code and its driving me nuts!!!!!
Can anyone shed any light on this please as I really cant see it..
simple modify your view like this to make it work use with and remove containerless
<div class="panel panel-default" data-bind="with:detail">
<div class="panel-heading">
<h2 class="panel-title">Bike Specifics</h2>
</div>
<table class="table table-striped" data-bind="foreach:$data">
<tr>
<td>Bike Name</td>
<td data-bind="text:CycleName"></td>
</tr>
<tr>
<td>Manufacturer</td>
<td data-bind="text:Manufacturer"></td>
</tr>
</table>
</div>
sample working fiddle here you can use nested div(if it's ok)
Containerless helps as you have class applied on div check fiddle using containerless here

Error using partial view, javascript and viewbag foreach

I'm trying to load a partial view using JavaScript, in turn the partial view will have a View Bag", to loop through.
All is working well, until I try to render the partial view I get an "object Object" error, if I remove the View bag loop the partial view loads
Controller
[HttpPost]
public ActionResult ServiceDetails(int id )
{
int count = 0;
var m = from c in db.ServiceCategoryFields
where c.serviceTypeID == id
select c;
ViewBag.count = count;
ViewBag.m = m.ToList();
return PartialView(m.ToList());
}
Partial View
<table style ="width:100% ">
<tr>
#foreach (var image in (List<String>)ViewBag.m)
{
<td>
#image
</td>
}
</tr>
JS File
type: "POST",
success: function (data) {
display.html('');
display.html(data);
},
error: function (reponse) {
alert("JS Error : " + reponse.toString());
}
Quick Solution
Based on your controller code below
[HttpPost]
public ActionResult ServiceDetails(int id )
{
int count = 0;
var m = from c in db.ServiceCategoryFields
where c.serviceTypeID == id
select c;
ViewBag.count = count;
ViewBag.m = m.ToList();
return PartialView(m.ToList());
}
ViewBag.m would be an instance of List<ServiceCategoryField>, but you convert it to List<string> in the partial view
#foreach (var image in (List<String>)ViewBag.m)
so you got the error. Assuming that PropertyName is the property of ServiceCategoryField with the value that you want to display inside <td> tags, you need to convert ViewBag.m to List<ServiceCategoryField> in the partial view as below
<table style ="width:100% ">
<tr>
#foreach (var image in (List<ServiceCategoryField>)ViewBag.m)
{
<td>
#image.PropertyName
</td>
}
</tr>
Alternative Solution
The previous solution requires converting ViewBag.m and it could produce runtime errors if you convert ViewBag.m to the wrong type. You can avoid the conversion in the partial view by using this alternative solution.
The first thing to do is creating a model class that will be used by the partial view, let's say the class name is ServiceDetailsViewModel and it has Count and Images property
public class ServiceDetailsViewModel
{
public int Count { get; set; }
public List<string> Images { get; set; }
}
Create an instance of ServiceDetailsViewModel, assign the properties, and pass model to the partial view in the controller. I assume PropertyName is a string and c.PropertyName is where the image in the partial view comes from
[HttpPost]
public ActionResult ServiceDetails(int id )
{
int count = 0;
var m = from c in db.ServiceCategoryFields
where c.serviceTypeID == id
select c.PropertyName;
ServiceDetailsViewModel model = new ServiceDetailsViewModel();
model.Count = count;
model.Images = m.ToList();
return PartialView(model);
}
Set ServiceDetailsViewModel as the model by using the below syntax at the top of your partial view code
#model ServiceDetailsViewModel
and loop through Model.Images as below
<table style ="width:100% ">
<tr>
#foreach (var image in Model.Images)
{
<td>
#image
</td>
}
</tr>

Categories

Resources