I am busy writing some helper functions for my fellow developers in-office who isn't too familiar with Bootstrap - which takes basic html and creates bootstrap layouts for them.
In this case, I am trying to make a justified horizontal list of radio buttons.
A example is:
<fieldset data-type="horizontal" data-bootstrap="radiogroup">
<label>
<input type="radio" name="g1" value="default" data-bind="checked: true"/>Recent
</label>
<label>
<input type="radio" name="g1" value="order" data-bind="checked: false"/>By Number
</label>
<label>
<input type="radio" name="g1" value="advanced" data-bind="checked: false"/>Advanced
</label>
</fieldset>
I execute some JQuery inside the typescript file linked to this page - and the code reads:
function layoutUnwrappedBootstrapControls() {
$("*[data-bootstrap='radiogroup']")
.each((index, element) => {
var listOfRadioButtons = $(element).find('label').clone();
$(element).children().remove();
$(element)
.append("<div class='btn-group col-lg-12 col-md-12 col-sm-12 col-xs-12 clearfix' data-toggle='buttons'></div>");
$(element)
.children(":first")
.append(listOfRadioButtons)
.find("label")
.addClass("btn btn-primary")
.css("width", (100 / listOfRadioButtons.length) + '%');
$(element).children(":first").button().button('refresh'); //< the issue
});
}
Which produces:
<div class="btn-group col-lg-12 col-md-12 col-sm-12 col-xs-12 clearfix" data-toggle="buttons">
<label class="btn btn-primary" style="width: 33.3333%;">
<input type="radio" name="g1" value="default" data-bind="checked: true" data-mini="true" data-theme="h" id="tz15" checked="checked">Recent
</label>
<label class="btn btn-primary" style="width: 33.3333%;">
<input type="radio" name="g1" value="order" data-bind="checked: false" data-mini="true" data-theme="h" id="tz16">By Number
</label>
<label class="btn btn-primary" style="width: 33.3333%;">
<input type="radio" name="g1" value="advanced" data-bind="checked: false" data-mini="true" data-theme="h" id="tz17">Advanced
</label>
</div>
On the page, this seems fine. The issue I have however, is the data-toggle='buttons'
part - it tells me that bootstrap runs some code in order to initialise the list of radio buttons - and it doesn't seem to play nice with dynamically created button-groups.
My attempt to reinitialise the button group doesn't work. Radio Buttons still remain static - doesn't swap out 'active' on the label, and 'checked' on the input.
The spoopier part is: I cannot reproduce my issue on JSFiddle using identical code! it works as expected on JSFiddle: JSFiddle
How can I force a re-initialisation of a dynamically-created button-group?
I am busy writing some helper functions for my fellow developers in-office who isn't too familiar with Bootstrap - which takes basic html and creates bootstrap layouts for them.
In this case, I am trying to make a justified horizontal list of radio buttons.
A example is:
<fieldset data-type="horizontal" data-bootstrap="radiogroup">
<label>
<input type="radio" name="g1" value="default" data-bind="checked: true"/>Recent
</label>
<label>
<input type="radio" name="g1" value="order" data-bind="checked: false"/>By Number
</label>
<label>
<input type="radio" name="g1" value="advanced" data-bind="checked: false"/>Advanced
</label>
</fieldset>
I execute some JQuery inside the typescript file linked to this page - and the code reads:
function layoutUnwrappedBootstrapControls() {
$("*[data-bootstrap='radiogroup']")
.each((index, element) => {
var listOfRadioButtons = $(element).find('label').clone();
$(element).children().remove();
$(element)
.append("<div class='btn-group col-lg-12 col-md-12 col-sm-12 col-xs-12 clearfix' data-toggle='buttons'></div>");
$(element)
.children(":first")
.append(listOfRadioButtons)
.find("label")
.addClass("btn btn-primary")
.css("width", (100 / listOfRadioButtons.length) + '%');
$(element).children(":first").button().button('refresh'); //< the issue
});
}
Which produces:
<div class="btn-group col-lg-12 col-md-12 col-sm-12 col-xs-12 clearfix" data-toggle="buttons">
<label class="btn btn-primary" style="width: 33.3333%;">
<input type="radio" name="g1" value="default" data-bind="checked: true" data-mini="true" data-theme="h" id="tz15" checked="checked">Recent
</label>
<label class="btn btn-primary" style="width: 33.3333%;">
<input type="radio" name="g1" value="order" data-bind="checked: false" data-mini="true" data-theme="h" id="tz16">By Number
</label>
<label class="btn btn-primary" style="width: 33.3333%;">
<input type="radio" name="g1" value="advanced" data-bind="checked: false" data-mini="true" data-theme="h" id="tz17">Advanced
</label>
</div>
On the page, this seems fine. The issue I have however, is the data-toggle='buttons'
part - it tells me that bootstrap runs some code in order to initialise the list of radio buttons - and it doesn't seem to play nice with dynamically created button-groups.
My attempt to reinitialise the button group doesn't work. Radio Buttons still remain static - doesn't swap out 'active' on the label, and 'checked' on the input.
The spoopier part is: I cannot reproduce my issue on JSFiddle using identical code! it works as expected on JSFiddle: JSFiddle
How can I force a re-initialisation of a dynamically-created button-group?
Share Improve this question edited Dec 29, 2017 at 13:27 Eon asked Dec 29, 2017 at 13:08 EonEon 3,97410 gold badges48 silver badges76 bronze badges 16- 3 Make sure that you include the bootstrap js file. You can see that JSFiddle is includeing jquery , bootstrap.css and bootstrap.js . If you do not include the bootstrap.js no error appears in the console, so thats why maybe you missed it. – knetsi Commented Dec 31, 2017 at 16:22
- Nope, It is on my project though – Eon Commented Dec 31, 2017 at 16:25
-
3
What is the
data-bind
for? is that for another library like knockout? Hard to help without a demo that actually reproduces your problem – charlietfl Commented Jan 1, 2018 at 21:16 - 1 To clarify: does everything look okay (visually) but doesn't have the data you'd expect (i.e. not checked), or does it also look wrong? – MynockSpit Commented Jan 2, 2018 at 17:19
- 1 @knetsi, drop your ment as the answer. I want to award the bounty to you. It turns out that within our framework, we had a <panyname>.bootstrap.js - which confused me. It wasn't Twitter bootstrap. I never saw the script load once - and that was what was causing the headaches. Added script from cdn - and boom, the code above worked. Note though : There is a load order. jQuery Mobile/jQueryUI and JQuery must be loaded before bootstrap for this code to work otherwise it causes collisions.. The obvious solution is the hardest to spot... – Eon Commented Jan 4, 2018 at 12:06
4 Answers
Reset to default 4If you call document ready again then previous events associated using bootstrap.js will be unbind, which is not a good idea so you can either change the sequence of execution of your script (means before bootstrap.js) or hold document ready event itself until you are done with your script. You can get reference of jquery.holdready here https://api.jquery./jquery.holdready/
If your code executes after bootstrap has already done it's business, it will not work...
You need to make your code execute before bootstrap...
So you need to either,
- Add your scripts before bootstrap if you are using document ready event.
- Move your scripts right after your html (in footer) without using document ready event.
The following worked for me (locally and in a fiddle).
In addition to incorporating document.ready
in a script tag inside the body (mentioned by previous answers) it looks like your knockout binding has a problem. I changed checked: true / checked: false
to checked: statusMsg
and added statusMsg: ko.observable("default")
. Knockout will check a radio box when the observables value is equal to some radio inputs nodeValue. From the documentation:
For radio buttons, KO will set the element to be checked if and only if the parameter value equals the radio button node’s value attribute or the value specified by the checkedValue parameter.
Knockout checked binding documentation
I logged the checked
values of the boxes after clicking and it worked.
My code and fiddle below:
<body>
<fieldset data-type="horizontal" data-bootstrap="radiogroup">
<label>
<input type="radio" name="g1" value="default" data-bind="checked: statusMsg"/>Recent
</label>
<label>
<input type="radio" name="g1" value="order" data-bind="checked: statusMsg"/>By Number
</label>
<label>
<input type="radio" name="g1" value="advanced" data-bind="checked: statusMsg"/>Advanced
</label>
</fieldset>
<script>
$(document).ready(function() {
$("*[data-bootstrap='radiogroup']")
.each((index, element) => {
var listOfRadioButtons = $(element).find('label').clone();
$(element).children().remove();
$(element)
.append("<div class='btn-group col-lg-12 col-md-12 col-sm-12 col-xs-12 clearfix' data-toggle='buttons'></div>");
$(element)
.children(":first")
.append(listOfRadioButtons)
.find("label")
.addClass("btn btn-primary")
.css("width", (100 / listOfRadioButtons.length) + '%');
});
var viewModel = {
statusMsg: ko.observable("default")
}
ko.applyBindings(viewModel);
});
</script>
</body>
Working fiddle here
The issue was the fact that, as @knetsi mentioned in the ments under the question has mentioned, when you do not have bootstrap.js loaded on your site, you will not get an error in the console to point you what the issue was. When, like on my site, you work with both JQuery UI / JQuery Mobile /JQuery and Bootstrap JS, Bootstrap needs to be loaded last - as it will cause a conflict with the other libraries when you attempt to refresh a button