Getting error on $.mobile.changePage(): Uncaught TypeError: Cannot call method 'trigger' of undefined - jquery-mobile

I have a JQM apps and I am incorporating Backbone.
Since my initial javascript code is huge, I am only extracting what I believe is problematic.
I am following the advices and calls steps cited here:
jqm-config.js from http://coenraets.org/blog/2012/03/using-backbone-js-with-jquery-mobile/
http://jquerymobile.com/test/docs/pages/backbone-require.html
I have a major problem, and this is the behaviour, the problem comes from this code:
var r = Backbone.Router.extend
router: ...
"page": "pageDisplay"
...
pageDisplay: function(){
c = new AView(); // Backbone.View ...fetch() data...
$(c.el).page(); // Call to JQM to add its extra stuff; seems done correctly
$.mobile.changePage( "#" + c.id, {changeHash: false}); // line 50
}
When following the links of <a href="#page" >, I come as expected to the
page "#page" properly processed. But once there, if I click a refresh, which is indirectly reprocessed by the same router rule, I end up with the following error:
Uncaught TypeError: Cannot call method 'trigger' of undefined
I downloaded the jquery mobile development code and observed this:
// JQM1.1.2 - Line #3772 Show a specific page in the page container.
$.mobile.changePage = function( toPage, options ) {
if ( isPageTransitioning ) {
pageTransitionQueue.unshift(arguments );
return;
}
var settings = $.extend( {}, $.mobile.changePage.defaults, options);
// Make sure we have a pageContainer to work with.
settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
// Make sure we have a fromPage.
settings.fromPage = settings.fromPage || $.mobile.activePage;
// Line #3788
var mpc = settings.pageContainer, // Line #3789
pbcEvent = new $.Event("pagebeforechange" ),
triggerData = { toPage: toPage, options: settings };
// Let listeners know we're about to change the current page.
mpc.trigger( pbcEvent, triggerData ); // Line #3794
The Uncaught TypeError is caused by Line #3794, because mpc is undefined.
So, from JQM, In the Chrome inspector, I can see also that settings.fromPage is undefined and settings.pageContainer is undefined. I kind of imagine, that JQM cannot make an assumption on the fromPage, and therefore, cannot proceed on my refresh. All the options I have tried on the $mobile.changePage() have not succeed. I am out of ideas.
UPDATE/ Online site with the minimum to reproduce the problem:
apartindex, access the website with the bug
Any help will be appreciated.

The dextoInit function that calls the router code is called in $(document).ready() which does not guarantee that the jQuery mobile page has actually been set up successfully. But the router code calls $.mobile.changePage which depends on jQuery Mobile being initialized.
Putting it into mobileinit or pageinit should work.
(Unfortunately I can't modify the code and test it easily.)

Although, this fix it for the moment, it does have drawbacks. See below.
$(document).bind("pageinit", function(){
console.log('bindtomobileinit: event pageinit received');
if ( !window.AppNode.router ){
window.AppNode.router = new AppNode.singletons.router();
console.log("mobileRouter.js: Starting b history");
console.log('mobileRouter.js: About to launch Backbone history');
Backbone.history.start();
}
});
Registering to pageinit has a weird effect of being fired twice. I see that 2 nodes have been added to the Dom: the default "loading" jquery mobile div (related to pageinit:1), and my data-role page (pageinit:2). So on a "refresh browser click", my situation leaves me waiting for a first pageinit, creating an unexpected jquery mobile dom element (a default page created to display the waiting JQM circle animation), which trigger the router creation, and allows the Backbone.history call which then deal with my "" home page. The second pageinit do not interfere with the settings since I execute it only once.
I am really disappointed by this setup. I will leave this question for now, since it does sort of work.

I've found the source of the problem to be jquery-mobile version 1.3.0. When I fall back to either JSM 1.2.0 or 1.2.1, the "Uncaught TypeError: Cannot call method 'trigger' of undefined" problem goes away.
BTW, I am not using Backbone.

I had fixed this problem by using method append(), but not html()
$('body').append(view.render().$el);

I was able to resolve this issue by changing the page data property from "data-role" to "data-mobile-page" as what is referenced in line 4042 of jqm 1.3.2
fromPage.data( "mobile-page" )._trigger( "beforehide", null, { nextPage: toPage } );

Setting
$.mobile.autoInitializePage = true;
In your jquery mobile config file, some place like:
$(document).on("mobileinit", function () {...});
May help.

Related

Rails 4 breaks Stellar.js after link

My rails 4 app breaks stellar.js after link_to.
I know that is something related with turbolinks.
I installed jquery.turbolinks and my js functions from uikit are all working now.
But the stellar.js still don't..
It works when I type the address in browser: 0.0.0.0:3000, but do not after clicking any link.
I am calling stellar.js from my assets/javascripts/my-js.js like this:
$(function(){
$.stellar();
});
I also tried with no success:
function initialize() {
$.stellar();
}
$(document).ready(initialize);
$(document).on('page:load', initialize);
Thank you
Your issue is most certainly related to Turbolinks. I have a feeling that when you call $.stellar() after a Turbolink request, the call has no effect since it's already attached to the window object and that doesn't go away during a the request. Try destroying it prior to initializing it again in the initialize function.
var initialize = function() {
$.stellar( 'destroy' );
$.stellar();
}
$(document).ready( initialize );
$(document).on( 'page:load', initialize );
You can also bind the destroy method to the turbolink before-cache event :
$(document).on "turbolinks:before-cache", ->
$.stellar('destroy')

Jquery calls not working in $viewContentLoaded of Angular

Unable to call jquery functions in $viewContentLoaded event of Angular controller, here is the code for the same.
$scope.$on('$viewContentLoaded', function() {
jQuery.growlUI('Growl Notification', 'Saved Succesfully');
jQuery('#category').tree()
});
Is any configuration required here?? I tried even noConflict(); var $jq = jQuery.noConflict();
Does it require any other configuration?
Thanks,
Abdul
First thing first, don't do DOM manipulation from controller. Instead do it from directives.
You can do same thing in directive link method. You can access the element on which directive is applied.
Make sure you load jquery before angularjs scripts, then grawlUI, three, angularJS and finally your application script. Below is directive sample
var app = angular.module("someModule", []);
app.directive("myDirective", function () {
return function (scope, element, attrs) {
$.growlUI('Growl Notification', 'Saved Succesfully');
element.tree();
};
});
angularjs has built in jQuery lite.
if you load full jquery after angular, since jQuery is already defined, the full jquery script will skip execution.
==Update after your comment==
I reviewed again your question after comment and realised that content which is loaded trough ajax is appended to some div in your angular view. Then you want to apply element.tree() jquery plugin to that content. Unfortunately example above will not work since it is fired on linking which happened before your content from ajax response is appended to element with directive I showed to you. But don't worry, there is a way :) tho it is quick and dirty but it is just for demo.
Let's say this is your controller
function ContentCtrl($scope, $http){
$scope.trees=[];
$scope.submitSomethingToServer=function(something){
$http.post("/article/1.html", something)
.success(function(response,status){
// don't forget to set correct order of jquery, angular javascript lib load
$.growlUI('Growl Notification', 'Saved Succesfully');
$scope.trees.push(response); // append response, I hope it is HTML
});
}
}
Now, directive which is in controller scope (it uses same scope as controller)
var app = angular.module("someModule", []);
app.directive("myDirective", function () {
return function (scope, element, attrs) {
scope.$watch("trees", function(){
var newParagraph=$("<p>" + scope.trees[scope.trees.length-1] + "</p>" ); // I hope this is ul>li>ul>li...or what ever you want to make as tree
element.append(newParagraph);
newParagraph.tree(); //it will apply tree plugin after content is appended to DOM in view
});
};
});
The second approach would be to $broadcast or $emit event from controller (depends where directive is, out or in scope of controller) after your ajax completes and you get content from server. Then directive should be subscribed to this event and handle it by receiving passed data (data=content as string) and do the rest as I showed you above.
The thing is, threat that content from ajax as data all the way it comes to directive, then inject it to element in which you want to render it and apply tree plugin to that content.

mobile.changepage requiring page refresh

I'm using $.mobile.ChangePage() to navigate from one HTML page to another. But the contents of the page is not changing. while doing so the page URL changes but the new page is not loaded. it requires to be refreshed to load.
you should use JavaScript function to change the page..using
window.location = 'your page ';
hope it will resolve your problem !
In the code that you provided in the comments above, you are likely getting an error stating that next_page is not defined. Given that you are dealing with jQuery Mobile, try assigning the click handler slightly differently:
Change the definition of the link to something like this:
<a id="btnNextPage" href="#" >Details</a>
You don't have to give it an id - you could just use selectors to identify the link in the following javascript:
// the event handler
function next_page() {
$.mobile.changePage("http://www.google.com", {transition:"slide"});
}
// assign the click event when the DOM is ready
$(function() {
$("#btnNextPage").click ( next_page );
});

jQuery / jQuery UI - $("a").live("click", ...) not working for tabs

So I have some jQuery UI tabs. The source code is as follows:
HTML:
<div class="tabs">
<ul>
<li>Ranges</li>
<li>Collections</li>
<li>Designs</li>
</ul>
<div id="ranges"></div>
<div id="collections"></div>
<div id="designs"></div>
</div>
jQuery:
$(document).ready(function() {
$(".tabs").tabs();
});
My problem is that I am trying to make each tab load a page into the content panel on click of the relevant link. To start with I am just trying to set the html of all the panels on clicking a link. From the code below, if I use method 1, it works for all links. However if I use method 2 it doesn't - but only for the links in the tabs (i.e. the labels you click to select a tab).
Method 1 (works for all links all the time, but would not be applied to links which are added after this is called):
$("a").click(function () {
$("#ranges, #collections, #designs").html("clicked");
});
Method 2 (works for all links which are not "tabified"):
$("a").live("click", function () {
$("#ranges, #collections, #designs").html("clicked");
});
Does anyone know why it is behaving like this? I would really like to get method 2 working properly as there may well be links which I need to add click events to which are added after the page is originally loaded.
Thanks in advance,
Richard
PS yes the function calls for .live and .click are both in the $(document).ready() function, before anyone says that that may be the problem - otherwise it wouldn't work at all..
Edit:
The solution I came up with involves an extra attribute in the anchors (data-url) and the following code (which outputs a 404 not found error if the page cannot be loaded). I aim to expand this over the next few weeks / months to be a lot more powerful.
$(".tabs").tabs({
select: function (event, ui) {
$(ui.panel).load($(ui.tab).attr("data-url"), function (responseText, textStatus, XMLHttpRequest) {
switch (XMLHttpRequest.status) {
case 200: break;
case 404:
$(ui.panel).html("<p>The requested page (" + $(ui.tab).attr("data-url") + ") could not be found.</p>");
break;
default:
$(ui.panel).html("<p title='Status: " + XMLHttpRequest.status + "; " + XMLHttpRequest.statusText + "'>An unknown error has occurred.</p>");
break;
};
});
}
});
I don't know if I understand what you are going for but basically you want to do something once a tab is clicked?
Here's the docs for setting up a callback function for selecting a tab.
EDIT: Don't know if that link is working correctly, you want to look at select under Events. But basically it is:
$("#tabs").tabs({
select: function(event, ui) { ... }
});
Where ui has information on the tab that was clicked.
jQuery UI tabs has an outstanding issue where return false; is used instead of event.preventDefault();. This effectively prevents event bubbling which live depends on. This is scheduled to be fixed with jQuery UI 1.9 but in the meantime the best approach is use the built in select event as suggested by #rolfwaffle.
Maybe the tabs() plugin that you are using is calling event.preventDefault(); (Reference) once it has created it's tabs.
Then it captures the click event and the bubbling stops, so it doesn't invoke your click-function. In jQuery this is done with
$(element).click(function(){
// Do stuff, then
return false; // Cancels the event
});
You'd have to alter the tabs() plugin code and remove this return false; statement, OR if you are lucky, the plugin might have an option to disable that behavior.
EDIT: Now I see you're using jQuery UI. Then you should check the documentation there, since it is an awesome plugin, it will do anything you want if you do the html right and pass it the right options.

JQuery: calling ajax on drop element

$("div.square").droppable({
accept: '.white',
drop: function (event, ui)
{
$to = "#" + $(this).attr('id');
alert(to);
$.post(
"/Game/AddMove",
{
from: $from,
to: $to,
GameID: $("#gameID").val()
});
}
});
Well it's nor working. So I must ask, is it possible to call AJAX on droping some UI element ?
The problem is, it's not even calling an controller,
I'm going to guess that you want your to variable to be the id attr of the dropped element. I have no idea where you intended the value of $from to come from.
Just a side note - I would suggest not using variables starting with a $, especially not with jQuery.
Anyway, to access the object that dropped, do this:
drop: function(event, ui) {
toStr = '#' + $(ui.helper).attr('id');
}
in other words, ui.helper is the HTML object that was dropped onto your droppable.
Good luck.
Yes, you can trigger ajax calls on drop. (live example)
I see a couple of issues (details below):
$("div.square").droppable({
accept: '.white',
drop: function (event, ui)
{
$to = "#" + $(this).attr('id');// <== 1. Implicit Global?
alert(to); // <== 2. Syntax error
$.post(
"/Game/AddMove",
{
from: $from, // <== 3. Where does this come from?
to: $to,
GameID: $("#gameID").val()
});
}
});
You seem to be using $to without declaring it. (If it's declared in a containing scope you haven't shown, that's fine; otherwise, though, you're falling prey to the Horror of Implicit Globals. (That's probably not what's keeping it from working, though.)
The code should blow up here, unless to is defined somewhere. You don't have any variable called to.
You're using a variable $from that isn't defined in your quoted code. Fair 'nuff if it's defined in an enclosing scope, but if so, probably worth mentioning in the question.
If none of the above is it, just walk through the code. There are plenty of browser-based debuggers these days. If you use Firefox, install and use Firebug. If you use Chrome or Safari, they have Dev Tools built in (you may have to enable them in preferences). If you use IE, IE8 and up have a built-in debugger; for IE7 and earlier you can use the free version of VS.Net. For Opera, it has a built-in debugger called Dragonfly... In all of these, you can set a breakpoint on the first line of your drop handler and step through to see what's going wrong.

Resources