jQuery mobile page navigation issue with IndexedDB - jquery-mobile

Let's have a simple jQuery mobile application with two pages. something like this:
<body>
<div data-role="page" id="page1">
<div role="main" class="ui-content">
Page 2
</div>
</div>
<div data-role="page" id="page2">
<div role="main" class="ui-content">
Page 1
</div>
</div>
</body>
Now, when I'm on Page 1 and create an IndexedDB database, the DB is assigned to my start URL "pages.html". Then, I navigate to Page 2 an can access the same IndexedDB. Everything is OK until now.
But, when I'm on Page 2 and click the browser's refresh button, the browser loads the page "pages.html#page2". Now the IndexedDB is assigned to the URL "pages.html#page2" and that is another database than of "pages.html".
How can I workaround this issue and get always the same database, even when user makes a browser refresh?

You shouldn't be seeing different databases unless the two URLs have different origins. Source:
IndexedDB adheres to a same-origin policy. An origin is the domain, application layer protocol, and port of a URL of the document where the script is being executed. Each origin has its own associated set of databases. Every database has a name that identifies it within an origin.
The security boundary imposed on IndexedDB prevents applications from accessing data with a different origin. For example, while an app or a page in http://www.example.com/app/ can retrieve data from http://www.example.com/dir/, because they have the same origin, it cannot retrieve data from http://www.example.com:8080/dir/ (different port) or https://www.example.com/dir/ (different protocol), because they have different origins.
Are you really seeing different databases at http://example.com/pages.html#page1 and http://example.com/pages.html#page2? Or is the URL changing in the second case somehow, maybe to https://example.com/pages.html#page2 or http://subdomain.example.com/pages.html#page2?

Related

MVC Layout with Menu

I'm new to MVC and I'm trying to make use of the Layout Page So far I have the following layout page:
...
<div class="container-full body-content">
<h2>#ViewBag.Title</h2>
<div class="row">
#if (Request.IsAuthenticated)
{
<div class="col-sm-3">
#{Html.RenderAction("MenuPartial", "Layout");}
</div>
<div class="col-sm-9" style="background-color:aqua">
#RenderBody()
</div>
}
else
{
#RenderBody()
}
</div>
...
Is there a way to get MVC to just re-render the render body rather than doing a full post back and re-loading the navigation menu each time a page changes?
First, MVC doesn't do "postbacks". If you click a link, that's just a GET request. If you actually submit a form, it will send the request as a POST, but the destination could be an entirely different view or the same.
Second, taking an action like clicking a link or submitting a form within a web browser by default sends a request to the server and then entirely replaces the user's rendered view with a the response from the server. That necessitates the the server send back a full HTML document, including any associated layout.
If you want to replace just a portion of the HTML page without changing the user's view, that requires using AJAX. You send an AJAX request to request an action that will return a partial view. In other words, it will not utilize the layout you've defined for the web application. You, then, are responsible for replacing the appropriate portion of the DOM client-side with the server's response. There's a plethora of client-side JavaScript libraries that can help you manage this type of workflow, but they're all frameworks in their own right. In other words, they handle routing, models, views, etc. These are what's referred to as SPAs, or Single Page Applications. When you create a SPA, the server is relegated to a pure support role, only providing endpoints allowing you to retrieve or update data. Web Api is a popular choice here exactly for that reason; as all the MVC machinery is unnecessary.
If you're just looking to optimize things by say not having to render the child action that returns the menu, you can employ OutputCache on the child action so that for a period of time, the action will not need to run again, and the HTML output it generated can just be dumped directly into the appropriate place in the layout.

Delaying load of page contents until menu item clicked in a multi-page template

I'm not sure I understand what's possible with multi-page templates in JQM so I need a bit of help. I'm using version 1.4.5.
Let's say my app has only two pages (Page A and B) generated by a multi-page template. It takes the server several seconds to generate each page because they require many database calls and data processing. Currently, this multi-page template is generated by a single script on the server, index.pl.
Both pages are accessed by the user through a navbar. Page A is the first page in the template so it's visible to the user first.
To speed up the app, I want the HTML for Page B to get generated and fetched from the server only after the user taps the navbar menu item for Page B.
After Page B loads, the user should now be able to switch between pages instantly since the content for both pages are loaded into the DOM.
What is the proper way of accomplishing this desired result?
Do I tie the navbar tap on Page B to an ajax call and inject the server response into Page B? This seems kludgy.
I'm thinking I'm missing something fundamental about JQM but I'm not sure what. Can someone help?
SERVER-SIDE SCRIPT PSEUDOCODE:
<!-- PAGE A -->
output <div data-role="page" id="page_a">
output <div data-role="navbar">
output <ul><li>Page A</li>Page B<li></ul>
output </div>
output <div role="main" class="ui-content">
generate_html_page_a();
output </div>
output </div>
<!-- PAGE B -->
output <div data-role="page" id="page_b">
output <div data-role="navbar">
output <ul><li>Page A</li>Page B<li></ul>
output </div>
output <div role="main" class="ui-content">
generate_html_page_b();
output </div>
output </div>
For your architecture the best approach is single page template but you can use the pagecontainer API to load any page programmatically.
$(":mobile-pagecontainer").pagecontainer("load", "about.html", { role: "dialog" });
Check the jQM docs for more information.

