jQuery add/remove css class on selected radio - jquery-ui

I've read a few solutions on here, but my problem differs enough where those will not work. Basically if the radio button is checked, add a css class to the parent div. If the radio is not checked, remove the css class. Sounds simple?
I have more than one radio button group, so in other words, there will be multiple radio buttons selected at a time. Each radio button group also is on different parts of the page seperated by other html.
Here is what I came up with:
$(document).ready(function () {
$('input').click(function () {
if ($('input:not(:checked)')) {
$('div').removeClass('style1');
}
if ($('input').is(':checked')) {
$(this).parent().addClass('style1');
}
});
});
I think I'm on the right path with the input:not(:checked), but on the next line it removes style1 from all div elements instead of checking if other divs radio button child is checked.
I guess what I'm asking is how do I write a script that when a radio button is clicked, add a css class to the parent and then find all div tags on the page that have a child of input. If the divs child input is not checked, remove the css class. So if a div has a child input element and it is checked, don't remove the css class from the inputs div.
I hope that makes sense.

Why not using the following: http://jsfiddle.net/Q2bzT/
$(document).ready(function () {
$('input').click(function () {
$('input:not(:checked)').parent().removeClass("style1");
$('input:checked').parent().addClass("style1");
});
});​

Assuming your radio buttons utilize the name property to properly group them, when one changes, you can find the radios with the same name, and remove the class, then add the class to the one that was activated.
Try it out: http://jsfiddle.net/U2AAQ/
$(document).ready(function () {
$(':radio').change(function () {
$(':radio[name=' + this.name + ']').parent().removeClass('style1');
$(this).parent().addClass('style1');
});
});​

I had a similar issue but I needed to target the radio button's label instead of a parent div element. I also needed to make sure the other related label elements did not have the class.
Here's what I came up with based on #user113716's answer:
HTML
MVC code removed so there is only HTML in this example
<ol class="list-group">
<li class="list-group-item">
<div class="input-group">
<label for="choice_ChoiceId" class="form-control">ChoiceDescription</label>
<span class="input-group-addon">
<input type="radio" id="choice_ChoiceId" value="choiceValue" name="choiceName" required />
</span>
</div>
</li>
</ol>
jQuery
$(':radio').click(function () {
var _groupName = $(this).attr('name'),
_radioId = $(this).attr('id'),
_radioGroup = $(':radio[name="' + _groupName + '"]');
//remove class from all labels for this group of radio buttons
_radioGroup.each(function(){
$('label[for*="' + $(this).attr('id') + '"]').removeClass('style1');
});
//add the class to the selected radio button
$('label[for*="' + _radioId + '"]').addClass('style1');
});

JavaScript
'use strict';
var o = 'label.input-check, label.input-radio';
$(o).find('input').change(function () {
$(o).find('input').filter('input[name="' + (this).name + '"]').each(function () {
$(this).parent(o).toggleClass('checked', (this).checked);
});
}).trigger('change');
Demo: http://jsfiddle.net/3uwp9c2n/
Just optimize if you need.

Related

Replaced div is not working Jquery Mobile

Basically I replaced the div in the content as soon as I click "Delete" on the Setting menu above. Well it does changes from collapsible set into checkbox with footer below containing two buttons. The buttons are delete and cancel but I can't perform anything with those buttons. For example, If Cancel clicked it should pop the alert popup (For the sake of testing). Please help..
<div data-role="content">
Tambah Katagori
<div id="Outcome" data-role="collapsibleset" data-theme="a" data-content-theme="a" data-collapsed-icon="arrow-r" data-expanded-icon="arrow-d"></div>
</div>
$("#Delete").click(function(){
$("#Outcome").replaceWith('<form><fieldset data-role="controlgroup" id="OutcometoDelete">');
db.transaction (function (transaction)
{
var sql = "SELECT * FROM KatagoriPengeluaran";
transaction.executeSql (sql,[],
function (transaction, result)
{
if (result.rows.length)
{
for(var i = 0; i< result.rows.length; i++ ) {
All2 =result.rows.item(i);
element = $(' <input type="checkbox" name="'+All2.Katagori+'" id="'+All2.Katagori+'"><label for="'+All2.Katagori+'">'+All2.Katagori+'</label>').appendTo($('#OutcometoDelete'));
}
All2 =result.rows.item((result.rows.length-1));
$('#'+All2.Katagori).append('</form></fieldset>');
$("#OutcometoDelete").append('<div id="someFooter" data-role="footer" data-position="fixed"><div id ="navbarFooter" data-role="navbar"><ul><li><a data-role="button" href="#popUpDelete">Delete</a></li><li><a data-role="button" href="index.html#Pengeluaran" data-ajax="false" id="cancelDelete" >Cancel</a></li></ul></div></div>');
$("#OutcometoDelete").trigger('create');
$("#someFooter").trigger('pagecreate');
$('#navbarFooter').trigger('pagecreate');
}
else
{
alert ("Retrieval Error");
}
}, error);
});
});
$("#cancelDelete").click(function(){
alert("oi");
});
This is because your way of event binding will not work for future elements. You can't just bind click event and expect it will work in the future, event(s) must be bind to something inside the DOM.
So this code will not work:
$("#cancelDelete").click(function(){
alert("oi");
});
On the other hand this code will work:
$(document).on('click',"#cancelDelete",function(){
alert("oi");
});
Second code will work because event is bind to document and it will propagate as soon as needed element is part of the DOM and appropriate event is trigger on it. This is also called delegated event binding.

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

