Container hierarchy access for jQuery elements - javascript

JQM elements on physical page:
#page_test1
button changing page to #page_test2
#page_test2
div #place to put something programmatically
to put button inside #place container I wrote the following (working) code:
$(document).on('pagebeforeshow', '#page_test2', function(event) {
$('#place').empty();
$('#place').append('Dynamic button inserted by JavaScript');
$('#place').trigger('create');
});
Ok, but when I take an attempt to move .on body to script level (directly under script tag) code inside become wrong because of context loose:
$(document).on('pagebeforeshow', '#page_test2', function(event) {
addButton(); // Attempt to move widget manipulation up
});
// Widget manipulation not changed but moved outside (level up) .on
// Not working
function addButton() {
$('#place').empty();
$('#place').append('Dynamic button inserted by JavaScript');
$('#place').trigger('create');
}
How to access JQM elements from different levels of JQM hierarchy and outside of it?
Guess it is very basic for JQM / Ajax so I will very thankful to take URL with common information.

To access an dynamically through code outside the target page, use the the following:
$(document).on(event, '.selector', function() { });
To access an dynamically through code inside the target page, use the the following:
$('.selector').on(event, function() { });

Related

javascript events not working with dynamic content added with json

I'm stuck with a situation where my DOM elements are generated dynamically based on $.getJSON and Javascript functions for this elements are not working. I'll post some general idea on my code because I'm looking just an direction of what should I do in this situation.
site.js contains general features like
$(document).ready(function() {
$('.element').on('click', function() {
$(this).toggleClass('active');
});
$(".slider").slider({
// some slider UI code...
});
});
After that:
$.getJSON('json/questions.json', function (data) {
// generating some DOM elements...
});
I have also tried to wrap all site.js content into function refresh_scripts() and call it after $.getJSON() but nothing seems to be working.
Firstly you need to use a delegated event handler to catch events on dynamically appended elements. Then you can call the .slider() method again within the success handler function to instantiate the plugin on the newly appended content. Try this:
$(document).ready(function(){
$('#parentElement').on('click', '.element', function() {
$(this).toggleClass('active');
});
var sliderOptions = { /* slider options here */ };
$(".slider").slider(sliderOptions);
$.getJSON('json/questions.json', function(data) {
// generating some DOM elements...
$('#parentElement .slider').slider(sliderOptions);
});
});
Instead of calling on directly on the element, call it on a parent that isn't dynamically added and then use the optional selector parameter to narrow it to the element.
$('.parent').on('click', '.element', () => {
// do something
});
The difference between this and:
$('.element').on('click', () => {});
is with $('.element').on(), you're only applying the listener to the elements that are currently in that set. If it's added after, it won't be there.
Applying it to $(.parent), that parent is always there, and will then filter it to all of it's children, regardless when they're added.
the easiest way is to add this after you add/generate your DOM
$('script[src="site.js"]').remove();
$('head').append('<script src="site.js"></script>');
of course your js function that generates DOM needs to be on another file than your site.js

Loading several .php file into one div

Hello i have this code to load php file into div. Its working but i need load next file into this div.
<script type="text/javascript">
$(function() {
$("a.load").on("click", function(load) {
load.preventDefault();
$("#zaw").hide().load(this.href).fadeToggle(1000);
});
});
</script>
<li><a class="load" href="zzz.php">zzz</a></li>
If i click "zzz" link loading file into my div (file table with images) i need hide this page and load next by click image.
UPDATE
Now working
<script type="text/javascript">
$(function() {
$("a.load").on("click", function(load) {
load.preventDefault();
$("#zaw").hide().empty().load(this.href).fadeToggle(1000);
});
});
</script>
You just simply need to bind another click event to an image (or table body) that you load through load() function. However, you may experience some issue with your click not working, and heres why:
If you attach two click handlers, one for a.load and second for, let's say, .image than only the first event will actually get bind to its element, and the socond one won't be attached because, well, .image doesn't exist yet - not untill you load it.
You could expect, that once you php file content will get loaded (with .image elements in it), then clicking them will fire an action you have declared, but it won't - those .image's are new DOM elements and they missed an event binding procedure which was done only once when the DOM was created (or DOM was ready if you use $.(document).ready()).
So, in order to get those clicks to work you need to either attatch them on load() function callback, like so:
$("a.load").on("click", function(load) {
load.preventDefault();
$("#zaw").hide().load(this.href, function(){
$(".image").on("click", function(e) {
$("#zaw").hide().load(/* load what you want */);
});
})
.fadeToggle(1000);
});
or insert .image click event binding inside php file you are loading or use some sort of delegation, for example:
$(document).on('click', '.image', function(){
/* do what you want */
});
which will make sure that even new, dynamically created DOM element will fire an action you want.