jQuery Mobile: about the page container ($.mobile.pageContainer)

$.mobile.pageContainer refers to the element that contains other virtual pages. It is set to <body>. So I assume that it can be changed. Indeed, some JQM methods (changePage) lets you specify non-default page container for a page. The JQM docs are lacking the necessary details. So my questions are:
Can you change the default page container in markup/code? How?
What are the reasons to have a page container other than <body>?
Does it mean that there can be multiple page containers with some "pages" residing in one page container and other "pages" residing in other containers? Why would you want to do this?
1 You can place your page divs within a container element in markup.
2 I use ASP.Net Webforms which requires a FORM element, so sometimes I add my jQM pages to a top level FORM instead of the body allowing me to use ASP.Net controls within my separate pages while sharing the same FORM element.
3 I think you need to keep all pages within the same container, otherwise links between pages break. Here is a jsFiddle with 2 pages in a container linking to eachother. Try putting them in separate containers and you will see the linking stop working.
<div id="PageContainer1">
<div data-role="page" id="page1">
<div data-role="header">
<h1>My page 1</h1>
</div>
<div data-role="content"> Go to Page 2
</div>
</div>
<!-- insert separate container here
</div>
<div id="PageContainer2">
-->
<div data-role="page" id="page2" data-theme="a">
<div data-role="header">
<h1>My page 2</h1>
</div>
<div data-role="content"> Go to Page 1
</div>
</div>
</div>
UPDATE: As pointed out in the comments, you can certainly navigate to pages in other containers via changePage, just the standard href="#page2" links break.
$.mobile.changePage("#page2", {"pageContainer": $("#Container2")});
I am not sure of a use case for having separate containers, perhaps code organization?

Jquery Mobile Javascript not working on ajax load

Have the following markup in my html page to toggle a search bar based on if a search icon is clicked:
<a id="searchIcon" href="/"></a>
<div id="searchWrapOuter" style="display:none;">
<div id="searchWrapInner">
<div id="formContainer">
<form id="searchForm" action="#">
<div>
<input type="search" name="search-mini" id="search-mini" value="" data-mini="true" />
</div>
</form>
</div>
</div>
</div>
Width the following javascipt/jquery:
$(function() {
$(document).on("click", "#searchIcon", function () {
var searchWrapper = $("#searchWrapOuter");
$(searchWrapper).slideToggle();
return false;
});
});
This code works as expected on a page load direct off a Url. When coming into the page off a link which is Ajax loaded, loads the contents of the page into the DOM, and the DOM ready handler only executes for the first page.
I have read about using the
$(document).on('pageinit'), not $(document).ready()/$(function()
I still haven't been able to get this to work when coming in off an ajax link however. What would be the correct way to implement these events to get the code to work coming in from an Ajax link?
Thanks,
Most likely it is because you are using IDs instead of classes. jQuery Mobile doesn't work well with IDs because it caches pages into the DOM so if you open a page, close it, then go back to the page, you might have your page twice inside the DOM (one visible, one hidden/cached). So when you do $("#searchWrapOuter") you don't know which element you are actually dealing with (in your case, probably the hidden one).
The solution is to change your IDs to classes. This is not very intuitive but I found that is the best way to work with jQuery Mobile.
Also note this comment in the doc which might also be relevant to you:
The id attribute of all your elements must be not only unique on a given page, but also unique across the pages in a site. This is because jQuery Mobile's single-page navigation model allows many different "pages" to be present in the DOM at the same time. This also applies when using a multi-page template, since all "pages" on the template are loaded at once.
http://jquerymobile.com/demos/1.2.0/docs/pages/page-anatomy.html
You can manually adjust delay time to 500ms and 1s.
$(searchWrapper).delay(1000).slideToggle();
My issue is that the page id was below the pages tags. So once I moved the page div above it, the javascript was included in the ajax page load. Previous to this

How to hide a content placeholder if it has no children without client code (MVC)

I have a ContentPlaceholder inside of a MasterPageView. All of my other pages come from the same master and I have one page that needs about 70% of the behavior in this master. There is a navigation panel in the master that is spitting out un-necessary html even if left blank by the page. Looks like this:
<div class="span3">
<div class="side_navigation">
<ul>
<asp:ContentPlaceHolder ID="SideNavigation" runat="server" />
</ul>
</div>
</div><%-- /master sub-navigation --%>
I simply want to hide ALL of this markup whenever my placeholder (SideNavigation) has 0 children. I don't want to use javascript. I'd rather do this work on the server and deliver it to the client with less responsibility and markup. I've already tried doing "this.SideNavigation.Controls.Count" but it always ends up being 0. If there was a way I could tie into a loaded event and then test this logic that would be great. I am ok with making a code-behind file for my master, but it would be nice to be able to accomplish my goal in the .master file only.
Let me know what you think.
I would probably recommend using a different master page for the page without the navigation. You can have nested master pages so you don't necessarily need to duplicate code to do this.
However if you do wish to keep it like this, I would personally use a bit of javascript (with jquery) as follows
$(function(){
if($('.span3 .side_navigation ul li').length() == 0){
$('.span3').hide();
}
});
obviously i'd give span3 an ID to make it not hide every span3 but you hopefully get the idea.

Resources