I am having problems persisting data from KO observableArray in a MVC Partialview...
I have a side navigation menu where one of the nodes is dynamically built using KOjs 'foreach', and this navigation menu should persist across the site. The menu is rendered ok on the first View page but when I navigate on other page (clicking on menu option or any way) the dynamic node is empty, although the observableArrays were fetched and loaded with the correct data.
It seems like the navigaition menu (which is a partial view) is not refreshing/reloading to render the menu nodes/options again.
Any help si much appreciated. TIA!
self.reports = ko.observableArray([]);
self.reportCategories = ko.observableArray([]);
self.getReports = function () {
App.Server.get("/.../reports/")
.then(function (vm) {
self.reports(vm.reports);
self.reportCategories(vm.categories);
});
};
self.init = function () {
self.getReports();
};
self.init();
<li>
<a class="level1" data-toggle="collapse" href="#report-submenu" aria-expanded="false" aria-controls="collapseExample">Reports</a>
<ul class="level1 collapse" id="report-submenu" data-bind="foreach: reportCategories">
<li>
<a class="level2 collapse" data-toggle="collapse" data-bind="text: label, attr: { href: '#' + value }"
aria-expanded="false" aria-controls="collapseExample"></a>
<ul class="level2 collapse" data-bind="foreach: reports, attr: { id: value }">
<li data-bind="if: category == $parent.categoryId">
<a class="level3" data-bind="text: menuName, attr: { href: reportName }"></a>
</li>
</ul>
</li>
Here's the other part of the code (a Nancy GET method):
Get["/"] = _ =>
{
var reportModel = new ReportModel();
var reports = reportService.GetList();
if (reports != null)
{
// Categories
reportModel.Categories = reports.Select(s => s.Category).Distinct().Select(c => new ReportCategoryModel()
{
CategoryId = c,
Label = c.TrimStart("Reports/".ToCharArray()),
Value = c.ToLower().Replace('/', '-')
}).ToList();
// Reports
reportModel.Reports = reports.Select(r => new ReportRecord()
{
MenuName = r.MenuName,
ReportName = r.ReportName,
Category = r.Category,
}).ToList();
}
return Response.AsJson(reportModel);
};
Related
I have a problem with a partial view. The first time when it is rendered everything is ok, but after that some data is loosed.
This is how my page should look: this is when the partial view is rendered the first time
but when I'm clicking on a category to check his subcategories, the image is null, it is not visible anymore. (only the name is visible)
This is my partial view:
#model IEnumerable<OnlineCarStore.Models.CategoriesVM>
<div class="container">
<div class="row">
#using (Html.BeginForm("SubCategories", "Product"))
{
<div class="list-group col-sm-3" style="width:280px;">
#{var selected = string.Empty;
if (#HttpContext.Current.Session["selectedCar"] == null)
{
selected = string.Empty;
}
else
{
selected = #HttpContext.Current.Session["selectedCar"].ToString();
}
foreach (var c in Model)
{
<a href="#Url.Action("SubCategories", "Product", new { selected = #selected, id = #c.ID, category = #c.CategoryName })" class="list-group-item">
<span> #c.CategoryName</span>
</a>
}
}
</div>
<div class="col-sm-9">
#foreach (var c in Model)
{
<div class="card-group" style="width:200px; display: inline-block">
<div class="card card">
<a href="#Url.Action("SubCategories", "Product", new { selected = #HttpContext.Current.Session["selectedCar"].ToString(), id = #c.ID, category = #c.CategoryName })" id="linkOnImg" class="card-group">
<img class="card-img-top center-block" src="#string.Format("../content/images/categories/{0}.jpg", #c.AtpID)" alt=#c.CategoryName style="padding-top: 5px">
<div class="card-text text-center">
<p class="category-card-title ">
<span class="text-muted">#c.CategoryName</span>
</p>
</div>
</a>
</div>
</div>
}
</div>
}
</div>
and this is the Subcategoris view, where the partial view is rendered second time:
<div class="container">
<div class="row">
#Html.Partial("/Views/Home/CategorieTypes.cshtml");
Here is the Product controller Subcategories method:
public ActionResult SubCategories(string selected, int id, string category)
{
List<CategoriesVM> listOfCategories = new List<CategoriesVM>();
var list = db.Categories.ToList();
var root = list.GenerateTree(c => c.ID, c => c.ParentId).ToList();
TreeItem<Categories> found = null;
var test = new TreeItem<Categories>();
foreach (var rootNode in root)
{
found = TreeGenerator.Find(rootNode, (n) => n.Item.ID == id);
if (found != default(TreeItem<Categories>))
{
test = found;
break;
}
}
foreach (var item in found.Children.ToList())
{
CategoriesVM categoryv = new CategoriesVM();
categoryv.ID = item.Item.ID;
categoryv.AtpID = item.Item.AtpID;
categoryv.Childrens = item.Children.ToList();
categoryv.CategoryName = item.Item.AtpName;//.Name;
listOfCategories.Add(categoryv);
}
SiteMaps.Current.CurrentNode.Title = selected + " " + category;
var tests = found.Children.ToList();
if (found.Children.ToList().Count == 0 )
{
return View("Index");
}
else
{
return View("SubCategories", listOfCategories);
}
}
I've checked in developer tool if the source for the image is correct, and although it is correct, the image is not showed:
Can you please help me in this problem? What I do wrong? Why the images don't appear after the first render of the partial view? Thanks in advance!
The path of the partial view is /Views/Home/CategorieTypes.cshtml and the path of the images is /Content/images/categories. In the partial view you are using ../content/images/categories/ as the path of the images which means that it will search for the path /Views/Content/Images/Categories which is invalid.
Remove the two dots in the src property and add a ~ so it will be like: ~/Content/Images/Categories/{img}.
or
Add one more ../ in order to go one level down to the directory like:
../../Content/Images/Categories/{img}
I have a True/False editor in my page doc type and I am using if to create the site navigation.
If topNavigation Checkbox is checked display item in the navigation
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
var root = Umbraco.TypedContentAtRoot().First();
var nodes = root.Children.Where(x => x.GetPropertyValue("topNavigation") != "True");
}
<ul class="nav navbar-nav">
#foreach (var page in nodes)
{
<p>#page.GetPropertyValue("topNavigation")</p>
<li class="#(page.IsAncestorOrSelf(Model.Content) ? "current" : null)">
#page.Name <span class="glyphicon glyphicon-chevron-down"></span>
</li>
}
</ul>
#*}*#
I can't seem to compare against a true value.
This shows everything -
var nodes = root.Children.Where(x => x.GetPropertyValue("topNavigation") != "True");
..and this show nothing
var nodes = root.Children.Where(x => x.GetPropertyValue("topNavigation") == "True");
Even though the checkboxes are checked.
You should able to use GetPropertyValue<bool>
var root = Umbraco.TypedContentAtRoot().First();
var nodes = root.Children.Where(x => x.GetPropertyValue<bool>("topNavigation"));
I'm trying to get data from database and populate different bootstrap dropdowns.
The table contains the following fields: id, ipAddress, hostName, recordNumber
The Model:
function myModel(){
var self = this;
self.id = ko.observable();
self.ipAddress = ko.observable();
self.hostName = ko.observable();
self.recordNumber = ko.observable();
}
The ViewModel
function myViewModel(){
var self = this;
self.ipAddresses = ko.observableArray();
self.hostNames = ko.observableArray();
self.recordNumbers = ko.observableArray();
self.selectedIpAddress = ko.observable("");
self.selectIpAddress = function (){
self.selectedIpAddress ();
}
}
var uri = 'api/items';
var array = [];
$.getJSON(uri)
.done(function (data) {
$.each(data, function (index, item) {
array.push(item);
self.ipAddresses(array.ipAddress);
self.hostNames(array.hostName);
self.recordNumbers(array.recordNumber);
});
});
The array contains well the data but I don't know how to access the different fields of the table, I tried this but it doesn't work:
self.ipAddresses(array.ipAddress);
self.hostNames(array.hostName);
self.recordNumbers(array.recordNumber);
Html code of one dropdown:
<div class="input-group">
<input type="text" class="form-control"data-bind="value:selectedIpAddress"
<div class="input-group-btn">
<button type="button" id="dropDownIpAddress" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" role="menu" data-bind="foreach: ipAddresses">
<li><a role="menuitem" href="#" data-bind="text: ipAddress, click: myViewModel.selectIpAddress"></a></li>
</ul>
</div>
</div>
JSFiddle
I am using knockout.js. I declare 2 model objects:
1)
var model =
{
products: ko.observableArray([])
}
2)
var customerModel =
{
cart: ko.observableArray([]),
filteredProducts: ko.observableArray([]),
currentView: ko.observable("list")
}
when the document is ready:
$(document).ready
(
function () {
getProducts();
}
);
it calls getProducts which sets the model.products observable array to have a single object:
var getProducts = function () {
model.products.removeAll();
model.products.push
(
{
Id: 1,
Name: "Product 1",
Description: "A nice product",
Price: 666.66,
Category: "Category 1"
}
)
}
i have a view that renders an ASP.NET partial view. the default customerModel.currentView is 'list' (as seen from the model object i declared):
<div data-bind="visible: customerModel.currentView() == 'list'">
#Html.Partial("ProductList")
</div>
in the partial view (ProductList.cshtml) is the following code:
<div data-bind="foreach: model.products()">
<span data-bind="text: $data.Description"></span>
<button data-bind="click: addToCart">Add to Cart</button>
</div>
clicking on the button invokes the addToCart function which adds a product to the cart and sets the view:
var addToCart = function (product) {
var cart = customerModel.cart;
cart().push
(
{
product: product,
count: 1
}
);
setView('cart');
}
setView is like this:
var setView = function (view) {
customerModel.currentView(view);
}
when set to 'cart', the following code renders a partial view:
<div data-bind="visible: customerModel.currentView() == 'cart'">
#Html.Partial("ProductCart")
</div>
now HERE is the kicker. ProductCart.cshtml looks like this:
<script>
var testCart = function () {
alert("There is " + customerModel.cart().length + " item incustomerModel.cart()");
}
</script>
<div data-bind="if: customerModel.cart().length == 0">There are no items in customerModel.cart( </div>
<button data-bind="click: testCart">Test Cart</button>
so guess what? the div that says "There are no items in customerModel" shows up because customerModel.cart().length == 0, however when i click the button the alert tells me that customerModel.cart().length is equal to 1.
It seems that you need to change cart().push to cart.push, as you are doing with model.products.
Thats how observableArrays work. See documentation.
When you call cart(), it returns a new array, with the values inside the observable. You are pushing your new value to that array, which is being lost in limbo.
You need to call the push method through the ko.observableArray API, this way it will notify all subscribers for that change, and the new value will be added to the observableArray.
I have a parent page (DistributionReview.aspx) that has a Deposit Date to select using DatePicker.
Just below I have two tabs(*DistributionByType* and DistibutionByStatus) that I want to load PartialViews. Here the parameter to the PartialView is DepositDate.
And I have a custom ViewModel called DistributionReviewModel that the parent page is implementing.
I am coming across articles that are directly loading static partial views(Ex:
http://www.kevgriffin.com/blog/index.php/2010/02/23/using-jquery-tabs-and-asp-net-mvc-partial-views-for-ajax-goodness/
). But I am looking for any code sample/articles by passing parameter?
Appreciate if anyone can share code samples to pass parameters and load the partialview both when the TabSelection is changed and and DepositDate is changed.
Thanks for your time.
Html Code:
<script type="text/javascript">
$(function () {
//tab
$("#divDistributionReview").tabs();
$("#fileDepositDate").datepicker(); //DateTime Picker
var depositDate = $("#fileDepositDate").val();
});
<div id="container" >
<% using (Html.BeginForm("frmDistributionReview", "DistibutionReview"))
{ %>
<div> Select a Date: <input type="text" id="fileDepositDate" name="datepicker" value='<%= ViewData["FileDepositDate"] %>' /></div>
<div id="divDistributionReview">
<ul>
<li>Distribution Type</li>
<li>Status</li>
</ul>
</div>
<%} %>
</div>
C# Code:
public ActionResult DistributionReview()
{
ViewData["FileDepositDate"] = DateTime.Now.ToShortDateString();
var view = View(ApplicationConstants.DistributionReviewViewName, new MegaLockbox.Web.ViewModels.DistributionByTypeViewModel(securityManager, distributionReviewDataAdapter, Convert.ToDateTime(ViewData["FileDepositDate"])));
return view;
}
public ActionResult DistributionByType(string id)
{
DateTime depositDate;
var view = new PartialViewResult();
if (DateTime.TryParse(id , out depositDate))
{
view = PartialView(ApplicationConstants.DistributionByTypeViewName, new MegaLockbox.Web.ViewModels.DistributionByTypeViewModel(securityManager, distributionReviewDataAdapter, depositDate));
}
return view;
}
public ActionResult DistributionByStatus(string id)
{
DateTime depositDate;
var view = new PartialViewResult();
if(DateTime.TryParse(id, out depositDate) )
{
view = PartialView(ApplicationConstants.DistributionByStatusViewName, new MegaLockbox.Web.ViewModels.DistributionByTypeViewModel(securityManager, distributionReviewDataAdapter, depositDate));
}
return view;
}
here you have nice guide how to do this:
http://ericdotnet.wordpress.com/2009/03/17/jquery-ui-tabs-and-aspnet-mvc/
if you have any questions.. let us know:)
PS you can download the example, and play with it
Html for tab headers
<li><a onclick="LoadTabData('type')" href="/DistributionReview/DistributionByType">Distribution Type</a></li>
<li><a onclick="LoadTabData('status')" href="/DistributionReview/DistributionByStatus">Status</a></li>
Jquery function
function LoadTabData(type){
if(type='type')
$.post("YourController/DistributionByType", { id: $("#fileDepositDate").val()},
function(data) {
$(#"yourByTypeTabDiv").html(data);
});
}else{
$.post("YourController/DistributionByStatus", { id: $("#fileDepositDate").val()},
function(data) {
$(#"yourByStatusTabDiv").html(data);
});
}
Also this will work.
<div id="tabs">
<ul>
<li>Tab 1</li>
<li>Tab 2</li>
<li>Tab 3</li>
</ul>
<div id="tab-1">
#Html.Partial("_PartialViewForTab1", Model)
</div>
<div id="tab-2">
#Html.Partial("_PartialViewForTab2", Model)
</div>
<div id="tab-3">
#Html.Partial("_PartialViewForTab3", Model)
</div>
</div>