So I have a rails app that renders views via jquery-ujs. (data-remote in the URLs, then a load of js.erb files with things like:
$('#whatever').html('<%= j render("form") %>');
In my main JS file, I have event handlers like so:
$('.action').on('click', function() {
console.log("clicked");
});
but the on() behaviour does not attach to the new elements inserted by jquery-ujs. I can go into the console and paste the above code and everything attaches fine (once the elements are already there), but straight after ujs fires, no luck. Is this a bug or am I doing something wrong?
This is with jQuery 1.9.1 and Rails 3.2.13 btw.
You need to bind on to a parent like document. Now, you're binding directly to the .action element, which is essentially the same as using $('.action').click(). Because you're adding elements to the DOM later, you need to delegate the handler to something that's already present before the elements are inserted. You can provide a selector as the second parameter of the .on event to bind it to .action.
Have a look at the 'Direct and delegated events' section in jQuery's API documentation for .on.
This should work:
$(document).on('click', '.action', function () {
console.log('Clicked!');
});
Since #whatever seems to be static (exists all the time) you can delegate the handling to it..
$('#whatever').on('click','.action', function(e){
console.log("clicked");
});
(assuming that the .action elements are added inside the #whatever element)
See http://api.jquery.com/on/#direct-and-delegated-events for more on delegated events
Related
My front-end structure is like below:
<div id='item-list'>
# List of items to be replaced every time
</div>
<form>
<submit/>
</form>
The idea is that, every time when the submit button is clicked, my JS would send AJAX request, and the server would return an HTML partial for the item-list, and in my front-end, the item-list would be replaced with the ajax return.
However, since there're also some use of UJS in my item-list, the bindings no longer works after the replacement.
I believe it's the problem that the UJS code didn't execute when the replacement happens. I want to ask how to force the execution of UJS code?
Thanks a lot
You'll need to delegate your event bindings from an element which is always going to be present on your page (typically document):
$(document).on("submit", ".element", function(){
//stuff
});
The problem you have is that Javascript only works with elements in the actual DOM. It doesn't, nor can it work with, elements which are appended after the DOM has been loaded
This means you have to bind the javascript events to elements which will always be present in the DOM, and delegate from them
--
That's the best I can do with what you've sent so far - if you give more context, I'll be able to provide a richer answer
I am trying to execute a snippet of JS only once, after the page has completely loaded and JQM has taken care of all the ui modifications (i.e. listviews, buttons, etc.). I do want it to execute only on that page, and not on subsequent pages.
What I tried first, was pageshow
<script>
$('[data-role=page]').live("pageshow", function() {
alert("Ready!");
});
</script>
This has the problem that the function is now attached to the page div and gets executed every time any subsequent page gets shown. However, I only want this to be executed once, and only for the page that contains that JS snippet.
Is there a way to listen to the pageshow event, without actually attaching the function to it.
The only way I was able to do it was by binding and unbinding like this:
<script>
$('[data-role=page]').bind("pageshow.test", testfun);
function testfun() {
alert("Ready!");
$('[data-role=page]').unbind("pageshow.test", testfun);
}
</script>
But is there a more elegant way to do so?
jQuery has a one function to bind an event handler to be executed only once. Check the reference.
The pageinit event fires once per page just after the jQuery Mobile framework initializes its widgets; I think it may be what you're looking for.
pageinit
Triggered on the page being initialized, after initialization occurs.
We recommend binding to this event instead of DOM ready() because this
will work regardless of whether the page is loaded directly or if the
content is pulled into another page as part of the Ajax navigation
system.
Source: http://jquerymobile.com/demos/1.1.0-rc.1/docs/api/events.html
If you want to bind to a specific page and not the rest, then select only the page you want to alter... Here's an example:
<script>
$(document).delegate('#my-page-id', 'pageinit', function() {
alert("PageInit!");
});
</script>
I'm using the data-remote along with data-URL to make an Ajax call via jquery ujs and it is working.
However, I can't understand how I'm to process the returned value.
For example, I have a controller action which returns some HTML - how do I attach a JS function (I presume) to replace the HTML in an existing div when the Ajax call finishes? I've set data-type to :html btw.
I can see the HTML is being returned by sniffing the network traffic.
I've got it to work by writing my own Ajax call (rather than using jquerys ujs version) but it feels as though I've reinvented the wheel - but I can't find how to use jquerys data-remote to make the call for me, and to then have it update a div (for example).
Thanks,
Ian
i presume that you have a button with the id "button" and a div with the id "add_some_content"
$("#button").click( function(){
$.get("some_random_url", function(data) {
$("#add_some_content").html(data);
});
});
or as jxpx777 pointed out:
$("#button").click(function(){
$("#add_some_content").load("some_random_url");
});
if you now press on the button, an ajax get request for your url is made. the answer from that page is attached to the div.
I have a single file for each page and i am trying to implement the pageinit event handler on every page (I think what belongs strictly to one page, should be declared there) as shown below:
<body>
<div id="myPage" data-role="page">
<!-- Content here -->
<script type="text/javascript">
$("#myPage").live('pageinit', function() {
// do something here...
});
</script>
</div>
</body>
The event is bound properly to the page, so the code is executed but - now my problem - if i go to another page and return later on the pageinit event will be executed twice. I think that is because the .live method binds the pageinit event again to the page. But shouldn't the pageinit event only called once at page initialization? What I am missing here?
I solve the issue by passing the name of the event, in this case the "pageinit" instead of the handler.
<script defer="defer" type="text/javascript">
var supplier = null;
$("#pageID").die("pageinit"); //<--- this is the fix
$("#pageID").live("pageinit", function(event){
console.log("initialized - #(ViewBag.ID)");
supplier = new Tradie.Supplier();
supplier.Initialize("#(ViewBag.ID)");
});
Ref: http://www.rodcerrada.com/post/2012/04/26/jQuery-Mobile-Pageinit-Fires-More-Than-Once.aspx
I think its probably best to move your JavaScript code into another file as while your navigating around your site jQuery Mobile may cleanup (read: delete from DOM) that myPage page and therefore will have to load it in again and hense rerun that same block of code you defined and bind 2 listeners for the pageinit event.
Thats basically why they suggest using the live or on functions however it falls over if you include the binding code on the page ;)
However if you insist on having your code placed on a per page basis than use bind instead of live.
Ref: http://jquerymobile.com/demos/1.0/docs/pages/page-cache.html
jQuery Mobile therefore has a simple mechanism to keep the DOM tidy. Whenever it loads a page via Ajax, jQuery Mobile flags the page to be removed from the DOM when you navigate away from it later (technically, on the pagehide event).
I'm pretty sure they recommend binding pageinit to the document using on(). E.g.
$(document).on ('pageinit', '#myPage', function (event) {
instead of having the pageinit bound to the page, which is getting re-inited. In fact, I thought $(document).on() was the recommended way to bind events in jQuery, in general, now.
A quick workaround I have used is declaring a variable containing the handler function.
var handler = function() {
// your code
};
Then always use die() before binding the handler with live()
$( "#myPage" ).die( handler ).live( handler );
I'm sure this is not the intended usage by the authors, but it does the trick, you can leave your code within the page DIV.
$("#page1").live("pageinit", function () {
alert('pageinit');
$("#page1").die("pageinit"); //<--- prevent from firing twice on refresh
});
I am using a master page on a JQuery-Mobile app that have few controller , and I want to set up a Javascript call to an initialize function on every page even when it loads through Ajax,
Iam sure there are few ways to do that, but whats the best approach and what would be the alternative to $(document).ready when the page is called through ajax instead of being directly loaded without that.
takepara's answer is correct, but...
If you want to modify the content of the page you will have to bind earlier.
Take a look at beforepagecreate event.
If your handler for this event returns false, then no JQM widgets and styles will be applied and you can work with it manually.
jQuery Mobile Docs - Events
$('div').live('pageshow',function(event, ui){
alert('This page was just hidden: '+ ui.prevPage);
});
or
$(document).bind("pageshow".function(){
// initialize code here
});