TLDR: Injecting and then replacing popup components into a div via AJAX is causing jQM to insert its own overlay elements outside of the div without removing them.
I have a jQM web page which dynamically loads the contents of a div tag on success of an ajax call:
$("#contentPane").html(data).trigger("create");
The ajax call can be made several times, each one replacing the previous contents of the div. The contents which are loaded vary: they may have identical components to what was previously there or, they may be completely different.
What I'm noticing is that if the contents I inject contain UI components which "popup" from the page (for example a dialog, or a selectmenu with data-native-menu = "false") JQM inserts overlay elements directly into the body tag or the active page tag, outside my active page's main content div.
For example:
<body>
...
<div class="ui-page ui-body-b ui-page-header-fixed ui-page-active" position="fixed" data-theme="b" data-role="page">
<div id="contentHeader" class="ui-header ui-bar-b ui-header-fixed slidedown" data-theme="b" data-position="fixed" data-role="header" role="banner">...</div>
<div id="contentPane" class="ui-content ui-body-b" data-theme="b" data-role="content" role="main">...</div>
<div class="ui-selectmenu ui-overlay-shadow ui-corner-all ui-body-a pop ui-selectmenu-hidden">...</div>
<div class="ui-selectmenu-screen ui-screen-hidden"></div>
</div>
...
<div class="ui-page ui-body-c ui-dialog ui-overlay-a" data-overlay-theme="a" data-theme="c" data-role="dialog" tabindex="0" style="min-height: 399px;">
</body>
The problem is that whenever I replace the contents of my "contentPane" div, these overlay elements stay in the DOM. If the new contents I inject require overlay elements as well, JQM creates new ones without removing the stale ones. So eventually my DOM looks like this:
<div class="ui-page ui-body-b ui-page-header-fixed ui-page-active" position="fixed" data-theme="b" data-role="page">
<div id="contentHeader" class="ui-header ui-bar-b ui-header-fixed slidedown" data-theme="b" data-position="fixed" data-role="header" role="banner">...</div>
<div id="contentPane" class="ui-content ui-body-b" data-theme="b" data-role="content" role="main">...</div>
<div class="ui-selectmenu-screen ui-screen-hidden" style="height: 3150px;"></div>
<div class="ui-selectmenu ui-overlay-shadow ui-corner-all ui-body-a pop ui-selectmenu-hidden">...</div>
<div class="ui-selectmenu-screen ui-screen-hidden"></div>
<div class="ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-a pop">...</div>
<div class="ui-selectmenu-screen ui-screen-hidden"></div>
<div class="ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-a pop">...</div>
<div class="ui-selectmenu-screen ui-screen-hidden"></div>
<div class="ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-a pop">...</div>
<div class="ui-selectmenu-screen ui-screen-hidden"></div>
<div class="ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-a pop">...</div>
</div>
Now this isn't a HUGE issue, as it doesn't break any functionality, but seeing how this is a mobile app, bloating up the DOM can lead to slow performance if it gets out of hand.
What I'm wondering is if there is some way I can tell JQM to clean up any of these stale DOM elements, or if there is a way I can check if any of these overlays have gone stale myself, say by using $(".ui-overlay-shadow, .ui-overlay-a") and then checking some property.
You could save the elements you inject into your page into a variable then use the .remove() operator from jQuery, Documentation.
var injectedDomElement = ...;
$(document).one("pagehide", function(){
injectedDomElement.remove();
}
Related
I'm trying to make an FAQ page using an accordion. In some of the answers I tried to make a clickable link, that will direct you to another question (I don't want the page to refresh).
With what I have now, the opened question (containing the link) will close the accordion after clicking, and open the desired accordion. The only thing missing is that the page will not scroll to the new question.
What I've got:
function openQuestion(q) {
jQuery('.accordion-toggle').removeClass('active');
jQuery('.accordion-container').fadeOut(500);
var accordions = jQuery('.accordion-toggle');
var accordion = accordions[q - 1];
jQuery(accordion).addClass('active');
jQuery(accordion).next('.accordion-container').slideToggle(500);
}
I assume the next jquery line would contain something with scrollIntoView. But no succes yet.
This is what I use in HTML
text
<div class="entry">
<h3>FAQ</h3>
<p>...</p>
<div class="clear"></div>
<div class="accordion wrapper">
<h3 class="accordion toggle active">
...
</h3>
<div class="accordion-container" style="display: block;">
<div class="content-block">
<span style="font-weight: 400;">...</span>
</div>
</div>
<!-- end accordion container -->
<h3 class="accordion toggle">...</h3>
<div class="accordion-container" style="display: none;">...</div>
<!-- end accordion container -->
</div>
</div>
I have 2 pages in my index.html in XDK. I navigate from one to the other. I want to add a back button just like the templates but it's not possible.
This is my html:
<div class="upage vertical-col left" id="mainpage">
<div id="SubPage" class="upage-content vertical-col left ">
<div class="tarea widget uib_w_1 d-margins" data-uib="media/text" data-ver="0" name="uib_w_1">
<div class="widget-container left-receptacle"></div>
<div class="widget-container right-receptacle"></div>
<div class="text-container">
<p>This is the main page</p>
</div>
</div>
<button class="btn widget uib_w_2 d-margins btn-default" data-uib="twitter%20bootstrap/button" data-ver="1" id="buttonSubPage">Go to sub page</button>
</div>
<div id="SubPage2" class="upage-content vertical-col left hidden"><span class="widget uib_w_3 d-margins badge" data-uib="twitter%20bootstrap/badge_and_label" data-ver="1">This is subfile 2</span>
</div>
</div>
I want to add the back button to "SubPage2". How can I achieve this? I'm working with a blank template in the app designer.
Add This code
$(document).ready(function(){
$("#buttonSubPage").click(function(){
$(".text-container").hide();
$("#SubPage2").show();
});
});
See Fiddle
After you add your header to the app designer, switch to the Code view look for the following code in newly created header
<div class="widget-container content-area horiz-area wrapping-col left"></div>
and then add the button code,
<button data-uib="twitter%20bootstrap/button" data-rel="back" data-ver="1" id="back">Back</button>
the data-rel controls the back action, without need for extra javascript.
My page is having a dialog and I'm dynamically shows it via javascript. It works fine in IE,FF,Safari but not in chrome and opera. If this is a known bug and has workarounds let me know, I'll post the code if you need more specification.
this is the dialog:-
<div id="infoDialog" data-role="page" data-overlay-theme="b">
<div id="headerConfirmation" data-role="header" data-theme="b">
<h1>Invalid Action</h1>
</div>
<div id="contentConfirmation" data-role="content" data-theme="b">
<p>Please increase the adults count first</p>
<a href='#' onclick='$(".ui-dialog").dialog("close");' data-role='button' data-theme='c'>Close</a>
</div>
this dialog is being loaded into an Iframe's body by this
jQuery.getJSON(url, function(data) {
$("body").html(data["html"]);
and this is how I load it via Javascript
$.mobile.changePage("#infoDialog", { transition: "pop",role: "dialog" });
The code is too much complex to add here this works fine in IE,FF,Safari
Thanks in Advance.
Thought of answering my own question. The problem resolves when I navigate to another page and come back again. Then the dialog closes properly everytime. So I add this code before all jquery mobile library:-
$("#firstLoad").bind("pagecreate",function()
{
$.mobile.changePage("#selectDates");
});
and then add a fake jquery mobile page like this
:-
<div id="firstLoad" data-theme="c" data-role="page" >
<!-- <div id="firstLoadHeader" data-role="header">
<h1>Welcome</h1>
</div>
<div id="contentSelectDates" data-role="content">
</div>
<div id="footerSelectDates" data-role="footer">
<h1>Travel Gateway</h1>
</div> -->
</div>
So my actual page that I want to show comes after this.
:-
<div id="selectDates" data-theme="c" data-role="page">
<div id="headerSelectDates" data-role="header">
<h1>Select Dates</h1>
</div>
<div id="contentSelectDates" data-role="content">
</div>
</div>
when I'm using my phone to test the app, I use the back device button to show the previous page this is working with all the pages except one page that shows a not styled page when trying to get to the pervious page so there somthing Odd. Here a briefe explanation.
there is 3 page #main_menu , #first_map , #second_map
when I'm into the #second_map page it should go to the #first_page when I press back button
but actually its showing the #main_menu page with not css styling.
could you plz tell me what is the problem an how we can fix it thank you in advance .
I provide the source code :
this is the main_page
</div>
<h2 id="thx_msg" style="margin:0 auto;"></h2>
<div class="grid2">
<div class="first" id="search_btn">
<div>
<img src="images/loupe.jpg"/>
<div>
</div>Search for a Spot</div>
</div>
<div class="second" id="submit_spot_btn">
<div>
<img src="images/spot.jpg"/>
</div>
<div>Submit a spot</div>
</div>
</div>
<ul style="margin:0 auto;" class="spaced_list" style="widht:280px;" >
<li><input type="button" data-role="none" value="Account info" class="btn" style="margin:0 auto;" id="main_page_account_info"/></li>
<li><input type="button" data-role="none" value="Log Out" class="btn" style="margin:0 auto;"id="main_page_log_out"/></li>
</ul>
</div>
here is the first_map page is named spot_page
<div data-role="page" id="spot_page" data-theme="b">
<div data-role="header" style="overflow:hidden;">
<img class="logo_icon" src="images/logo_icon.png">
</div><!-- header -->
<div class="clear"></div>
<div id="search_form_holder" style="margin:0px 25px" >
<p class="center" style="font-size:16px;font-weight:bold;">
Search for a Spot
</p>
<ul class="some_space" style="margin:0 auto;
margin-left:auto;
margin-right:auto;
align:center;
text-align:center;
width:280px;">
<li><input type="text" id="address_zip" class="field black" placeholder="Address/Zip Code"/></li>
<li id="to"></li>
<li><input type="button" data-role="none" style="width:200px;margin:15px auto;" id="search_spot_btn" class="btn" value="Search for a Spot"></li>
</ul>
<div id="hidden_scroller" style="display:none">
<select id="distance" name="Within">
<option value="1">1 Mile</option>
<option value="3">3 Miles</option>
<option value="5">5 Miles</option>
<option value="10">10 Miles</option>
</select>
</div>
</div><!-- search form -->
<div id="first_map" style="width: 100%;
height: 247px;border:1px solid black;margin:0 auto">
</div>
</div><!-- split view -->
and finally the second map here :
<div data-role="page" id="nearby_page">
<div data-role="header" style="overflow:hidden;">
<img class="logo_icon" src="images/logo_icon.png">
</div><!-- header -->
<div class="clear"></div>
<div class="second_header">Spots nearby</div>
<div id="map" style="width: 100%;
height: 398px;border:1px solid black;margin:0 auto">
</div>
</div>
As you can see the pages are separate from each other.
I have a last question could a navigation plugin help to fix the problem like jquery history plugin and thanks for your help.
Make sure to have your pages on different separate pages. If not these kind of errors will occur. Mostly, you will encounter abnormal navigation error. That is what I have experienced in my experience.
BTW, you should show more of your code for people here to help you out.
Update
PhoneGap and Android's back button do behaves odd. What I have done in my application is disabled the back button and given the soft back button on the top header. Simple history.back() will do the magic for back buttons.
You can disable as follows.
$(function(){
document.addEventListener("deviceready", onDeviceReady, false);
})
// PhoneGap is loaded and it is now safe to call PhoneGap methods
//
function onDeviceReady() {
// Register the event listener
document.addEventListener("backbutton", onBackKeyDown, false);
}
// Handle the back button
//
function onBackKeyDown() {
console.log("Back button pressed but nothing happened");
}
Anyway this is my approach. You may choose to be different.
I'm using Primefaces 3.2 with Tomcat 7.0.23 and JSF 2.0
i'm using the component.
<p:carousel id="aCarousel" value="#{BBCarousel.carouselItems}" var="carouselItem"
autoPlayInterval="3000"
rows="4" vertical="true" circular="true" pageLinks="0" headerText="Informations" >
<div class="thumbnail">
<img src="images/minilogo.png" />
</div>
<div class="info">
#{carouselItem.item_title}
<span class="cat">Category: #{carouselItem.item_cat}</span>
</div>
</p:carousel>
When the carousel reaches the last carousel item, the carousel slides to (move up) the first element.. instead, i would like that the last item to be attached to the first item, in a "circular way", without a break.. so i get a continuous scrolling effect..
I hope I have been clear..
thanks!
Looking at Firebug I see that the carousel is mostly a div and a hidden input that have coordinate values.
<div id="slideShow" class="ui-carousel ui-widget ui-widget-content ui-corner-all" style="width: 404px;">
<div class="ui-carousel-header ui-widget-header ui-corner-all">
<div class="ui-carousel-viewport" style="width: 404px; height: 253px;">
<ul style="left: -808px;">
<li class="ui-carousel-item ui-widget-content ui-corner-all photo">
<img id="slideShow:j_idt15" alt="" src="/showcase/images/nature1.jpg;jsessionid=A181FD9A4E1990E40E09B3743EB2EE61">
</li>
<li class="ui-carousel-item ui-widget-content ui-corner-all photo">
<li class="ui-carousel-item ui-widget-content ui-corner-all photo">
<li class="ui-carousel-item ui-widget-content ui-corner-all photo">
</ul>
</div>
<input id="slideShow_first" type="hidden" value="2" name="slideShow_first">
</div>
These values are changing at the autoPlayInterval which looks like a jQuery script is being invoked to move the image and perform an effect while doing so.
I don't see anything in the Primefaces documentation that suggest the unwanted autoplay effect can be changed. I don't think this is possible without modifying the Primefaces code.