Update horizontal link list with jQuery Mobile and Knockout JS - jquery-mobile

I'm using jQuery mobile and Knockout JS (latest versions of both).
I cannot seem to style a horizontal list after knockout updates the dom.
<h2>Dynamic</h2>
<div id="dynamicControlgroup" data-role="controlgroup" data-type="horizontal" data-mini="true" data-bind="foreach: Labels">
</div>
<h2>Static</h2>
<div id="staticControlgroup" data-role="controlgroup" data-type="horizontal" data-mini="true">
3G
SD
HD
HD+
/div>
The "Static" looks good, but the "dynamic" is not styled by jQuery mobile. I've tried several methods of trying to make this work, and I am missing something... after knockout runs, I do:
$("#dynamicControlgroup").trigger("create")
$("#dynamicControlgroup").children('a').buttonMarkup({ inline: true,mini: true,corners: true, type: "horizontal"});
But here is what it looks like:
Thoughts?

After appending new items, use the below code.
$('[data-role="controlgroup"]').controlgroup().trigger('create');
Note: Creating completely new controlgroup doesn't get enhanced corners dynamically. However, appending new items into existing controlgroup corners get enhanced. This problem can be solved by adding ui-first-child and ui-last-child classes.
$('[data-role="controlgroup"] a').first().addClass('ui-first-child');
$('[data-role="controlgroup"] a').last().addClass('ui-last-child');
Demo

Turns out with Knockout you need to remove the controlgroup from the div so you dont get the "empty wrapper". So the dynamic code looks like:
<h2>Dynamic</h2>
<div id="dynamicControlgroup" data-type="horizontal" data-mini="true" data-bind="foreach: Labels">
</div>
and then on page load, you can call
$('#dynamicControlgroup').controlgroup().trigger('create');
$('#dynamicControlgroup a').first().addClass('ui-first-child');
$('#dynamicControlgroup a').last().addClass('ui-last-child');
and this works. Thanks to Omar for the help on the first/last rounded classes tip!

Related

jquery Mobile - Auto Divider

I'm using the jquery Mobile AutoDivider for a web project of mine and it works great in IE8, but for some reason in Chrome it's not generating the headers for me.
My question is: How exactly does the AutoDivider determine what to make a 'divider'? Is is just the first item within your <li></li>?
Here's my basic HTML structure (it's ultimately placed in a ASP.Net Repeater:
<ul data-role="listview" data-autodividers="true">
<li>
<img src="mySource.jpg" alt="" />
<h3>John Doe</h3>
<p><strong>Company Name Here</strong></p>
<p>User Address</p>
<p class="ui-li-aside">
<strong style="display: none;"><!-- This is what seems to make the headers in IE, placing this right here: -->
Last Name of Employee</strong>
</p>
</li>
</ul>
see the docu http://jquerymobile.com/demos/1.2.0/docs/lists/docs-lists.html
Autodividers
A listview can be configured to automatically generate dividers for its items. This is
done by adding a data-autodividers="true" attribute to any listview.
By default, the text used to create dividers is the uppercased first letter of the
item's text. Alternatively you can specify divider text by setting the > autodividersSelector option on the listview programmatically.

Show/Hide multiple, layered jQuery UI widgets

I'm new to all this so please bear with me.
I've been using some jQuery UI widgets and I'm wanting to create category (adults) radio buttons with their own set of subcategories (children) that only appear when the appropriate adult is selected.
Here's the code I have so far: http://jsfiddle.net/99azd/
The problem is only the formatting of the initial set of children work, the others show up as plain checkboxes. I think it has something to do with the div id="format" but I'm not sure.
<div style="display: none;" id="Adult1Children">
<div id="format">
<input type="checkbox" id="child1" value="child1"/><label for="child1">child1</label>
<input type="checkbox" id="child2" value="child2"/><label for="child2">child2</label>
</div>
</div>
Got some help from the IRC channel - here's the fixed code:
http://jsfiddle.net/w6qFC/
I had a duplicated id "format" so it only ran the first one. All I had to do was change the id to a class instead and then in the js change from #format to .format. Simple.
$( ".format" ).buttonset();
and
<div class="format">

