Composite view with collapsible list view - jquery-mobile

I am trying to render a composite view with the following template but I do not have a clue on how to accomplish it. The main idea is that each collapsible is a category with its items (something like a treeview). A category may or may not have items
<div data-role="collapsible">
<h2>{{Category}}</h2>
<ul id="Items" data-role="listview" data-inset="true">
</ul>
</div>
The composite view has attributes:
attributes: function() {
return {
"data-role": "collapsible-set",
"data-theme" : "b",
"data-content-theme" : "a"
};
},

Take a look on the blog post I wrote on the subject: http://davidsulc.com/blog/2013/02/03/tutorial-nested-views-using-backbone-marionettes-compositeview/
Also, Derick's blog post on the subject could be of interest: http://lostechies.com/derickbailey/2012/04/05/composite-views-tree-structures-tables-and-more/

Related

Sitefinity Custom Fields for list widgets and how to use them in MVC view templates

I've added a Custom Field to the List Widget in Sitefinity 8.1, it's Type is Related data and it's Data type is Pages. The field name is LinkedPageUrl.
Works perfectly in the back end allowing me to select a page from system and store it against that particular List Item.
I can't find any place in Sitefinity's documentation that explains how I would programmatically use this field in a MVC based List.SimpleList.cshtml view template that I'm customizing.
I've seen this being used in the News widget where there is an associated Image for each News Article:
<img src="#Html.Raw(item.Fields.RelatedImg.Fields.MediaUrl)" class="img-responsive" />
But I don't get close to this because I don't have the slightest idea where to begin... What's the model structure, syntax, etc.
My objective is to change each list item rendered out into an anchor and the anchor should make use of this Related Data field's URL for it's Href property.
EDIT:
You can do something like this in the widget template:
#foreach (var item in Model.Items)
{
<h3 #Html.InlineEditingAttributes(Model.ProviderName, Model.ContentType.FullName, (Guid)item.Fields.Id)
#Html.InlineEditingFieldAttributes("Title", "ShortText")>
#item.Fields.Title
</h3>
<ul>
#foreach (var listItem in ((ListViewModel)item).ListItemViewModel.Items)
{
<li #Html.InlineEditingAttributes(Model.ProviderName, ((ListViewModel)item).ListItemViewModel.ContentType.FullName, (Guid)listItem.Fields.Id)>
<div #Html.InlineEditingFieldAttributes("Title", "ShortText")>
#listItem.Fields.Title
</div>
<div class="sfMultiRelatedItmsWrp">
<h2 class="sfrelatedItmTitle">Related pages</h2>
#foreach (var link in listItem.Fields.LinkedPageUrl)
{
var node = PageManager.GetManager().GetPageNode(link.Fields.Id);
var url = PageExtesnsions.GetFullUrl(node);
<div>#link.Fields.Title - #url</div>
}
</div>
</li>
}
</ul>
}
This is given that you selected that multiple pages can be selected per list item.
EDIT: Make sure to include the following namespaces
#model Telerik.Sitefinity.Frontend.Mvc.Models.ContentListViewModel
#using Telerik.Sitefinity.Frontend.Lists.Mvc.Models;
#using Telerik.Sitefinity.Frontend.Mvc.Helpers;
#using Telerik.Sitefinity.Modules.Pages;
EDIT2: If the custom field allows for only 1 page to be selected then it should look like this:
<div class="#Model.CssClass">
#foreach (var item in Model.Items)
{
<h3 #Html.InlineEditingAttributes(Model.ProviderName, Model.ContentType.FullName, (Guid)item.Fields.Id)
#Html.InlineEditingFieldAttributes("Title", "ShortText")>
#item.Fields.Title
</h3>
<ul>
#foreach (var listItem in ((ListViewModel)item).ListItemViewModel.Items)
{
<li #Html.InlineEditingAttributes(Model.ProviderName, ((ListViewModel)item).ListItemViewModel.ContentType.FullName, (Guid)listItem.Fields.Id)>
<div #Html.InlineEditingFieldAttributes("Title", "ShortText")>
#listItem.Fields.Title
</div>
<div class="sfMultiRelatedItmsWrp">
<h2 class="sfrelatedItmTitle">Related pages</h2>
#{
var node = PageManager.GetManager().GetPageNode(listItem.Fields.LinkedPageUrl.Fields.Id);
var url = PageExtesnsions.GetFullUrl(node);
}
<div>#listItem.Fields.Title - #url</div>
</div>
</li>
}
</ul>
}
A good starting point is this article

Update a partial view from another partial view in ASP.NET MVC without updating all the views

