33

I'm using the new jquery mobile 1.0 alpha 1 release to build a mobile app and I need to be able to toggle the text of a button. Toggling the text works fine, but as soon as you perform the text replacement the css formatting gets broken.

Screenshot of the messed up formatting: http://awesomescreenshot.com/03e2r50d2

    <div class="ui-bar">
        <a data-role="button" href="#" onclick="Podcast.play(); return false" id="play">Play</a>
        <a data-role="button" href="#" onclick="Podcast.download(); return false" id="download">Download</a>
        <a data-role="button" href="#" onclick="Podcast.consumed(); return false" id="consumed">Mark Old</a>
    </div>

$("#consumed").text("Mark New");
Josh Rickard
  • 1,593
  • 2
  • 16
  • 29

10 Answers10

67

When you create the button it adds some additional elements, some inner <span> elements that look like this:

<a data-role="button" href="#" onclick="Podcast.consumed(); return false" id="consumed">
  <span class="ui-btn-inner ui-btn-corner-all">
    <span class="ui-btn-text">Mark Old</span>
  </span>
</a>

To change the text, you'll want this selector:

$("#consumed .ui-btn-text").text("Mark New");
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • 17
    There should be a better way to achieve this, like with the `$('ul').listview('refresh');` call to update a list. Although the way described works, it takes into account internal knowledge of how the final layout of the elements looks like. This implementation detail might change in the future. But since jquery mobile is still in alpha stage, +1 for the pragmatic solution. – Jordão Jan 24 '11 at 19:34
  • 1
    I came across this question cause the initial question was a bit misleading (Nick's answer is correct though). But I just want to add, for others looking into the same problem with an actual – Mathias Conradt Nov 08 '11 at 06:16
  • 4
    -1 > The correct approach here is to run $('#myButton').button('refresh') after a DOM update. – Steven de Salas Apr 20 '12 at 15:33
  • @StevendeSalas - at the time of this answer, that was not the behavior, it had no effect - you should edit answers in this case to indicate a newer/better way has since been added to the library. – Nick Craver Apr 21 '12 at 19:08
  • I added the correct answer when I voted this one down, its at the bottom unnoticed. – Steven de Salas Apr 22 '12 at 18:50
  • It is a weak solution, since what if jquerymobile changes the class name... but it works. – shaharsol Jun 06 '12 at 07:55
12
<a data-role="button" href="#" id="consumed">Mark Old</a>

You want to:

$('#consumed').text('Mark New');
$('#consumed').button('refresh');

The reason is to enable your changes to be backwards-compatible with future versions of jQuery mobile.

Steven de Salas
  • 20,944
  • 9
  • 74
  • 82
  • This method fails with"uncaught exception: cannot call methods on button prior to initialization; attempted to call method 'refresh'" when I try this (Firefox 12.0). Accepted answer worked for me. Using jQM 1.1.0 and jQ 1.7.1. – PahJoker May 13 '12 at 01:01
  • Accepted answer is a bit of botch even though it works, you want to use the jQuery API as much as possible to ensure future compatibility. This answer will work fine after the button has been initialized, make sure you wrap the code in `$(document).ready(function() { ... });` – Steven de Salas May 13 '12 at 09:52
  • This doesn't work even if the button is initialized. http://jsfiddle.net/4Bgx7/1405/ – Alejo Jul 31 '12 at 17:20
  • 1
    -1. I am down voting, because this is being pushed as a proper solution, but based on the jQuery Mobile docs themselves, this will not work for link buttons. To quote the [docs](http://jquerymobile.com/demos/1.2.0/docs/buttons/buttons-types.html): **"Link-based buttons aren't part of the button plugin and only just use the underlying buttonMarkup plugin to generate the button styles so the form button methods (enable, disable, refresh) aren't supported."** – Justin Holzer Feb 06 '13 at 13:56
  • 1
    I'd just use val instead of text: $('#consumed').val('Mark New'); $('#consumed').button('refresh'); – Googol Mar 13 '13 at 15:46
9

I read through this and various options online and think I may have a simpler solution. It definitely works for links you are turning into a button with the data-role="button" attribute.

Simply put the text of the button in a separate span, and then change the contents of the span in your JavaScript.

e.g.

<a data-role="button" href="#" id="consumed"><span id="oldBtnText">Mark Old</span></a>

Then a simple

$('#oldBtnText').html("Old");

Will do the job. It also shouldn't be a problem if jQuery changes their structure.

Britic
  • 503
  • 4
  • 10
  • 1
    This was the only approach here that worked in jQM 1.4.0. I don't see the nested spans that Nick references in his answer. – DOK Feb 24 '14 at 01:06
  • B-E-A-U-T-I-F-U-L. This is just like that joke of expensive fountain pen that works in space against pencil solution. – Adway Lele Jan 28 '16 at 17:51
8

I wrote a simple plugin to do this for either a link based button, or an <input type="button"> button. So if you have

<input type="button" id="start-button" val="Start"/>

or

<a href="#" data-role="button" id="start-button">Start</a>

Either way, you can change the displayed text with

$("#start-button").changeButtonText("Stop");

Here's the plugin:

(function($) {
    /*
     * Changes the displayed text for a jquery mobile button.
     * Encapsulates the idiosyncracies of how jquery re-arranges the DOM
     * to display a button for either an <a> link or <input type="button">
     */
    $.fn.changeButtonText = function(newText) {
        return this.each(function() {
            $this = $(this);
            if( $this.is('a') ) {
                $('span.ui-btn-text',$this).text(newText);
                return;
            }
            if( $this.is('input') ) {
                $this.val(newText);
                // go up the tree
                var ctx = $this.closest('.ui-btn');
                $('span.ui-btn-text',ctx).text(newText);
                return;
            }
        });
    };
})(jQuery);

... because sprinkling your code with dependencies on exactly how jQuery Mobile renders these buttons is not a good idea. Programming rule: if you gotta use a hack, isolate it to a well-documented, re-usable chunk of code.

Leopd
  • 41,333
  • 31
  • 129
  • 167
  • I like this solution because if the class .ui-btn-text is changed some day in jQuery Mobile there will be only a few lines of code to change instead of a bunchload of html and javascript. – Libby Apr 30 '12 at 18:49
  • best solution, worked like a charm, also as Libby pointed out the hack is made clean by abstraction. – Priyank Bolia Jul 12 '12 at 16:57
3

This works for me:

$('#idOfOriginalButton').prev('.ui-btn-inner').children('.ui-btn-text').html('new text');

solution from: http://forum.jquery.com/topic/changing-text-works-except-for-buttons

Yuval A.
  • 5,849
  • 11
  • 51
  • 63
  • 1
    +1 because this allows you to change the text when a button is clicked. `$("button").bind("click", function(event, ui) { $(this).prev('.ui-btn-inner').children('.ui-btn-text').html('new text'); return false; });` – styfle Dec 21 '11 at 19:02
1

For markup like

<button id="consumed">Mark Old</button>

$("#consumed").html("Mark New");
$("span > span", $("#consumed").parent()).html("Mark New");
Vikas
  • 24,082
  • 37
  • 117
  • 159
0

In the new jquery mobile version there is an inner span tag within the button.

So you have not to change the text of the 'a' tag but to change the text of the inner span.

e.g.

$("#consumed .ui-btn-text").text("test");

letsdev-cwack
  • 99
  • 4
  • 10
0

For those interested in a easy solution, I created a plugin called Audero Text Changer.

Aurelio De Rosa
  • 21,856
  • 8
  • 48
  • 71
0

As of JQM 1.3.1 (maybe earlier?) simple .text() seems to be supported.

Peter
  • 1
0

For some reason I am not having an 'ui-btn-text' classed span the first time I want to change the button text. So I workaround it like this:

var button = $("#consumed");
var innerTextSpan = button.find(".ui-btn-text");

// not initialized - just change label
if (innerTextSpan.size() == 0) {
    button.text(label);

// already initialized - find innerTextSpan and change its label    
} else {
    innerTextSpan.text(label);
}
Plamen
  • 330
  • 2
  • 8