Run .each() based on elements within specific tab - javascript

I've got a layout with something to this effect:
<div id="issueWidgets">
<div class="column">
<div class="portlet" id="boxIssues">
<div class="portlet-header">Some Title</div>
<div class="portlet-content">Some content</div>
</div>
</div>
<div class="column">
<div class="portlet" id="boxStats">
<div class="portlet-header">Some Stats Title</div>
<div class="portlet-content">Some Stats content</div>
</div>
</div>
</div>
<div id="projectWidgets">
<div class="column">
<div class="portlet" id="boxProjects">
<div class="portlet-header">Some Title</div>
<div class="portlet-content">Some content</div>
</div>
</div>
</div>
<div id="userWidgets">
<div class="column">
<div class="portlet" id="boxUsers">
<div class="portlet-header">Some Title</div>
<div class="portlet-content">Some content</div>
</div>
</div>
<div class="column">
<div class="portlet" id="boxUsers2">
<div class="portlet-header">Some Title</div>
<div class="portlet-content">Some content</div>
</div>
</div>
</div>
And on and on...Each main div serves as a jquery ui tab.
So basically I've got tabs (as divs with the following IDs: issueWidgets, projectWidgets, and userWidgets). These divs contain some portlet divs (these are just divs that act as widgets within each column (div class=column).
I've got code that looks for each class with name column to create some cookie information like so:
// function that writes the list order to a cookie
function saveOrder() {
$(".column").each(function(index, value){
var colid = value.id;
var cookieName = "cookie-" + colid;
// Get the order for this column.
var order = $('#' + colid).sortable("toArray");
// For each portlet in the column
for ( var i = 0, n = order.length; i < n; i++ ) {
// Determine if it is 'opened' or 'closed'
var v = $('#' + order[i]).find('.portlet-content').is(':visible');
// Modify the array we're saving to indicate what's open and
// what's not.
order[i] = order[i] + ":" + v;
}
$.cookie(cookieName, order, { path: "/", expiry: new Date(2016, 1, 1)});
});
}
The issue I am having is this runs for every element with class name column. So basically it goes out to issueWidgets and finds each column, and goes to projectWidget and finds any element with class=column, and finally to userWidgets and also finds any element with class=column and runs the above code.
I want to limit it to run based on the its parent widget div. So for instance I'd want it to run only on issueWidgets when I am looking at the issueWidgets tab. Remember these are actually tabs (jquery ui). If I'm in the projectWidgets tab I'd want to find all elements with class=column but ONLY on the projectWidgets tab not all the other tabs...etc etc.
So basically my function should take in the tab either issueWidgets, projectWidgets, userWidgets and work .each only located within those tabs.
edit
I'm not sure how to modify this to use find(), since the original code within document ready looks like this:
$(".column").sortable({
connectWith: ".column",
handle: ".portlet-header",
cancel: ".portlet-toggle",
placeholder: "portlet-placeholder ui-corner-all",
stop: function () { saveOrder(); }
});
$(".portlet")
.addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
.find(".portlet-header")
.addClass("ui-widget-header ui-corner-all")
.prepend("<span class='ui-icon ui-icon-minusthick portlet-toggle'></span>")
.end()
.find(".portlet-content");
restoreOrder();
$(".portlet-header .ui-icon").hover(
function () { $(this).addClass("ui-icon-hover"); },
function () { $(this).removeClass('ui-icon-hover'); }
);
$(".portlet-toggle").click(function () {
var icon = $(this);
icon.toggleClass("ui-icon-minusthick ui-icon-plusthick");
icon.closest(".portlet").find(".portlet-content").toggle();
saveOrder();
});