I have two partial views displaying, for the left one, the menu, and for the right one, the content.
When I click on "Link 1", I want to switch the "Content" area from the partial view "PartialViewContent1" to "PartialViewContent2".
In terms of code, I actually manage to do this :
File Index.vbhtml
<body>
<article>
<section>
<p>#Html.Action("Menu", "Menu")</p>
</section>
</article>
<aside>
#Select Case Convert.ToString(Model)
Case "Menu2"
#Html.Action("PartialViewContent2", "PartialViewContent2")
Case "Menu3"
#Html.Action("PartialViewContent3", "PartialViewContent3")
Case Else
#Html.Action("PartialViewContent1", "PartialViewContent1")
End Select
</aside>
File PartialViewMenu.vbhtml
<ul>
<li>
#Html.ActionLink("Link 1", "Link1", "Home")
</li>
<li>
#Html.ActionLink("Link 2", "Link2", "Home")
</li>
<li>
#Html.ActionLink("Link 3", "Link3", "Home")
</li>
With this architecture, every view (and partial view displayed) is refreshed.
I'm afraid this behavior not ergonomic and not very efficient in terms of performance. Is there a method to update the Content and not the menu (or the rest of the view if there is a footer or a header) ?
I finally found how to do this.
A simple jQuery code using Ajax does the trick :
$(function() {
$('#link1').click(function(){
$.ajax({
url: this.href,
dataType: "script",
success: function(result) {
$("#container").html(result);
}
});
});
e.preventDefault();
return false;
});
});

How do I correctly render jQuery Mobile Tab widget items using KnockoutJS?

jsFiddle at http://jsfiddle.net/nAgfQ/2/ (See top of HTML section for explanation and workaround.)
Scenario
I'm using jQuery Mobile (1.4.2) and KnockoutJS (3.1.0) to build a very straightforward single-page tab-based web app for displaying data to business users.
Code
Here's the JS:
$(function () {
var Tab = function (Title, TabID) {
var self = this;
self.Title = ko.observable(Title);
self.TabID = ko.observable(TabID);
self.TabHref = ko.computed(function () {
return '#' + self.TabID();
});
};
function DashboardViewModel() {
var self = this;
self.Title = ko.observable();
self.DashboardID = ko.observable();
self.tabs = ko.observableArray([
new Tab("Tab 1", "tabs-1", []),
new Tab("Tab 2", "tabs-2", [])]);
self.refreshTabs = function () {
$('#tabs').tabs("refresh").tabs("option", "active", 0);
//Added to callback to convert navbar div into jQuery Mobile Navbar
$('#dashboard_navbar').navbar();
};
}
dvm = new DashboardViewModel();
ko.applyBindings(dvm);
});
Here's the body content of the page:
<body>
<div data-role="page" id="page-1">
<div data-role="header">
<h1>jQuery Mobile Tabs Test</h1>
</div>
<div data-role="content">
<div data-role="tabs" id="tabs">
<div data-role="navbar" id="dashboard_navbar">
<ul data-bind="template { foreach : tabs }">
<li><a data-bind="attr : { href: TabHref } , text: Title" data-ajax="false"></a>
</li>
</ul>
</div>
<div data-bind=" template { foreach :tabs, afterRender: refreshTabs}">
<div data-bind="attr : { id: TabID }" class="ui-body-d ui-content">
<h4 data-bind="text: Title" />
</div>
</div>
</div>
</div>
</div></body>
Issue
When you have a Tab widget in jQuery Mobile, you are encouraged to declare an element to have a data-role attribute set to "navbar."
When jQuery renders the page, it looks for the first ul child element of the selected element, and reads the number of li elements underneath that ul.
It then uses this to add a class with the naming schema ul-grid-N, where N is the letter of the alphabet corresponding to the number of elements found minus 1 (i.e. ul-grid-a for 2 elements, ul-grid-b for 3, etc.) If there is only one element, it uses a special class ul-grid-solo.
However, when you use KnockoutJS to load a set of bound tabs, you just supply a single li element as a template underneath a foreach binding. jQuery Mobile only sees the 1 element and so adds the ul-grid-solo class and then the navbar li elements end up being rendered as stacked on top of one another instead of horizontally aligned.
Workaround
The solution I have so far is to remove the "navbar" data-role and instead use KnockoutJS's afterRender callback to convert the element into a navbar once all the bound tabs have been inserted. (See the *refreshTab*s function in the DashboardViewModel object.)
This works, but is less than ideal since it forces the ViewModel to know something about the View which is an MVVM no-no.
Questions
Can I tell jQuery Mobile to hold off applying the grid class to the navbar until after the bindings have been applied? I poked around its API but didn't see anything particularly useful.
Is there something I can do with Knockout's custom bindings? Again, trying not to inject any DOM manipulation into the ViewModel.
In general, any other workarounds, comments on the code, etc. would be appreciated.
Working with knockout and jQuery Mobile for a while, I can confirm that they simply do not play nice together. Our team has a list of re-usable knockout custom bindings just for working with jQuery mobile, because they're such a pain.
You could essentially wrap up the below workaround, or your own, into a custom binding that you'd use in place of foreach. Or subscribe to changes to the array of navbar items and update there.
Workaround based on your jsFiddle, trying to recreate the navbar, you have to also rip out the dynamic markup that jQuery mobile puts into the elements. Try adding this (source):
navbar.find("*").andSelf().each(function(){
$(this).removeClass(function(i, cn){
var matches = cn.match (/ui-[\w\-]+/g) || [];
return (matches.join (' '));
});
if ($(this).attr("class") == "") {
$(this).removeAttr("class");
}
});
JSFiddle

