How to get the newly loaded page on pageinit? - jquery-mobile

On page 1, when ajax loading to page 2, I need to get the [data-role=page] element of page 2,
but on pageinit(or pagecreate), the $.mobile.activePage is still page 1.
How to get the newly loaded page instead of the current page on pageinit?
$(document).on('pageinit', function () {
console.log($.mobile.activePage); // page 1
});

If you want to retrieve it one time only, then use pagecreate because it fires once per page and it fires before navigation is commenced.
$(document).on("pagecreate", function (e) {
if ( $(e.target).hasClass("ui-dialog") ) {
var dialog = $(e.target);
}
});
To retrieve it every time you navigate to it, you can use othe pageContainer events. In case you want to alter the page you're nacigating to, use pagecobtainerbeforechange.
$(document).on("pagecintainerbeforechange", function (e, data) {
if ( typeof data.toPage == "object" && typeof data.prevPage != "undefined" && data.toPage.hasClass("ui-dialog") ) {
data.toPage.find(".foo").addClass(".bar");
}
});
For other events in case you just want to access dialog and manipulate its markup.
$(document).on("pagecontainerbeforeshow pagecontainershow", function (e, data) {
if ( data.toPage.hasClass("ui-dialog") ) {
var dialog = data.toPage;
/* do something */
});

Related

jQuery UI Sortable with React.js buggy

I have a sortable list in React which is powered by jQuery UI. When I drag and drop an item in the list, I want to update the array so that the new order of the list is stored there. Then re-render the page with the updated array. i.e. this.setState({data: _todoList});
Currently, when you drag and drop an item, jQuery UI DnD works, but the position of the item in the UI does not change, even though the page re-renders with the updated array. i.e. in the UI, the item reverts to where it used to be in the list, even though the array that defines its placement has updated successfully.
If you drag and drop the item twice, then it moves to the correct position.
// Enable jQuery UI Sortable functionality
$(function() {
$('.bank-entries').sortable({
axis: "y",
containment: "parent",
tolerance: "pointer",
revert: 150,
start: function (event, ui) {
ui.item.indexAtStart = ui.item.index();
},
stop: function (event, ui) {
var data = {
indexStart: ui.item.indexAtStart,
indexStop: ui.item.index(),
accountType: "bank"
};
AppActions.sortIndexes(data);
},
});
});
// This is the array that holds the positions of the list items
var _todoItems = {bank: []};
var AppStore = assign({}, EventEmitter.prototype, {
getTodoItems: function() {
return _todoItems;
},
emitChange: function(change) {
this.emit(change);
},
addChangeListener: function(callback) {
this.on(AppConstants.CHANGE_EVENT, callback);
},
sortTodo: function(todo) {
// Dynamically choose which Account to target
targetClass = '.' + todo.accountType + '-entries';
// Define the account type
var accountType = todo.accountType;
// Loop through the list in the UI and update the arrayIndexes
// of items that have been dragged and dropped to a new location
// newIndex is 0-based, but arrayIndex isn't, hence the crazy math
$(targetClass).children('form').each(function(newIndex) {
var arrayIndex = Number($(this).attr('data-array-index'));
if (newIndex + 1 !== arrayIndex) {
// Update the arrayIndex of the element
_todoItems[accountType][arrayIndex-1].accountData.arrayIndex = newIndex + 1;
}
});
// Sort the array so that updated array items move to their correct positions
_todoItems[accountType].sort(function(a, b){
if (a.accountData.arrayIndex > b.accountData.arrayIndex) {
return 1;
}
if (a.accountData.arrayIndex < b.accountData.arrayIndex) {
return -1;
}
// a must be equal to b
return 0;
});
// Fire an event that re-renders the UI with the new array
AppStore.emitChange(AppConstants.CHANGE_EVENT);
},
}
function getAccounts() {
return { data: AppStore.getTodoItems() }
}
var Account = React.createClass({
getInitialState: function(){
return getAccounts();
},
componentWillMount: function(){
AppStore.addChangeListener(this._onChange);
// Fires action that triggers the initial load
AppActions.loadComponentData();
},
_onChange: function() {
console.log('change event fired');
this.setState(getAccounts());
},
render: function(){
return (
<div className="component-wrapper">
<Bank data={this.state.data} />
</div>
)
}
});
The trick is to call sortable('cancel') in the stop event of the Sortable, then let React update the DOM.
componentDidMount() {
this.domItems = jQuery(React.findDOMNode(this.refs["items"]))
this.domItems.sortable({
stop: (event, ui) => {
// get the array of new index (http://api.jqueryui.com/sortable/#method-toArray)
const reorderedIndexes = this.domItems.sortable('toArray', {attribute: 'data-sortable'})
// cancel the sort so the DOM is untouched
this.domItems.sortable('cancel')
// Update the store and let React update (here, using Flux)
Actions.updateItems(Immutable.List(reorderedIndexes.map( idx => this.state.items.get(Number(idx)))))
}
})
}
The reason jQuery UI Sortable doesn't work with React is because it directly mutates the DOM, which is a big no no in React.
To make it work, you would have to modify jQuery UI Sortable so that you keep the DnD functionality, but when you drop the element, it does not modify the DOM. Instead, it could fire an event which triggers a React render with the new position of the elements.
Since React uses a Virtual DOM, you have to use the function React.findDOMNode() to access an actual DOM element.
I would call the jQuery UI function inside the componentDidMount method of your component because your element has to be already rendered to be accessible.
// You have to add a ref attribute to the element with the '.bank-entries' class
$( React.findDOMNode( this.refs.bank_entries_ref ) ).sortable( /.../ );
Documentation - Working with the browser (everything you need to know is here)
Hope that makes sense and resolves your issue

Which page was just shown?

In 1.4.2, I have this:
$(document).on('pagecontainershow', PageShown);
function PageShown(myEvent, myUI ) {
log(this)
log(myEvent)
log(myUI)
};
I can't determine which page was just shown.
If I add more specificity to the selector, the event doesn't fire.
Update
As of jQuery Mobile 1.4.2 you can access previous .prevPage and next page .toPage.
$(document).on("pagecontainerhide", function (e, ui) {
var activePage = ui.toPage,
previousPage = ui.prevPage;
});
Both are jQuery objects so $() isn't needed.
To determine which page is currently active, you have two options:
Listen to pagecontainerhide and check ui.nextPage object emitted by that event
$(document).on("pagecontainerhide", function (e, ui) {
var activePage = $(ui.nextPage);
});
On pagecontainershow, use the below function which will return active page.
var activePage = $.mobile.pageContainer.pagecontainer("getActivePage");
Read more about page events.

jQuery Mobile - Loading External HTML

I'm loading some external html into a div in a jquery mobile app. Everything works fine, however I'm trying to make it a little bit smoother.
Here is my code:
$(document).bind('pagebeforecreate', function (event, ui) {
if (event.target.id == 'pageViewOrder') {
//get the page
$.getJSON(root_url + '/orders/view/' + window.viewOrderReference + '/?callback=?', null, function (d) {
$("#viewOrder_content").html(d.html).trigger("create");
$.mobile.loading('hide');
});
}
What's happening is the page is being displayed prior to the ajax call finishing. Is there a way of halting jquery mobile from proceeding to display the page before this call is finished? At the moment it shows the page then the content pops in.
EDIT: This is loading in single pages
Cheers,
Ben
Halting the display process is easy, you just need to call event.preventDefault().
The problem is then to make sure that you will go with the process once you retrieve your content. What I would actually do is bind to pagechange, check if you have already retrieved the data, if not, then interrupt the process, retrieve the data and start over. If yes, then proceed as planned.
var contentRetrieved = false; //will indicate wether the JSON call has already been executed
var contentToDisplay; //data from the JSON call
$(document).live('pagebeforechange', function (event, data) {
if (( typeof data.toPage === "string" ) && ($.mobile.path.parseUrl(data.toPage).hash == '#pageViewOrder')) {
if (contentRetrieved) {
contentRetrieved = false; //content is already retrieved, we proceed with the pagechange
} else {
event.preventDefault(); //prevent further page change operations
$.getJSON(root_url + '/orders/view/' + window.viewOrderReference + '/?callback=?', null, function (d) {
contentToDisplay = {"html":d.html};
contentRetrieved = true;
$.mobile.changePage("#pageViewOrder");
});
}
}
});
$(document).bind('pagebeforecreate', function (event, ui) {
if (event.target.id == 'pageViewOrder') {
$("#viewOrder_content").html(contentToDisplay.html).trigger("create");
$.mobile.loading('hide');
}
});​

jQuery Mobile + backbone.js: navbar issue

I load pages created from templates dynamically with a function from the Router (as seen on some tutorials):
changePage: function(page) { // page is a View object
$(page.el).attr('data-role', 'page');
page.render();
$('body').append($(page.el));
var transition = $.mobile.defaultPageTransition;
if (this.firstPage) {
transition = 'none';
this.firstPage = false;
}
$.mobile.changePage($(page.el), {changeHash:false, transition: transition});
}
The thing is when pages contain a JQ Mobile navbar, the active item is not highlighted. Actually it is, like 1 ms, then it's not, I feel like it's because the navbar is "reloaded".
When I click 2 times on the same item, it works the second time.
Is there anybody who is able to have working navbars with jQuery Mobile and backbone.js?
I ended up doing that:
var activeTab = null;
$('[data-role=page]').live('pageshow', function (event, ui) {
$.each($('[data-role=navbar] ul li').children(), function (i, val) {
if (typeof activeTab !== "undefined" && activeTab != null && $(val).attr('id') == 'navTab' + activeTab)
$(val).addClass($.mobile.activeBtnClass);
else
$(val).removeClass($.mobile.activeBtnClass);
});
activeTab = null;
});
And for each route that requires an active tab I just do for instance:
r_search: function() { // Search page (form)
activeTab = "Search";
this.changePage(new SearchView());
},

PhoneGap / JQuery Mobile dbShell questions

I am trying to do a query everytime the user changes a page in a phonegap app. I am new to Phonegap/JQuery Mobile, but don't understand what is going on.
When I click a button, the pagebeforechange is getting called twice.
First time it works correctly. Next call, it does not run the dbshell.transaction, and no error is shown. So, if I click the overview page first, it works, but the other page does not. If I click the other page first, the overview page does not work. In both cases, re-visiting the same page does not re-do the query.
What's going on here? It must be something incorrect with the way I am calling dbshell?
//Listen for any attempts to call changePage().
$(document).bind( "pagebeforechange", function( e, data ) {
alert("pagebeforechange");
// We only want to handle changePage() calls where the caller is
// asking us to load a page by URL.
if ( typeof data.toPage === "string" ) {
// We are being asked to load a page by URL, but we only
// want to handle URLs that request the data for a specific
// category.
var u = $.mobile.path.parseUrl( data.toPage ),
reOverviewPage = /^#overviewPage/,
reViewByType = /^#viewByType/,
pageUrl=data.toPage;
var params = parseParams(pageUrl.substr(pageUrl.lastIndexOf("?") + 1));
if ( u.hash.search(reOverviewPage) !== -1 ) {
alert("overview");
dbShell.transaction(function(tx) {
alert("doing query");
tx.executeSql("select _id, description from area where _id=?",[params['id']],renderOverview,dbErrorHandler);
},dbErrorHandler);
} else if (u.hash.search(reViewByType) !== -1 ) {
alert("viewByType");
dbShell.transaction(function(tx) {
try
{
alert("!");
tx.executeSql("select trip.* from trip, trip_type, trip_type_lookup where trip_type.trip_id = trip._id and trip_type_lookup._id = trip_type.trip_type_lookup_id and lower(trip_type_lookup.type_name) = ?",[params['type']],dbErrorHandler, renderViewByType);
}
catch(e)
{
alert(e.message);
}
},dbErrorHandler);
}
}
});

Resources