jQueryMobile Change listview's item attributes dynamically

I want to change dynamically (click event) a data-theme of a list item in a jQueryMobile listview. Firebug shows me that the change is performed but the list is not refreshed. (If I add elements it works, but with attribute changes the list won't be refreshed.) For example I want to change the data-theme from c to f when the item is clicked.
I tried everything I read in this forum, from trigger('mouseout') over trigger('create') on parents to refreshing the whole page, but no effect at all, so I guess I am blind to see something obvious. Maybe somebody can give me a hint... :)
<script>
function fillList() {
var li = '<li data-theme="c">List item</li>';
$("#alist").empty().append(li).promise().done(function () {
$(this).off("click").on("click", ".info", function (e) {
e.stopImmediatePropagation();
e.preventDefault();
var theLiElem = $(this).closest('li');
theLiElem.attr('data-theme','f').trigger('mouseout');
theLiElem.trigger("create");
});
$(this).listview("refresh");
});
}
$(document).on("pageinit", "#info-page", function () {
fillList();
});
</script>
<div data-role="page" id="info-page">
<div data-role="content">
<ul data-role="listview" id="alist" data-inset="true">
</ul>
</div>
</div>
Kind regards,
Steve

Knockout checked binding not updating if radio button is deleted

I have a page with a set of radio buttons that is dynamically created by knockout based on the selection of a drop down on the page. This is all working fine but the problem I have is that the "checked" binding on the radio buttons does not seem to be cleared if the radio button is removed due to a change of the drop down. This leaves me with a ViewModel with a value for "checked" when in fact nothing on the view is checked (or at least nothing that can be seen).
What I would expect to happen is that once the radio button is removed the checked binding would go back to being null but I can only assume the binding does not get updated if the radio button is removed from the DOM.
You can see this happening on jsfiddle - basically if you select a radio button and then change the drop down the selected value will still refer to the now removed (and therefore unchecked) radio button.
HTML:
<ul data-bind='foreach: availableChildren'>
<li>
<label>
<input type="radio" name="children" data-bind="checked: $root.selectedChild, value: id" /><span data-bind="text: name"></span>
</label>
</li>
ViewModel:
var ViewModel = function (settings) {
var availableParents = ko.observableArray(settings.parents),
selectedParent = ko.observable(),
availableChildren = ko.computed(function () {
if (!selectedParent()) {
return null;
}
return selectedParent().children;
}),
selectedChild = ko.observable();
return {
availableParents: availableParents,
selectedParent: selectedParent,
availableChildren: availableChildren,
selectedChild: selectedChild,
};
};
Is there anyway to get this to work as I would expect or is this just something that has been missed from Knockout?
I added this snippet to your viewmodel to get the behaviour you wanted:
// create internal computed
ko.computed(function() {
// add dependency to selectedParent
var s = selectedParent();
// reset selectedChild
selectedChild('');
});
Your updated fiddle: http://jsfiddle.net/danne567/avbU7/2/

Jquery-Mobile: How to add the data dynamically to the select menu based on the text box value

I am new to jquery mobile. In my UI, one text box and one select menu are there. Initially select menu is empty.If the textbox value is more than 1 then some data is added to the select menu otherwise select menu is empty. For this, i am calling the function at the onchange of select menu but it is not working. Please can anybody help me.
Edit:
Ex:
$('#Goal_Time').bind( "focus", function(event, ui)
{
if(Goal_WeightVar.val() > 0)
{
Goal_WtVar = Math.abs(weightVar.val() - Goal_WeightVar.val());
Min_DurationVar = Math.round(Goal_WtVar * 2.2);
for(var i=0;i<10;i++)
{
$('#Goal_Time').append('<option value=Min_DurationVar>Min_DurationVar</option>');
}
}
});
thanks
Well Kinda working example:
http://jsfiddle.net/v5DC3/5/
JS
$('#Goal_WeightVar').live('change', function() {
var weightVar = 0; // for testing only
var goalWeightVar = $('#Goal_WeightVar').val();
if(goalWeightVar > 0)
{
Goal_WtVar = Math.abs(weightVar - goalWeightVar);
Min_DurationVar = Math.round(Goal_WtVar * 2.2);
for(var i=0;i<10;i++)
{
$('#Goal_Time').append('<option value='+Min_DurationVar+'>'+Min_DurationVar+'</option>');
}
$('#Goal_Time').listview('refresh');
}
});
HTML
<div data-role="page" id="Goal_Time_Page">
<div data-role="content">
<label for="Goal_WeightVar">Goal Weight:</label>
<input type="text" name="Goal_WeightVar" id="Goal_WeightVar" value="" />
<label for="Goal_Time" class="select">Goal Time:</label>
<select name="Goal_Time" id="Goal_Time">
<!-- Add options here -->
</select>
</div>
</div>
You will need to tweak it
As it says in the docs of jQuery Mobile, you have to tell the select menu to update it's contents by calling $('select').selectmenu();
If it still doesn't work you'll have to post a little sample code so I can have a look at it.
Edit:
Actually, that's not even necessary. If you have an empty <select id="to-append"></select>, you can just add options via $('#to-append').append('<option value="a">A</option>')!
The onchange event of the select is probably not the right event to do this though. The select will not change as long as it's empty, thus your event will never get triggered. Try the blur event of the text box.
jQuery Mobile Docs - Select

Resources