Close button on dialog returns to the wrong page

Here's a very simple fiddle:
http://jsfiddle.net/mmSKj/
If you click the "presets" button in the header bar, it opens a dialog. If you click the "close" button on the dialog, instead of going back to the page it came from, it goes to the last page (excluding the dialog itself) on the page (the one with the content This is another page). How come? Is there a way to fix the automatically inserted back button so it behaves itself properly (like the "home" button I included in the dialog) or, failing that, is there a way to remove the close button.
<div data-role="page" id="index">
<header data-role="header">
<h1>Index</h1>
Presets
</header>
<article data-role="content">
<div>This is the main page</div>
</article>
</div>
<div data-role="page">
This is another page
</div>
<div data-role="page" id="presets">
<header data-role="header">
<h1>Presets</h1>
</header>
<div data-role="content">
This is a dialog!
</div>
</div>
Update
As Taifun pointed out, the problem is the lack of an id on the page. Adding an id fixes my first fiddle. However, my real situation is a little more complicated, as shown in this fiddle:
http://jsfiddle.net/mmSKj/2/
Here I am actually creating pages dynamically using knockout, and I assign IDs to those pages via data binding, but, it seems, those ids are not recognized by jQuery Mobile for some reason. If you look with Firebug, you can see that the ids are correctly added to the attributes of the pages, but when you close the dialog, you end up on page 3 rather than the original page.
Update 2
Simple fix, I just added a dummy id to the bit of html that knockout is going to use as a template:
<!-- ko foreach: pages -->
<div data-role="page" data-bind="attr: {id: name}" id="dummy">
This is <span data-bind="text:name"></span>
</div>
<!-- /ko -->
See here.
The dummy id is replaced by knockout, so links to that page work correctly and jQuery mobile seems to be happy!
add an id to your other page
<div data-role="page" id="anotherpage">
This is another page
</div>
then it will work, see jsfiddle
coming back to another solution, because you mentioned: is there a way to remove the close button? Yes, just add this style, see also this answer...
<style>
.ui-dialog .ui-header a[data-icon=delete] {
display: none;
}
</style>
and another jsfiddle to demonstrate that

Knockout, JQMobile, and generating a collapsible-set doesn't quite seem to work right