Running Master page scripts on imported page lines

I'm importing some php into a div block using a link like this
<a class="ajax-link" href="login.php">Login/Register</a>
and such script (that uses jquery load to fill the div block).
$(function() {
$("a.ajax-link").on("click", function(e) {
e.preventDefault();
$("#body-element").load(this.href);
});
});
Now let's say the loaded php file after running the php portion also contains a link with "ajax-link" class and I want that link too to change the contents of that div block
<?php
...
?>
<a class="ajax-link" href="view.php">View content</a>
But rather than running the above mentioned function on it, it seems to ignore it completely and opens a new page instead.
So basically... how can I run that script on imported parts of the page?
This is where event delegation comes in handy.
$(document.body).on("click", "a.ajax-link", function(e) {
// ...
});
This code needs to be re-run ... dynamically added objects are not included in previous on clicks.
$("a.ajax-link").on("click", function(e) {
e.preventDefault();
$("#body-element").load(this.href);
});
... you could also ... turn off the old watcher.
$("a.ajax-link").off("click");
UPDATE:
Try ...
$("a.ajax-link")
.off("click")
.on("click", function(e) {
e.preventDefault();
$("#body-element").load(this.href);
});
You have to apply the click listener on the newly added link as well, as the element has to be loaded into the DOM when applying the click listener in order for it to be applied. However, if you just re-run the same code you'll like run into the problem of having two event listeners on the first ajax-link.
Try this:
// We still use on doc ready to be sure the
// first link is present before applying listener
$(function()
{
// Reset all listeners on ajax-links and
// then apply listeners via function
resetAjaxLinks();
});
// This function will remove any ajaxlink
// listeners and then apply them correctly
function resetAjaxLinks()
{
// Remove event listeners and then on click....
$("a.ajax-link").off('click').on("click", function(e)
{
// Prevent default link action...
e.preventDefault();
// Load in your content...
$("#body-element").load(this.href);
// Once content is loaded in, reset event listeners!
resetAjaxLinks();
});
}
EDIT: This is not the best method for this. Instead, use event delegation as specified by this answer.

JQuery/ Jquery Mobile - best way to remove instance of class from div by toggling

