i am using knockout to display items on page. I have a list of groups ex: Group 1, Group 2,... each group is in it's own div. When i click on one of the groups it will open and display the items in the group. Some of my groups don't have any items to display and instead of it not showing anything i would like to change that to display: "No items in group"
I am having trouble doing this in the view in javascript and thought i would be able to do it in my knockout/jquery script
View:
<div class="accordion-group elements-by-item">
<div class="accordion-heading">
<a class="ui_title accordion-toggle text_x-large item_accordion_toggle" data-toggle="collapse" data-parent="#ByTimeIndex"
data-bind="text: Title() != null ? Title() : Identity(), attr: { 'href': '#itemContent_' + Id(), 'data-item-id': Id() }">
</a>
</div>
<div class="accordion-body collapse state-loading" data-bind="attr: { 'id': 'itemContent_' + Id(), 'data-item-id': Id() }">
#Html.Partial("_itemElements")
</div>
</div>
**_itemElements Page:**
<div class="accordion-inner no_border" data-bind="foreach: Children">
<div class="element">
........
</div>
<div>
knockout/Jquery js
$idx.ItemsRetrieved = new Array();
$idx.GetItemContent = function (element) {
var _itemId = element.attr('data-item-id');
var _elementData = $idx.itemData;
this.GetElementContent({
groupId: _itemId,
groupData: _elementData.items,
elementData: _elementData,
apiUrl: _courseIndexOptions.GetitemUrlPrefix + _itemId,
accordionBodySelector: '.accordion-body[data-item-id="' + _itemId + '"]',
accordionBtnSelector: 'a[data-item-id="' + _itemId + '"]',
viewModel: $idx.TimeViewModel
});
}
$idx.GetElementContent = function (options) {
if (linq.From($idx.ItemsRetrieved).Any(function (x) { return x == options.groupId })) {
$(options.accordionBodySelector).removeClass(constants.StateClasses.Loading);
return;
}
return Ajax.Get({
Url: options.apiUrl,
OnSuccess: function (data) {
var _items = linq.From(options.groupData);
var _itemToUpdate = _items.Where(function (x) { return x.Id == options.groupId; });
if (_itemToUpdate.Any()) {
_itemToUpdate.First().Children = data.Items;
}
ko.mapping.fromJS(options.elementData, options.viewModel);
sections.ElementArray.AddRange(data.Items);
$(options.accordionBodySelector).removeClass(constants.StateClasses.Loading);
$idx.ItemsRetrieved.push(options.groupId);
$(options.accordionBtnSelector).click();
}
});
how can i check if the children ItemsRetrieved = 0 and to set a message "No Items" to show in the view page?
You can do that :
<div class="accordion-inner no_border" >
<div data-bind="foreach: Children">
<div class="element">
</div>
</div>
<span data-bind="if : Children().length == 0">No items in group</span>
<div>
I hope it helps.
Related
I need help filling dependent dropdowns. I have dependent dropdown that work when entering data, select the State dropdown and the dependent dropdowns reload based on the state selected.
Issue is when I want to edit, the state is filled and selected from database, but the dependents don't get filled and selected. The onChange function doesn't get activated or hit.
Here are my codes:
<div class="form-row">
<div class="col">
<div class="form-group">
<label asp-for="Sposted"></label>
<select asp-for="Sposted"
class="form-control"
asp-items="#(new SelectList(#ViewBag.statelist, "Stateid", "Statename" ))"
onchange="sposted(this)">
</select>
</div>
</div>
<div class="col">
<div class="form-group">
<label asp-for="Pcommand"></label>
<select asp-for="Pcommand" class="form-control" id="Pcommand"
asp-items="#(new SelectList(string.Empty, "Commandid", "Cfname"))">
<option>Select ...</option>
</select>
</div>
</div>
<div class="col">
<div class="form-group">
<label asp-for="PayP"></label>
<select asp-for="PayP" id="PayP"
class="form-control"
asp-items="#(new SelectList(string.Empty, "Ppid", "Ppfull"))"></select>
</div>
</div>
</div>
The 2 dropdowns, Pcommand and PayP are dependent on sposted. Again, when editing, the sposted drop down is selected and filled from db, but doesn't cascade to the other 2.
Here is the JS:
<script type="text/javascript">
//$(document).ready(function () {
//$('#Sposted').change(function () {
function sposted(stateid) {
console.log(stateid.value);
var url = '#Url.Content("~/")' + "MemberList/RetPayPoint";
//var ddlsource = "#Sposted";
//$.getJSON(url, { Stateid: $(ddlsource).val() }, function (data) {
$.getJSON(url, { Stateid: stateid.value }, function (data) {
var items = '';
$("#PayP").empty();
$.each(data, function (i, pp) {
items += "<option value='" + pp.value + "'>" + pp.text + "</option>";
});
$('#PayP').html(items);
});
}//});
// });
</script>
Thank you in advance.
A few days later, I have decided to add the controller method that is supposed to fill the dropdowns in the view.
public IActionResult DisplayMem()
{
var statelist = _mr.GetStates().ToList();
statelist.Insert(0, new ToxState { Stateid = 0, Statename = "Select..." });
ViewBag.statelist = statelist;
var rank = _mr.GetRanks().ToList();
rank.Insert(0, new ToxRank { Rankid = 0, Fullname = "Select..." });
ViewBag.rank = rank;
//memid = memlist.FirstOrDefault().MemberId;
var obj = _mr.MemberInfo((long)_ar.FindAcc(long.Parse(HttpContext.Session.GetString("memberid"))).MemId);
return View(obj);
}
All he information needed to fill the view elements are in obj. It loads the selects the state from the id in obj, but the onchange isn't fired to fill the dependent dropdowns.
When editing using selected stateid you need to get both dropdowns data, just like you are getting PayP data by using selected stateid like:
$.getJSON(url, { Stateid: stateid.value }, function (data) {
var items = '';
$("#PayP").empty();
$.each(data, function (i, pp) {
items += "<option value='" + pp.value + "'>" + pp.text + "</option>";
});
$('#PayP').html(items);
});
You will call your function sposted and pass selected stateid both times while creating or editing.
After days of research, I couldn't seem to find a way to to force the onchange to call Ajax to dynamically fill the dependent dropdowns. So I took a cue from Mateen's 3rd comment and rewrote the method in the controller to read load the relevant items into a ViewBag.
public IActionResult DisplayMem()
{
var statelist = _mr.GetStates().ToList();
statelist.Insert(0, new ToxState { Stateid = 0, Statename = "Select..." });
ViewBag.statelist = statelist;
var rank = _mr.GetRanks().ToList();
rank.Insert(0, new ToxRank { Rankid = 0, Fullname = "Select..." });
ViewBag.rank = rank;
var obj = _mr.MemberInfo((long)_ar.FindAcc(long.Parse(HttpContext.Session.GetString("memberid"))).MemId);
ViewBag.payp = _mr.GetPayPoint(obj.Sposted.Value).ToList();
ViewBag.pcommand = _mr.GetCommand(obj.Sposted.Value).ToList();
return View(obj);
}
On a main page for example the Edit.cshtml I have this code here which renders a select 2 with the country flags and it works fine, but when I attempt to move it into a partial view it does not work.
My Html Field which is inside PleasureCraftEditViewPartial.cshtml
<div class="form-group">
#Html.DisplayNameFor(model => model.MooringCountry)
<select asp-for="MooringCountry" class="form-control select2" style="height:35px" id="MooringCountry" name="MooringCountry">
<option>Please select Mooring Country</option>
</select>
<span asp-validation-for="MooringCountry" class="text-danger"></span>
</div>
The above is in my PleasureCraftEditViewPartial.cshtml
#if (#Model.VesselCat == (int)VesselCat.VesselCatType.Commercial) {
#await Html.PartialAsync("ComercialEditViewPartial")
}
#if (#Model.VesselCat == (int)VesselCat.VesselCatType.MotorBoats ||
#Model.VesselCat == (int)VesselCat.VesselCatType.SailingBoats ||
#Model.VesselCat == (int)VesselCat.VesselCatType.SmallBoats) {
#await Html.PartialAsync("PleasureCraftEditViewPartial")
}
The below is in my Edit.cshtml
<script>
$(function () {
//Initialize Select2 Elements
$('.select2').select2();
var isoCountries = [
{ id: 1, flag: 'gbp', text: 'United Kingdom' },
{ id: 2, flag: 'usa', text: 'United States' }
];
function formatCountry(country) {
if (!country.id) { return country.text; }
var $country = $('<span class="flag-icon flag-icon-' + country.flag + ' flag-icon-squared"></span>' + '<span class="flag-text">' + country.text + "</span>");
return $country;
};
//Assuming you have a select element with name country
// e.g. <select name="name"></select>
$("[id='Flag']").select2({
placeholder: "Please Select a Flag",
templateResult: formatCountry,
data: isoCountries
});
$("[id='MooringCountry']").select2({
placeholder: "Please Select a Mooring Country",
templateResult: formatCountry,
data: isoCountries
});
$('#Flag').trigger('change');
});
</script>
There are no errors in my console
Just an empty dropdown
In my Action I have Three LINQ SQL(Join) , two of them which is bla4,bla5 it was working until i add Third SQL which is bla6 and SQL(bla6) only going to work or executed until RMAHistory table get data/value or have data in it and RMAHistory table get value/data until than user submitted the form before that all the rows is null in RMAHistory table and in my LINQ SQL (bla6) i have Join with RMAHistory and beacuse i have interesting one column of that table.
Here is my question how can i check if SQL (bla6) its null than run/execute bla4,bla5 and than return view and if SQL(bla6) its not null than run/execute (bla4,bla5,bla6) and in the return view.
I have tried to check if modal its null or not both in view and Controller ,but i get Object reference is not set to an instance of an object and it's beacuse rmah.AntalRMA is null.
Can anyone help me or point me in the right direction!
Thanks in advance :)
Controller:
public ActionResult RMA(RMAHistory oodvm ,string id, string Varenummer, string OrdreNo)
{
var bla6 = (from sil in data.Sales_Invoice_Line
join rmah in data.RMA_History on sil.Document_No_ equals rmah.Fakturnummer
where sil.Document_No_ == id
select new RMAHistory.SingelRMAAntal
{
TotalRMA = rmah.AntalRMA
});
var col2 = data.Sales_Shipment_Line.Where(t => t.Order_No_ == OrdreNo).Where(t => t.No_ == Varenummer).Select
(t => new
{
No_ = data.Sales_Invoice_Header.Where(or => or.Order_No_ == OrdreNo).FirstOrDefault().No_,
Line = t,
Serial = data.Item_Ledger_Entry.Where(ledger => ledger.Document_No_ == t.Document_No_).Where(ledger => ledger.Document_Line_No_ == t.Line_No_).ToList(),
TrackAndTrace = data.Track_and_Trace.Where(track => track.Shipping_No_ == t.Document_No_).Select(tr => new { traceNR = tr.Track_and_Trace, tracePath = tr.Track_and_trace_path, Agent = tr.Shipping_agent }).FirstOrDefault()
});
var bla4 = col2.Select(t =>
new RMAHistory.OrdreRMA
{
//Select something
});
var bla5 = (from sih in data.Sales_Invoice_Header
join sil in data.Sales_Invoice_Line on sih.No_ equals sil.Document_No_
join item in data.Item on sil.No_ equals item.No_
join itemcat in data.ItemCategory on item.Item_Category_Code equals itemcat.Code
where sil.Document_No_ == id
&&
sil.No_ == Varenummer
&&
sih.Order_No_ == OrdreNo
select new RMAHistory.InvoiceOrdreLineSingel
{
//Select something
});
oodvm.OrdreRMAs = bla4.FirstOrDefault();
oodvm.InvoiceDetailsSingelLine = bla5.FirstOrDefault();
oodvm.SingelRMAAntals = bla6.FirstOrDefault();
return View(oodvm);
}
RMAHistory ViewModel:
public class RMAHistory
{
public SingelRMAAntal SingelRMAAntals { get; set; }
public class SingelRMAAntal
{
public SingelRMAAntal()
{
}
public SingelRMAAntal(string TotalRMA)
{
this.TotalRMA = TotalRMA;
}
public string TotalRMA { get; set; }
}
}
View:
#using NameSpace.Models
#model RMAHistory
<div class="content">
<form id="RMAForm">
<input type="text" id="Kundenavn" value="#Model.InvoiceDetailsSingelLine.Kundenavn">
<br/>
<input id="Ordrenummer" type="text" value="#Model.InvoiceDetailsSingelLine.Ordrenummer">
<br/>
if (Model.SingelRMAAntals.TotalRMA == null)
{
<div style="display:none;" class="col-md-3">
<input name="Antal_RMA" id="Antal_RMA" value="#Model.SingelRMAAntals.TotalRMA">
</div>
}
else
{
<div class="col-md-3">
<input name="Antal_RMA" id="Antal_RMA" value="#Model.SingelRMAAntals.TotalRMA">
</div>
}
</form>
</div>
Change your view to look like below
#using NameSpace.Models
#model RMAHistory
<div class="content">
<form id="RMAForm">
<input type="text" id="Kundenavn" value="#Model.InvoiceDetailsSingelLine.Kundenavn">
<br/>
<input id="Ordrenummer" type="text" value="#Model.InvoiceDetailsSingelLine.Ordrenummer">
<br/>
if (Model != null)
{
if (Model.SingelRMAAntals != null)
{
if (Model.SingelRMAAntals.TotalRMA == null)
{
<div style="display:none;" class="col-md-3">
<input name="Antal_RMA" id="Antal_RMA" value="#Model.SingelRMAAntals.TotalRMA">
</div>
}
else
{
<div class="col-md-3">
<input name="Antal_RMA" id="Antal_RMA" value="#Model.SingelRMAAntals.TotalRMA">
</div>
}
}
}
</form>
</div>
I am using Ajax to populate a partial view in my web application. This partial view contains a link to download a PDF file based upon the data that is currently in the table / List<> of the model.
The partial view is as follows:
#model Inspection_Reports.ViewModel.SummaryReportViewModel
<table id="summaryReportTable" class="table-condensed table-striped">
<thead><tr><td>Inspector</td><td>Attendant</td><td>Property</td><td>Room Number</td><td>Date</td><td>HK Score</td><td>Maint. Score</td></tr></thead>
<tbody id="resultsContainer">
#foreach (var report in #Model.reportsList)
{
<tr><td>#report.inspect.empName</td><td>#report.attendant.empName</td><td>#report.location.locName</td><td>#report.room</td><td>#report.endTime</td><td>#report.hkDisplay</td><td>#report.mainDisplay <input type='hidden' name='reportId[i]' /></td></tr>
}
</tbody>
</table>
#Html.ActionLink("Export as PDF", "GenerateSummaryPDF", new { summary = #Model.reportsList })
GenerateSummaryPDF method:
public FileResult GenerateSummaryPDF(List<report_summary> summary) {
Document doc = pdfWorker.readyDocument("Inspection Report, Generated " + DateTime.Now.ToString("MM-dd-yyyy"));
pdfWorker.createSummaryReport(doc, summary);
pdfWorker.savePDF(doc, String.Format("{0}/Inspection_Summary_{1}.pdf", #"C:\Users\Khandokar\Desktop", DateTime.Now.ToString("MM-dd-yyyy")));
return File(String.Format("{0}/Inspection_Summary_{1}.pdf", #"PATH", DateTime.Now.ToString("MM-dd-yyyy")), "application/pdf", "Inspection.pdf");
The problem is that, when the GenerateSummaryPDF is called, the summary list is empty. The list is not null, but merely has no items in it.
However, I am not sure why this is the case. When I click the export link, there is data in Model.reportsList; it is visible in the table and further verified by setting a breakpoint.
The parent view:
#model Inspection_Reports.ViewModel.SummaryReportViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Report Summaries</title>
</head>
<body>
<h2>Summary Reports</h2>
<form class="form-horizontal">
<div class="form-group"><label class="control-label col-md-2">Start Date: </label><div class="col-md-4"><input class="form-control summaryFilter" type='text' value="#Model.fromDate" name='startDate' id='startDate' /></div><label class="control-label col-md-2">End Date: </label><div class="col-md-4"><input type='text' value="#Model.toDate" class='form-control summaryFilter' name='endDate' id='endDate' /></div></div>
<div class="form-group">
<label class="control-label col-md-2">Filter By: </label>
<div class="col-md-4">
<select class="form-control summaryFilter" name="filterTypeList" id="filterTypeList">
<option value="">Select...</option>
<option value="Property">Property</option>
<option value="Attendant">Attendant</option>
<option value="Inspector">Inspector</option>
</select>
</div>
<label class="control-label col-md-2">Filter Selection: </label><div class="col-md-4">
<select class="form-control summaryFilter" name="filterSelectionList" id="filterSelectionList"></select>
</div>
</div>
</form>
<div id="reportResults">
#{Html.RenderPartial("SummaryPartialView", Model);}
</div>
#section scripts {
<script src="~/Scripts/ajaxReports.js"></script>
}
</body>
</html>
The methods used to populate the partial view (based largely on this article: https://cmatskas.com/update-an-mvc-partial-view-with-ajax/)
[HttpGet]
public async Task<ActionResult> GetSummaryReports(string fromDate, string toDate, string filterType, string filterValue)
{
DateTime from = Convert.ToDateTime(fromDate);
DateTime to = Convert.ToDateTime(toDate);
Int32 filterValID = Int32.Parse(filterValue);
SummaryReportViewModel vm = await GetSummaryVM(from, to, filterType, filterValID);
return PartialView("SummaryPartialView", vm);
}
private async Task<SummaryReportViewModel> GetSummaryVM(DateTime from, DateTime to, string filterType, int filterValID)
{
SummaryReportViewModel vm = new SummaryReportViewModel();
to = to.AddDays(1);
var reports = dbContext.report_summary.Where(r => r.endTime <= to && r.endTime >= from);
if (filterType.Equals("Property"))
{
reports = reports.Where(r => r.locationID == filterValID);
}
else if (filterType.Equals("Attendant"))
{
reports = reports.Where(r => r.employee == filterValID);
}
else
{
reports = reports.Where(r => r.inspector == filterValID);
}
vm.reportsList = reports.ToList<report_summary>();
return vm;
}
The Ajax
$(".summaryFilter").change(function () {
var fromDate = $("#startDate").val();
var toDate = $("#endDate").val();
var filterType = $("#filterTypeList").val();
var filterValue = $("#filterSelectionList").val();
if (filterValue != null || typeof (filterValue) != typeof (undefined)) {
$.ajax({
url: "GetSummaryReports?fromDate=" + fromDate + "&toDate=" + toDate + "&filterType=" + filterType + "&filterValue=" + filterValue,
type: 'get',
success: function (data) {
$("#reportResults").html(data);
},
});
}
});
Thanks for any help.
You're asking a bit much of a Get method - you should instead switch to a form that Posts to allow model binding to handle your complex list object.
We're developing news website we're confused with some concept of usage. I'd like to ask and know better if possible. We've a homepage which may contain a lot of models at once so we're separating our homepage to partial views and we're planning to feed them with the appropriate models.
In one partial we're enumerating in categories that are not marked as deleted and we've two types of categories. One of them displays the latest post and the other displays 4 posts at once. We've achieved this actually but as i've mentioned we would like to know if there is a better way or if we're doing anything wrong because right now we're keeping the connection to the context open until the partial is rendered.
Here is the code for views
Partial View Code (CategoryRepeater.cshtml)
#using SosyalGundem.WebUI.DatabaseContext;
#{
var categoryList = new List<PostCategories>();
var db = new SosyalGundemDb();
categoryList = db.PostCategories.Include("Posts").Where(x => !x.IsDeleted).ToList();
}
#for (int i = 0; i < categoryList.Count; i++)
{
if (i % 3 == 0 || i == 0)
{
#Html.Raw("<div class=\"row-fluid spacer\">")
}
var category = categoryList[i];
if (category.PostCategoryType == 1)
{
<div class="span4">
<h3 class="title"><span>#category.PostCategoryName</span></h3>
#{
var article = category.Posts.FirstOrDefault();
if (article != null)
{
<article class="post">
<div class="entry clearfix">
<div class="span6">
<a href="#" title="Permalink to Suspen disse auctor dapibus neque pulvinar urna leo" rel="bookmark">
<img width="225" height="136" src="#Url.Content("~/Content/uploadedimages/" + article.Media.ToList()[0].MediaContent )" alt="shutterstock_70184773" />
</a>
</div>
<div class="span6">
<h4 class="smallnewstitle">#article.PostTitle</h4>
<p>#(article.PostSummary.Length > 100 ? article.PostSummary.Substring(0, 100) : article.PostSummary)</p>
<div class="meta">
<span class="date">#article.PostDate.ToString("MMMM dd, yyyy")</span>
</div>
</div>
</div>
</article>
}
}
</div>
}
else
{
<div class="video-box widget span4">
<h3 class="title"><span>#category.PostCategoryName</span></h3>
#{
int cati = 0;
var firstPost = category.Posts.OrderByDescending(x => x.PostDate).FirstOrDefault();
}
#if (firstPost != null)
{
<h4 class="smallnewstitle">#firstPost.PostTitle</h4>
<p>#(firstPost.PostSummary.Length > 100 ? firstPost.PostSummary.Substring(0, 100) : firstPost.PostSummary) </p>
<ul>
#foreach (var item in category.Posts.OrderByDescending(x => x.PostDate))
{
if (cati <= 3)
{
<li>
<a href="#" title="#item.PostTitle" rel="bookmark">
<img width="225" height="136" src="#Url.Content("~/Content/images/dummy/shutterstock_134257640-225x136.jpg")" alt="shutterstock_134257640" />
</a>
</li>
}
else
{
break;
}
cati++;
}
</ul>
}
</div>
}
if (i % 3 == 0 && i != 0)
{
#Html.Raw("</div>")
}
}
#{
db.Dispose();
}
Separate your concerns. You can see this project for start: http://www.codeproject.com/Tips/617361/Partial-View-in-ASP-NET-MVC
Controller
#using SosyalGundem.WebUI.DatabaseContext;
public ActionResult SomeAction()
{
var model = new CategoriesModel
{
NotDeletedCategories = db.PostCategories.Include("Posts").Where(x => !x.IsDeleted).ToList(),
DeletedCategories = db.PostCategories.Include("Posts").Where(x => x.IsDeleted).ToList()
};
return View(model);
}
Model
public class CategoriesModel
{
public List<PostCategories> NotDeletedCategories {get;set;}
public List<PostCategories> DeletedCategories {get;set;}
};
View
#model CategoriesModel
#Html.RenderPartial("DeletedCategories", Model.DeletedCategories)
#Html.RenderPartial("NotDeletedCategories", Model.NotDeletedCategories)
Hi Jinava,
I would suggest bind Model to the View,
Like,
public ActionResult CategoryRepeater()
{
var multiViewModel = new MultiViewModelModel
{
ModelForParialView1= new XYZ(),
ModelForParialView2= new PQR()
};
return View(model);
}
For the View
#model MultiViewModelModel
And then PAss the views with the MultiViewModelModel.ModelForParialView1 and MultiViewModelModel.ModelForParialView2
You can perform all the model operations on the view.
And at the controller level perform all the database operations and release the database connection there itself no need to get that on the view.
Hope this explanation helps you.