I've checked out a number of samples, but none are quite the same as what I'm trying to do.
What I've got works, mostly, but it doesn't quite work right.
Here's a fiddle to illustrate the issue.
http://jsfiddle.net/5yA6G/4/
Notice that the top set works fine, but it's statically defined.
The bottom set (Tom, steve, bob) "work" basically, but the header element ends up both in the collapsible header AND in the portion of the collapsible that gets hidden.
Seems like I must be doing something wrong, but I haven't been able to figure out what.
Any ideas?
Just for reference and for anyone else running into this problem, it turns out to be at least somewhat obvious in hindsight.
Knockout's built in "anonymous" templating works great in many cases, but with JQMobile, it can be a tad quirky.
That's because JQMobile will adjust the content of the anonymous template when the page loads, just as it does with all the other content.
Then, later, when you use knockout's ApplyBindings function, knockout will add the applicable elements, just as it should. As many posts and answers have hinted at, you then MUST call collapsible() on the newly created elements, via something like this.
$("div[data-role='collapsible']").collapsible({refresh: true});
No problem there. HOWEVER, if JQM has already applied formatting, then the anonymous template has already been "rendered" by JQM, so rendering it again by calling collapsible causing all sorts of funky results, including doubled heading, nested collapsibles, etc.
The solution for me was to use Knockout's "Named Template" feature, and just put the template to render the collapsible elements into a tag, like this:
<script type="text/html" id="alarm-template">
<div data-role="collapsible" data-collapsed="true" data-collapsed-icon="arrow-d" data-expanded-icon="arrow-u" data-enhance="false">
<h3 data-bind="text:name"></h3>
<p>The content here</p>
<p data-bind="text: name"></p>
</div>
</script>
Doing this prevents JQM from "rendering" the template elements when the page loads, so they'll be rendered properly when they're actually generated.
EDIT: The above works fine for collapsibles NOT in a collapsible-set, but, if they're in a set, I've found the styling of the elements (particularly, the corner rounding to indicate belonging to a set) doesn't work right.
From what I can tell, there are 2 problems:
The first is that just triggering "Create" doesn't actually refresh the styling of all the collapsibles in the set. to do that you have to do...
$("div[data-role='collapsible-set']").collapsibleset('refresh');
But, there's a worse problem. JQM "marks" the last item in the set as the "last item". That fact then gets used to determine how to style the last item as it's being expanded/collapsed.
Since Knockout doesn't actually rebuild the entire set (for speed), each time you call the refresh method, JQM dutifully marks the last item as "last", but never removes the marks on previous items. As a result, if you start from an empty list, EVERY item ends up being marked "last" and the styling fails because of this.
I've detailed the fix for that at github in an issue report.
https://github.com/jquery/jquery-mobile/issues/4645
I actually found a much easier way to do this:
Set up your foreach binding as you normally would for me it looked like this
<div data-bind="foreach: promotions">
<h3 data-bind="text: Title"></h3>
<p>Creator:<span data-bind="text: Creator"></span></p>
<p>Effective Date:<span data-bind="text: EffectiveDate"></span></p>
<span data-bind="text: Description"></span>
<a data-bind="text: ButtonText, attr: {href: ButtonLink}"></a>
Wrap that in a div with class="collapsible like so
<div data-role="collapsible-set" data-bind="foreach: promotions">
<div class="collapsible">
<h3 data-bind="text: Title"></h3>
<p>Creator:<span data-bind="text: Creator"></span></p>
<p>Effective Date:<span data-bind="text: EffectiveDate"></span></p>
<span data-bind="text: Description"></span>
<a data-bind="text: ButtonText, attr: {href: ButtonLink}"></a>
Apply the collapsible widget via jquery mobile after you do your binding like so:
$(document).ready(function () {
ko.mapping.fromJS(data, dataMappingOptions, PromotionViewModel.promotions);
ko.applyBindings(PromotionViewModel);
$('.collapsible').collapsible();
});
For a collapsible set the same idea can be applied just set the class="collapsible-set" on your foreach div. Hope this helps

How are themes applied to jquery mobile plugins?

Currently I'm working on building my first plug-in for JQuery Mobile. I've managed to make the basic code work, however I'm struggling to understand how the themeing is applied. After spending 2 hours of googling to no avail, I'm at a bit of a loss for where to look next.
Essentially:
How do I build my plug-in to pull styles from JQM's themes? Is there a reference of where/how the themes are applied at the mechanical level I can use? The plugin I'm building is a somewhat customized progress bar display and I'd like the color and borders of the bar to use the theme.
jQuery Mobile themes are based on a standard set of classes that relate to visual characteristics. For example the .ui-btn class should be added to buttons and the .ui-icon class should be added to icons to follow the jQuery Mobile theming convention. Another example is how you can add .ui-icon-shadow class to an element with the .ui-icon class and it will be given a shadow.
Here is an example jQuery Mobile button:
<a href="../../" data-icon="home" data-iconpos="notext" data-direction="reverse" class="ui-btn-left ui-btn ui-shadow ui-btn-corner-all ui-btn-icon-notext ui-btn-up-f" data-corners="true" data-shadow="true" data-iconshadow="true" data-wrapperels="span" data-theme="f" title="Home">
<span class="ui-btn-inner ui-btn-corner-all">
<span class="ui-btn-text">Home</span>
<span class="ui-icon ui-icon-home ui-icon-shadow"> </span>
</span>
</a>
So you can either add these classes to your HTML markup manually, or you can create widgets using the functions that jQuery Mobile exposes:
$('<ul data-role="listview"><li>FOOBAR</li></ul>').listview();
Source: http://jquerymobile.com/demos/1.1.0/docs/lists/lists-methods.html
There are functions like listview() for all the widgets and most of them can take-in options so you can set whether the widget gets box-shadow or whatever else.
Update
To have your widget inherit the closest theme you can do something like this:
//assuming `this` is the widget element
var theme = $(this).closest('[data-theme]').attr('data-theme') || 'a';

Resources