looping collection in knockoutjs in to ul

I have json collection like this
0: {FamilyDetailId:1, Name:Daniel, GenderId:1, Dob:/Date(1375554600000)/,…}
1: {FamilyDetailId:3, Name:Askar, GenderId:1, Dob:/Date(1375554600000)/,…}
var employeeFamilyModel;
function bindModel(data) {
employeeFamilyModel = ko.mapping.fromJS(data);
ko.applyBindings(employeeFamilyModel, document.getElementById("collapseOne"));
}
function loadData (employeeGuid) {
$.ajax({
url: "/HumanResource/EmployeeProfile/EmployeeProfileFamily?employeeGuid=" + employeeGuid,
type: 'post',
contentType: 'application/json',
success: function (result) {
bindModel(result);
}
});
};
view
<ul data-bind="foreach: employeeFamilyModel">
<li data-bind="text: Name"></li>
</ul>
my problems is to display each collection in new UL list
ex :
<ul>
<li> Name: Daniel </li>
</ul>
<ul>
<li> Name: Askar </li>
</ul>
how to achieve this in knockoutjs ?
Everything you have inside ko foreach block will be repeated like foreach loop. And everything you have in ko text will just output without any element around.
<!-- ko foreach: employeeFamilyModel -->
<ul>
<li>Name: <!--ko text: Name--><!--/ko--></li>
</ul>
<!-- /ko -->
To elaborate, you simply need to move your foreach binding 'up' a level, so that the <ul> is included for each data element in your view model.
JS:
employeeFamily = ko.observableArray([{Name: 'John Doe', Owner: 'John'},
{Name: 'Jane Doe', Owner: 'Jane'}])
ko.applyBindings(employeeFamily, document.getElementById("collapseOne"));
Html:
<div id = 'collapseOne' data-bind="foreach: employeeFamily">
<label data-bind="text: 'This list belongs to ' + $data.Owner"></label>
<ul>
<li data-bind="text: $data.Name"></li>
</ul>
</div>
Result:
This list belongs to John
John Doe
This list belongs to Jane
Jane Doe
I added the owner attribute to emphasize that each <ul> was bound to a different $data element. See JSFiddle example

Asp.Net MVC load a partial view using ajax from a JQuery UI tab

I have several action methods on my controller that return a partial view (ascx), and I want these partial views to be rendered when clicking on the different JQuery UI tabs.
The tabs are defined like this:
<div id="tabs">
<li>First tab</li>
<li><%= Html.ActionLink("General", "General", new {id=Model.Id}) %></li>
<li><%= Html.ActionLink("Details", "Details", new {id=Model.Id}) %></li>
<div id="FirstTab">
...
</div>
</div>
This renders the tabs fine, the first tab (with static content) is displayed correctly, but when I click the other tabs, nothing happens.
If instead of returning a partial view from the action methods I just return plain content, it renders the content just fine and the tabs work perfectly.
Any idea of what am I doing wrong?
Thanks
Hey, I've done the same thing recently. I simplified in order to be more clear:
The html:
<div class="tabs">
<ul>
<li>
<a onclick="TabItemClicked(this,<%=Url.Action("General", new {id=Model.Id}) %>))" href="#fragment1">
<span>General</span>
</a>
</li>
<li>
<a onclick="TabItemClicked(this,<%= Html.ActionLink("Details", new {id=Model.Id}) %>))" href="#fragment2">
<span>Details</span>
</a>
</li>
</ul>
<div id="fragment1"></div>
<div id="fragment2"></div>
</div>
and the JQuery code:
function TabItemClicked(a, action) {
var container = $(a).parents('div.tabs');
var resultDiv = $($(a).attr('href'), container);
$.ajax({
type: "POST",
url: action,
data: {},
success: function(response) {
resultDiv.html('');
resultDiv.html(response);
}
});
}

Resources