Forcing jQuery Mobile to re-evaluate styles/theme on dynamically inserted content

Jquery Mobile

Jquery Mobile Problem Overview


Objective: Load HTML content via $.ajax, insert it into the DOM, have jQuery Mobile apply theme styles to it.

Problem: Content gets inserted but lacks jQuery Mobile theming.

Code:

$.ajax({
    ...
    success: function(html) {
        $('#container').append(html);
        $('#page').page('refresh', true);
    }
});

The HTML returned includes data-role tags which jQM should style...

<a data-role="button">Do Something</a>

Instead of applying the styles like it should, I get the following error:

> uncaught exception: no such method > 'refresh' for page widget instance


Above code tested using http://code.jquery.com/mobile/latest/jquery.mobile.js


Similar questions which brought me to the above error message:

https://stackoverflow.com/questions/5157386/consistently-update-page-with-appropriate-jquery-mobile-styles

https://stackoverflow.com/questions/5249250/jqm-jquerymobile-dynamically-added-elements-not-displaying-correctly-and-css-is

https://stackoverflow.com/questions/4039428/jquery-mobile-dynamically-creating-form-elements

Jquery Mobile Solutions


Solution 1 - Jquery Mobile

Just got an answer to a similar question, try using

.trigger("create")

on the element that gets the content added to.

See here: https://stackoverflow.com/questions/7999436/jquery-mobile-does-not-apply-styles-after-dynamically-adding-content

Solution 2 - Jquery Mobile

If you add items to a listview, you'll need to call the refresh() method on it to update the styles and create any nested lists that are added. For example:

$('#mylist').listview('refresh');

If you need to render a dynamic page, please read:"jQuery Mobile and Dynamic Page Generation". Sample code from this article:

// Load the data for a specific category, based on
// the URL passed in. Generate markup for the items in the
// category, inject it into an embedded page, and then make
// that page the current active page.
function showCategory( urlObj, options )
{
	var categoryName = urlObj.hash.replace( /.*category=/, "" ),

		// Get the object that represents the category we
		// are interested in. Note, that at this point we could
		// instead fire off an ajax request to fetch the data, but
		// for the purposes of this sample, it's already in memory.
		category = categoryData[ categoryName ],

		// The pages we use to display our content are already in
		// the DOM. The id of the page we are going to write our
		// content into is specified in the hash before the '?'.
		pageSelector = urlObj.hash.replace( /\?.*$/, "" );

	if ( category ) {
		// Get the page we are going to dump our content into.
		var $page = $( pageSelector ),

			// Get the header for the page.
			$header = $page.children( ":jqmData(role=header)" ),

			// Get the content area element for the page.
			$content = $page.children( ":jqmData(role=content)" ),

			// The markup we are going to inject into the content
			// area of the page.
			markup = "<p>" + category.description + "</p><ul data-role='listview' data-inset='true'>",

			// The array of items for this category.
			cItems = category.items,

			// The number of items in the category.
			numItems = cItems.length;

		// Generate a list item for each item in the category
		// and add it to our markup.
		for ( var i = 0; i < numItems; i++ ) {
			markup += "<li>" + cItems[i].name + "</li>";
		}
		markup += "</ul>";

		// Find the h1 element in our header and inject the name of
		// the category into it.
		$header.find( "h1" ).html( category.name );

		// Inject the category items markup into the content element.
		$content.html( markup );

		// Pages are lazily enhanced. We call page() on the page
		// element to make sure it is always enhanced before we
		// attempt to enhance the listview markup we just injected.
		// Subsequent calls to page() are ignored since a page/widget
		// can only be enhanced once.
		$page.page();

		// Enhance the listview we just injected.
		$content.find( ":jqmData(role=listview)" ).listview();

		// We don't want the data-url of the page we just modified
		// to be the url that shows up in the browser's location field,
		// so set the dataUrl option to the URL for the category
		// we just loaded.
		options.dataUrl = urlObj.href;

		// Now call changePage() and tell it to switch to
		// the page we just modified.
		$.mobile.changePage( $page, options );
	}
}

Solution 3 - Jquery Mobile

If you're using the ajax method to load into content, this is how I got the styling and jquery mobile functionality to work. It's pretty much the same as the suggestion above but for some people you probably like seeing a more full example.

Here is the code:

$.ajax({
url: 'url.php',
success: function(data) {    
$("#div").html(data).trigger('create');
}
});

Solution 4 - Jquery Mobile

As an update to the answers provided. As of v1.45 you can select your content and use .enhanceWithin() to enhance the child elements.

http://api.jquerymobile.com/enhanceWithin/

Solution 5 - Jquery Mobile

In jQuery Mobile Framework alpha4.1 and earlier this was done by using the .page() method.

Example to show there's not much of a difference:

$( ... lots of HTML ...).appendTo(".ui-content").page();

More info: http://jquerymobiledictionary.dyndns.org/faq.html

Why the new way (see T. Stone's answer) was introduced? .page() was written with an assumprion that the DOM element was not enhanced before.

For the sake of decoupling tje jQuery Mobile team introduces event-driven enhancement that will not only allow triggering the event, but also will make creating new widgets for new data-roles possible without modifying the code of JQM's .page method.

Solution 6 - Jquery Mobile

$('.selector').trigger('create'); seems to be the best approach, see the official FAQ below:

http://view.jquerymobile.com/master/demos/faq/injected-content-is-not-enhanced.php

Solution 7 - Jquery Mobile

For others searching for an answer for this, as of 6/9/2011 the jQuery mobile team has implemented this feature in a development branch. According to this issue, it will work in this manor:

$(".ui-content").append( ... lots of HTML ...).trigger( "enhance" );

https://github.com/jquery/jquery-mobile/issues/1799

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionT. StoneView Question on Stackoverflow
Solution 1 - Jquery MobileLarsiView Answer on Stackoverflow
Solution 2 - Jquery MobiledouywView Answer on Stackoverflow
Solution 3 - Jquery MobileWilliam FossView Answer on Stackoverflow
Solution 4 - Jquery MobileEstenView Answer on Stackoverflow
Solution 5 - Jquery MobilenaugturView Answer on Stackoverflow
Solution 6 - Jquery MobileLeonardo PintoView Answer on Stackoverflow
Solution 7 - Jquery MobileT. StoneView Answer on Stackoverflow