Access to the parent of that element and compare.
$(".column").each(function(index, value){
// If isn't the parent you're looking for..
if($(this).parent().attr('id') != 'projectWidgets'){
continue;
}
// the rest of your code
}
EDIT: According to the answers below, new code:
I'm assuming that the code you post (var selectedTabIndex = $('#tabs').tabs('option', 'active');) gives the HTML content, am I right?
If so, use instead something like this:
$tabSelected = $('#tabs').tabs('option', 'active');
and all you have to do is find the .column.
$tabSelected.find('.column').each(function(index, value){
});
EDIT 2: According to the jQuery Tab documentation:
Since the activate event is only fired on tab activation, it is not
fired for the initial tab when the tabs widget is created. If you need
a hook for widget creation use the create event.
So, take care, you might need create event also. The below code should do the trick.
$('#tabs').tabs({
activate: function(event, ui){
$(this).find('.column').each(function(i, value){
});
}
});

Related

Jquery access attributes where the data attribute is substring

Thanks a million for taking the time to read this :) First let me show you the example code I am dealing with:
<div id="section-0000001" class="section" data-section-223344="{"id":"123456", "type":"product"}">
<div>Section 0000001</div>
</div>
<div id="section-0000002" class="section" data-section-223344="{"id":"123456", "type":"category"}">
<div>Section 0000002</div>
</div>
<div id="section-123456" class="section" data-section-223344="{"id":"123456", "type":"showcase-product"}">
<div>Section 123456</div>
</div>
<div id="section-234567" class="section" data-section-223344="{"id":"234567", "type":"showcase-product"}">
<div>Section 234567</div>
</div>
<div id="section-345678" class="section" data-section-223344="{"id":"345678", "type":"showcase-product"}">
<div>Section 345678</div>
</div>
<div id="section-0000003" class="section" data-section-223344="{"id":"123456", "type":"image"}">
<div>Section 0000003</div>
</div>
What I want to achieve, is to add a class to all divs with the type 'showcase-product'. I do not have access to the original code so I need to do this with Jquery. There is unfortunately not a unique class to filter these out and the only thing unique is the showcase-product but as you can see that is part of an object within the data attribute and I cannot figure out how to access it.
If the attribute data-section-xxxxxx was the same, this would be much easier but each div has a unique value on the end but the first part data-section- is always the same.
I can loop through the divs with this:
$('.section').each(function(){
for(data in $(this).data())
console.log(data);
});
But I cannot figure out a way to filter out only the divs with type = showcase-product.
I also tried a different approach:
$( ".section" ).each(function( i ) {
element=this;
$.each(this.attributes, function() {
if(this.name.indexOf('data-section') != -1)
$(element).addClass("myClass");
});
});
This adds the class but it also adds it to the ones without type = showcase-product such as type = image or type = category.
I guess it might be something like
this.name.type.value.indeOf('data-section') != 1
But I am not sure of the correct syntax or how to access it especially since type is not the value, it's an object within the value.
Any help appreciated.
See this approach; what it does is explained in the comments:
$(".section").each(function(i, element) {
// get dataset values
var dataValues = Object.values(element.dataset);
// find if has type using a regular expression
var foundType = false;
for (var j = 0; j < dataValues.length; j++) {
if (dataValues[j].match(/\"type\":\"showcase-product\"/)) {
foundType = true; // one dataset value matched!
}
}
// skip this element if no match
if (!foundType) return;
// do your stuff with showcase-product here:
console.log(element, 'found!');
$(element).addClass("myClass");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="section-0000001" class="section" data-section-223344='{"id":"123456", "type":"product"}'>
<div>Section 0000001</div>
</div>
<div id="section-0000002" class="section" data-section-223344='{"id":"123456", "type":"category"}'>
<div>Section 0000002</div>
</div>
<div id="section-123456" class="section" data-section-223344='{"id":"123456", "type":"showcase-product"}'>
<div>Section 123456</div>
</div>

How do i apply a function to only a specific div in a collection of divs generated by foreach loop?

When i click on SHOW MORE in one of the divs generated, in every div the footer div shows up with options Test1, Test2. I want the function to apply to the div im clicking on only. Help please :(
#foreach ($articles as $article)
<div class="row">
<div class="panel-heading">{{$article->title}}</div>
<div class="panel-body">{{$article->content}}</div>
<div class="panel-footer">
<div class="more" onclick="showPortals()">
Show More</div>
<div class="other_sources">Other Sources:
Test 1,
Test 2
<span class="less" onclick="hidePortals()">Show Less</span>
</div>
</div>
</div>
#endforeach
<script>
function showPortals() {
$(".other_sources").show();
$(".more").hide();
}
function hidePortals() {
$(".other_sources").hide();
$(".more").show();
}
</script>
Send the current element to the method
<div class="more" onclick="showPortals(this)">
<span class="less" onclick="hidePortals(this)">Show Less</span>
Use jquery to and hide/show the desired elements
function showPortals(element) {
var $panelFooter = $(element).closest('.panel-footer');
$panelFooter.find(".other_sources").show();
$panelFooter.find(".more").hide();
}
function hidePortals(element) {
var $panelFooter = $(element).closest('.panel-footer');
$panelFooter.find(".other_sources").hide();
$panelFooter.find(".more").show();
}
You can access the object you’re clicking via this object. You can pass it to your function:
<div class="more" onclick="showPortals(this)">
<span class="less" onclick="hidePortals(this)">Show Less</span>
Once you have the object representing your element (here, it will be div and span respectively), you can wrap it inside $ to get a jQuery object. Then, you can use .closest('.panel-footer') on the jQuery object to get your panel footer, and .find(selector) to find relevant objects inside the current panel-footer:
function showPortals(clickedElement) {
var $panelFooter = $(clickedElement).closest('.panel-footer');
$panelFooter.find(".other_sources").show();
$panelFooter.find(".more").hide();
}
function hidePortals(clickedElement) {
var $panelFooter = $(clickedElement).closest('.panel-footer');
$panelFooter.find(".other_sources").hide();
$panelFooter.find(".more").show();
}
However, onclick="hidePortals(this)" is not a recommended way of doing things because you’re mixing JavaScript with HTML. Instead, it’s recommended that you remove onclick="..." handlers and use jQuery’s .click handler, like this:
<script>
$(function() {
$('.more').click(function () {
var $panelFooter = $(this).closest('.panel-footer');
$panelFooter.find(".other_sources").show();
$panelFooter.find(".more").hide();
});
$('.less').click(function () {
var $panelFooter = $(this).closest('.panel-footer');
$panelFooter.find(".other_sources").hide();
$panelFooter.find(".more").show();
});
});
</script>
Change your selector to reflect each record's id.
#foreach ($articles as $article)
<div class="row">
<div class="panel-heading">{{$article->title}}</div>
<div class="panel-body">{{$article->content}}</div>
<div class="panel-footer">
<div class="more-{{$article->id}}" onclick="showPortals({{$article->id}})">
Show More</div>
<div class="other_sources-{{$article->id}}">Other Sources:
Test 1,
Test 2
<span class="less" onclick="hidePortals()">Show Less</span>
</div>
</div>
</div>
#endforeach
<script>
function showPortals(id) {
$(".other_sources-"+id).show();
$(".more-"+id).hide();
}
function hidePortals() {
$(".other_sources").hide();
$(".more").show();
}
</script>
Add a click event to every div:
One way:
$( document ).on( "click", 'div', doSomething);
But if you are trying on an specific id, you may change your selector.

Dynamic jQuery Waypoints Loop

I'm struggling with the syntax for a loop that goes through and dynamically sets jQuery Waypoints.
Currently I have this code -
HTML Markup
For each 'process-anchor' I want to create a jQuery Waypoint
<div class="container">
<div class="process-anchor-1"></div>
<div class="process-anchor-2"></div>
<div class="process-anchor-3"></div>
<div class="process-anchor-4"></div>
<div class="process-anchor-5"></div>
</div>
<div class="image-list">
<div class="process-image"><img src="test.jpg"/></div>
<div class="process-image"><img src="test.jpg"/></div>
<div class="process-image"><img src="test.jpg"/></div>
<div class="process-image"><img src="test.jpg"/></div>
<div class="process-image"><img src="test.jpg"/></div>
</div>
Javascript Code (currently)
var process_fixed_anchor_1 = $('.process-anchor-1').waypoint({
handler: function(direction) {
$(".process-image-1").toggleClass("fade-in");
}
});
I want to run through and create waypoints however the amount of anchor DIV's may change. How could I edit the above code to be dynamic so I don't have to be specific every time?
Thanks,
DIM3NSION
Still just a bit unclear on what you're trying to accomplish, but here's how I would dynamically assign waypoints to a page given an unknown number of anchor divs:
Markup
I have added class="trigger-anchor" to your anchor divs with the hopes of finding a more approachable way to target those divs. Also put a common class on your process-image-* rather than letting them all be unique.
<div class="container">
<div class="process-anchor-1" class="trigger-anchor">
<div class="process-image"><img src="test.jpg"/></div>
</div>
<div class="process-anchor-2" class="trigger-anchor">
<div class="process-image"><img src="test.jpg"/></div>
</div>
<div class="process-anchor-3" class="trigger-anchor">
<div class="process-image"><img src="test.jpg"/></div>
</div>
<div class="process-anchor-4" class="trigger-anchor">
<div class="process-image"><img src="test.jpg"/></div>
</div>
<div class="process-anchor-5" class="trigger-anchor">
<div class="process-image"><img src="test.jpg"/></div>
</div>
</div>
JavaScript
I'll run an .each() on the elements where class="trigger-anchor" to build by waypoints. This way I don't have to declare var loops = 5; or anything like that.
<script type="text/javascript">
// Wait until our DOM is ready
$( document ).ready( function() {
// Keep Track of how many we make and store
// our instances in an array to access if
// we need to later
var anchors = array();
$( '.trigger-anchor' ).each( function() {
var tmp_instance = $( this ).waypoint({
handler: function(direction) {
$( this ).children('process-image').toggleClass("fade-in");
}
});
anchors.push( tmp_instance );
} );
} );
</script>
See if that helps to get you in the right direction.
According to Waypoints website http://imakewebthings.com/waypoints/guides/jquery-zepto/, you can accomplish the same thing as follows (waypoints will loop and fill your array with each instance). I used this method on my site.
//within your document.ready function
var anchors = array();
anchors = $( '.trigger-anchor' ).waypoint({
handler: function(direction) {
$(this).children('process-image').toggleClass("fade-in");
}
});
//ALTERNATE METHOD
//you can also include your handler in the waypoint call
anchors = $( '.trigger-anchor' ).waypoint(function(){
$(this).children('process-image').toggleClass("fade-in");
});

jQuery - how to run one event while delaying another?

I'm a bit of a jQuery newbie, so forgive me if this seems a bit simple! I am setting up a sliding header system, which works very much like an accordion menu, however the links to open and close the elements are in a different part of the HTML, so all the accordion tutorials I found didn't work.
I have got this so far: HTML:
<div class="drawer" id="drawer_about"></div>
<div class="drawer" id="drawer_contact"></div>
<div class="drawer" id="drawer_hire"></div>
<div class="drawer" id="drawer_social"></div>
...
<ul class="navigation">
<li><span>About Me</span></li>
<li><span>Get In Touch</span></li>
<li><span>Hire Me</span></li>
<li><span>Social Networks</span></li>
</ul>
And jQuery:
$(document).ready(function(){
$("#drawer_about").hide();
$("#drawer_contact").hide();
$("#drawer_hire").hide();
$("#drawer_social").hide();
lastBlock = ("#drawer_hire");
$('.show_hide_about').click(function(){
$("#drawer_about").slideToggle(700);
$(lastBlock).hide(700);
lastBlock = ("#drawer_about");
});
$('.show_hide_contact').click(function(){
$("#drawer_contact").slideToggle(700);
$(lastBlock).hide(700);
lastBlock = ("#drawer_contact");
});
$('.show_hide_hire').click(function(){
$("#drawer_hire").slideToggle(700);
$(lastBlock).hide(700);
lastBlock = ("#drawer_hire");
});
$('.show_hide_social').click(function(){
$("#drawer_social").slideToggle(700);
$(lastBlock).hide(700);
lastBlock = ("#drawer_social");
});
});
Am I going OTT here? is there a simpler way to do this?
The main problem I'm having is it all works, however if the ABOUT ME panel is open and the user clicks the HIRE ME link, I get a weird effect. What I'd want in this situation is for the ABOUT ME panel to fold up, then the HIRE ME panel to fold down.
Hope that makes sense, thanks folks,
Alex
I'd set up the links like this: asdf
Then you all you need is:
$('.show').click(function(ev) {
var $visibleDrawer = $('.drawer:visible').eq(0); // make sure to get only one (or 0) drawer
// set currentSection to the drawer's id or empty if no drawer was found
var currentSection = $visibleDrawer.length?$visibleDrawer.attr('id').replace('drawer_',''):'';
$('.drawer').slideUp(700);
$('a.show').removeClass('active'); // reset all link classes
(function(clickedSection, $link){ //<-- pass the active link to have access to it inside the closure
if(currentSection != clickedSection){
$link.addClass('active'); // set active class on clicked link
setTimeout(function() {
$('#drawer_'+clickedSection).slideDown(700);
}, ($visibleDrawer.length?700:0)); // set the timeout to 0 if no drawer visible
}
})($(this).data('section'),$(this)); //<--
ev.preventDefault();
});
using .animate() you can parse a callback function which will be executed at the end of the animation, or you can use .queue() to keep track of the point of execution against and element. Some pseudo code of the first way
$('#foo').animate(function() {
// do stuff with foo
}, duration, easing, function() {
$('#bar').animate(function() {
// do stuff with bar
})
});
Here is a link to how it works on jsFiddle (Note that you should choose framework to be jQuery)
I think this would work with you :
$(document).ready(
function(){
$('.header').click(function(){
//To hide all other contents
$('.content').slideUp('slow');
var num=$(this).attr('id').split('_')[1];
//And show this one ..
$('#content_'+num).slideDown('slow');
});
}
);
HTML should look like this :
<div class="header" id="title_111">Category 1</div>
<div class="content" id="content_111">
</div>
<div class="header" id="title_112">Category 2</div>
<div class="content" id="content_112">
</div>
<div class="header" id="title_113">Category 3</div>
<div class="content" id="content_113">
</div>
<div class="header" id="title_114">Category 4</div>
<div class="content" id="content_114">
</div>
<div class="header" id="title_115">Category 5</div>
<div class="content" id="content_115">
</div>
<div class="header" id="title_116">Category 6</div>
<div class="content" id="content_116">
</div>

jQuery Pagination Plugin

Hopefully this is something that will be easy to remedy. I'm having a bit of an issue understanding the jQuery Pagination plugin.
Essentially, all I am trying to do is load a PHP file, and then paginate the results. I'm attempting to go off their example, but I am not yielding the results I'm looking for.
Here's the JavaScript:
function pageselectCallback(page_index, jq){
var new_content = $('#hiddenresult div.result:eq('+page_index+')').clone();
$('#Searchresult').empty().append(new_content);
return false;
}
function initPagination() {
var num_entries = $('#hiddenresult div.result').length;
// Create pagination element
$("#Pagination").pagination(num_entries, {
num_edge_entries: 2,
num_display_entries: 8,
callback: pageselectCallback,
items_per_page:3
});
}
$(document).ready(function(){
$('#hiddenresult').load('load.php', null, initPagination);
});
Here's my HTML (after the PHP has been loaded):
<div id="Pagination" class="pagination"> </div>
<br style="clear:both;" />
<div id="Searchresult"> </div>
<div id="hiddenresult" style="display:none;">
<div class="result">Result #1</div>
<div class="result">Result #2</div>
<div class="result">Result #3</div>
<div class="result">Result #4</div>
<div class="result">Result #5</div>
<div class="result">Result #6</div>
<div class="result">Result #7</div>
</div>
Basically, I am trying to show "3" items per page, but this is not working. I'm assuming that somewhere, I am going to need to create a for loop in my JS, but I'm confused on how to do so. The documentation can be found here.
You don't even need to use a for loop, just use jQuery's slice() method and a bit of math.
I've hosted a working demo on JS Bin: http://jsbin.com/upuwe (Editable via http://jsbin.com/upuwe/edit)
Here's the modified code:
var pagination_options = {
num_edge_entries: 2,
num_display_entries: 8,
callback: pageselectCallback,
items_per_page:3
}
function pageselectCallback(page_index, jq){
var items_per_page = pagination_options.items_per_page;
var offset = page_index * items_per_page;
var new_content = $('#hiddenresult div.result').slice(offset, offset + items_per_page).clone();
$('#Searchresult').empty().append(new_content);
return false;
}
function initPagination() {
var num_entries = $('#hiddenresult div.result').length;
// Create pagination element
$("#Pagination").pagination(num_entries, pagination_options);
}

Categories

Resources