I'm using JQuery mobile framework here, so i've got two 'pages' which in reality both exist in one HTML document. You can navigate between the two via the hamburger menu icon on the top left.
There is an events page. each events has an 'add to favourites' button. when clicked the event populates the favourites page. I'm doing this by cloning the div class.
var add = $('.add-to-fav');
add.on('click', function(){
//change button status
if ($(this).text() == "Add to favourites")
{
$(this).text("Remove from favourites");
$(this).closest(".event-block").clone().appendTo('#fav-list');
} else {
$(this).text("Add to favourites");
//get this instance of event block and remove from #fav-list
}
});
My issue comes with trying to remove (or unfavourite) the event by clicking again on the same button. I want this to be achievable from both the events page and the favourites page.
What's the most elegant way to achieve this?
here's a codepen - i've tried to remove as much unrelated code as possible
http://codepen.io/MartinBort/pen/EajBXB/
First of all, you are using the same panel for both pages with same ID. Either use an external panel or give each one a unique ID. If you plan to use an external panel, place it outside any page and initialize it manually.
$(function () {
$("#menu-panel").panel().enhanceWithin();
});
To add listeners, use pagecreate it fires once per page. This way, you can assign different functions for buttons based on containing page. Use event.target to target buttons .add-fav within created page not other ones in DOM.
You can remove "Event" from favourites page from public-events page by retrieving its' header's text since you aren't using IDs' or classes to differentiate between events.
$(document).on("pagecreate", "#public-events", function (event) {
$('.add-to-fav', event.target).on('click', function () {
if ($(this).text() == "Add to favourites") {
$(this).text("Remove from favourites");
$(this).closest(".event-block").clone().appendTo('#fav-list');
} else {
$(this).text("Add to favourites");
/* retrieve event title */
var eventTitle = $(this).closest(".event-block").find("h2").text();
/* loops through event blocks in favourite page */
$('#favourites #fav-list .event-block h2').each(function () {
if ($(this).text() == eventTitle) {
/* remove matching event */
$(this).closest(".event-block").remove();
}
});
}
});
}).on("pagecreate", "#favourites", function (event) {
$('.add-to-fav', event.target).on('click', function () {
$(this).closest(".event-block").remove();
});
});
Demo

using preventDefault() with on() in jQuery AJAX tabs

I have a set of jQuery UI AJAX tabs that load individual .php pages when they are clicked. All of my styling, etc. conveys, because the pages that hold the tabs widget provide the already linked CSS, and scripts. When it comes to the actual pages that load when clicking on the tabs however, I can't seen to get preventDefault() to work with .on() on these newly created DOM elements.
I'm using jQuery BBQ with my tabs so I can't have "#"s being appended to the URL. This is caused when links within the tab panels are clicked.
I've been able to successfully use preventDefault() on DOM elements that are initially loaded, but not ones that are being fetched into the tabs widget via AJAX.
My function for a content toggler is...
$(function(){
$(".showMoreOrLess").on('click', (function() {
if (this.className.indexOf('clicked') != -1 ) {
$(this).removeClass('clicked');
$(this).prev().slideUp(500);
$(this).html("Read More" + "<span class='moreUiIcon'></span>");
}
else {
$(this).addClass('clicked');
$(this).prev().slideDown(500);
$(this).html("See Less" + "<span class='lessUiIcon'></span>");
}
}));
});
I'd like to combine the preventDefault() from this function into it.
// prevents default link behavior on BBQ history stated tab panels with "showMoreOrLess" links
$(".showMoreOrLess").click(function (event)
{
event.preventDefault();
//here you can also do all sort of things
});
// /prevents default behavior on "showMoreOrLess" links
I've tried several ways using .on("click", function(work)), etc. I've used .on() in a separate function and also tried to combine it in the first function above. Does anyone know what I'm doing wrong? The code works on tab content that is static, just not content loaded via AJAX. Any help would be greatly appreciated. Can't seem to figure this out. Thanks in advance.
the part $(".showMoreOrLess").click just applies to already accessable links on your page
try to use event delegation (here the clicks are captured on an every time existing element and you just pass the selector it is watching for... as a nice side effect you save listeners
$(document).on("click", ".showMoreOrLess", function(event) {
event.preventDefault();
//here you can also do all sort of things
});
rather than document use a certain id from your page $("#myContainerId") (EDIT: of course the elements you are clicking on need to be inside of the element with the id)
$("body").on('click', ".showMoreOrLess", function(event) {
event.preventDefault();
var self = $(this);
if (self.hasClass('clicked')) {
self.html("Read More" + "<span class='moreUiIcon'></span>").removeClass('clicked').prev().slideUp(500);
}else {
self.html("See Less" + "<span class='lessUiIcon'></span>").addClass('clicked').prev().slideDown(500);
}
});

Categories

Resources