Reputation: 534
Sorry if this has been asked before, I've searched but couldn't find anything appropriately related...
I have a very simple site here that has 3 buttons:
Add Component
Save Current State
Restore Saved State
The Add Component button does exactly what I want which is to create a new simple collapse item within the
<div data-role="collapsible-set" class="flow" id="collapsibleComponent"></div>
tags.
Also, the Save Current State
storeCurrentState();
button seems to capture the required code identically to what's being displayed (which is correct).
However, when I click the Restore Saved State button (run the restorePriorState();
method), the code that is read from the localStorage and put back into the page is not consistent with the code that was saved. As a result I end up with a nested looking collapsed item like below...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TutorialW3a</title>
<link href="jquery-mobile/jquery.mobile.theme-1.3.0.min.css" rel="stylesheet" type="text/css" />
<link href="jquery-mobile/jquery.mobile.structure-1.3.0.min.css" rel="stylesheet" type="text/css" />
<script src="jquery-mobile/jquery-1.11.1.min.js"></script>
<script src="jquery-mobile/jquery.mobile-1.3.0.min.js"></script>
</head>
<body>
<div data-role="page" id="page">
<div data-role="header">
<h1>Header</h1>
</div>
<div data-role="content">
<div data-role="collapsible-set" class="flow" id="collapsibleComponent">
<!--New collapsible divs go here-->
</div>
</div>
<button onclick="addCollapsibleComponent()">Add component</button>
<button onclick="storeCurrentState()">Save current state</button>
<button onclick="restorePriorState()">Restore saved state</button>
<div data-role="footer" data-position="fixed">
<h4>Footer</h4>
</div>
</div>
</body>
</html>
<script>
//
var collapsibleComponentContent = document.getElementById("collapsibleComponent");
var collapsibleDiv;
function addCollapsibleComponent() {
//create div element
collapsibleDiv = $('<div id="new" data-role="collapsible" data-collapsed="true"><h3>Heading</h3><p>Paragraph</p></div>"');
//append new collapsible div to #collapsibleComponent
$("#collapsibleComponent").append(collapsibleDiv);
//collapse all collapsible divs
$('div[data-role="collapsible"]').collapsible();
}
//
function storeCurrentState() {
collapsibleDiv = document.getElementById("new");
localStorage.setItem("html_data", JSON.stringify(collapsibleComponentContent.innerHTML));
}
//
function restorePriorState() {
collapsibleComponentContent.innerHTML = JSON.parse(localStorage.getItem("html_data"));
$("#new").collapsible();
}
</script>
This is what is generated when a new collapsible component is created...
<div id="new" data-role="collapsible" data-collapsed="true" class="ui-collapsible ui-collapsible-inset ui-collapsible-collapsed">
<h3 class="ui-collapsible-heading ui-collapsible-heading-collapsed">
<a href="#" class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-btn-up-c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="plus" data-iconpos="left" data-theme="c"
><span class="ui-btn-inner"
><span class="ui-btn-text">Heading<span class="ui-collapsible-heading-status"> click to expand contents</span></span
><span class="ui-icon ui-icon-plus ui-icon-shadow"> </span></span
></a
>
</h3>
<div class="ui-collapsible-content ui-collapsible-content-collapsed" aria-hidden="true"><p>Paragraph</p></div>
And this is what is created when I reload...
<h3 class="ui-collapsible-heading ui-collapsible-heading-collapsed">
<a href="#" class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-btn-up-c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="plus" data-iconpos="left" data-theme="c"
><span class="ui-btn-inner"
><span class="ui-btn-text"
><a href="#" class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-btn-up-c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="plus" data-iconpos="left" data-theme="c"
><span class="ui-btn-inner"
><span class="ui-btn-text">Heading<span class="ui-collapsible-heading-status"> click to expand contents</span></span
><span class="ui-icon ui-icon-plus ui-icon-shadow"> </span></span
></a
><span class="ui-collapsible-heading-status"> click to expand contents</span></span
><span class="ui-icon ui-icon-plus ui-icon-shadow"> </span></span
></a
>
Upvotes: 1
Views: 134
Reputation: 7707
You are asking "Why", so here is the answer:
JQM is a mixed JS/CSS framework, i.e. the widgets
are enhanced by JS and styled by CSS. After page initialization, the widgets (identified by the "data-role
" tag) are enhanced by the framework by adding some nested elements (div
, span
), pseudo-elements
(icons) and event handlers.
That said, in Your code You are saving the enhanced version of Your initial markup together with the data-role
attribute, but You are saving only the markup, this means You won't save the JS data
which will be created by the framework during the widget initialization. In short, You are saving only one half of the already enhanced widget.
The next time, the framework will find the data-role
attribute again, but not the associated data
object and by invoking $("#new").collapsible();
You will end up with that double-nested markup.
More information:
You can take a look at the JQM widget object as follows:
$.data(document.getElementById("new"),"mobile-collapsible")
or:
$("#new").jqmData("mobile-collapsible")
There is more than one possible solution for Your task.
Maybe You can restore the initial un-enhanced markup:
$("#collapsibleComponent :jqmData(role='collapsible')").collapsible("destroy");
and save that:
localStorage.setItem("html_data", JSON.stringify($("#collapsibleComponent").html()));
Finally, You assumption that
to capture the required code identically to what's being displayed is correct
is wrong.
Upvotes: 1