Refresh child in dynamically created nested accordion - javascript

I am trying to append items to a nested accordion dynamically when the user clicks a button. I am using the following code to create a nested accordion:
$(".accordion").accordion({
collapsible: true,
autoHeight: false,
animated: 'swing',
heightStyle: "content",
changestart: function(event, ui) {
child.accordion("activate", false);
}
});
var child = $(".child-accordion").accordion({
active:false,
collapsible: true,
autoHeight: false,
animated: 'swing'
});
In order to do this, I have found that I need to refresh the accordion using the following:
$('.accordion').accordion("refresh");
My problem is that when I try to refresh the inner accordion using:
$('.child-accordion').accordion("refresh");
I get the following:
Error: cannot call methods on accordion prior to initialization; attempted to call method 'refresh'
When I inspect the div that should be refreshed it has the following ids/classes:
DIV#shelf0sections.child-accordion.ui-accordion-content.ui-helper-reset.ui-...
I tried using the selector:
$('#shelf0sections .child-accordion').accordion("refresh");
instead which doesn't give an error, but nothing happens visually.
jsFiddle: http://jsfiddle.net/Mw9SA/3/
(Note that the first element in the list is just an example to see the nested accordion working, If you try to add sections to it, it won't work. Use the '+Shelf' button, then open the new accordion and use the '+Section' button.)

How about a more modular approach?
Fiddle or it didnt happen: http://jsfiddle.net/Varinder/24hsd/1/
Explanation
The idea is ( the same ) to create a brand new accordion element on the fly with correct events attached and appended somewhere in the DOM.
It's generaly more managable to have repeater HTML markup abstracted away in a template somewhere in DOM and use JS to reference it rather that building it from a string.
Heres the accordion template in the markup:
<div class="template">
<div class="accordion">
<h3 class="accordion-title">accordion title</h3>
<div class="accordion-content">
accordion content
</div>
</div>
</div>
Heres the full HTML markup - just in case:
<div class="page">
</div>
<div id="addShelf" class="button">+ Shelf</div>
<div id="addSection" class="button">+ Section</div>
<div class="template">
<div class="accordion">
<h3 class="accordion-title">accordion title</h3>
<div class="accordion-content">
accordion content
</div>
</div>
</div>
JS
Starting off by storing different accordion configurations:
var shelfConfig = {
collapsible: true,
autoHeight: false,
animated: "swing",
heightStyle: "content"
}
var shelfSectionConfig = {
active:false,
collapsible: true,
autoHeight: false,
animated: "swing"
}
Kepping a track of current accordion number and current accordion section number ( number of sections inside last accordion ) - might come in handy if you require a feature to remove an accordion shelf
var currentShelfNumber = 0;
var currentShelfSectionNumber = 0;
Chaching DOM elements, notice reference to the tempalte div
var $page = $(".page");
var $accordionTemplate = $(".template").children();
var $addSection = $("#addSection");
var $addShelf = $("#addShelf");
Creating a helper function that simply returns a cloned copy of the accordion template from the DOM
function getAccordionTemplate() {
return $accordionTemplate.clone();
}
Main function generateAccordion - it takes two arguments, accordionNumber to append current number in titles etc and accordionType to find out which accordion configuration to use.
With those parameters it will return a brand-spanking-new accordion with appropriate events attached which can then be append to the DOM
function generateAccordion( number, accordionType ) {
var $accordion = getAccordionTemplate();
var accordionTitle = "twerking bieber?";
if ( accordionType == "shelf" ) {
accordionTitle = "Shelf " + number;
} else {
accordionTitle = "Shelf Section";
}
$accordion.find("h3").text( accordionTitle );
var $accordionWithEvents = attachAccordionEvents( $accordion, accordionType );
return $accordionWithEvents;
}
Notice the call to another function attachAccordionEvents as the name suggests - this fella will attach events to the accordion element.
function attachAccordionEvents( $accordionElement, accordionType ) {
if ( accordionType == "shelf" ) {
$accordionElement.accordion( shelfConfig );
} else {
$accordionElement.accordion( shelfSectionConfig );
}
return $accordionElement;
}
Another helper function which makes sure "add section" button doesnt show up if there is no accordion shelf for it to work on
function manageSectionButton() {
if ( $page.children().length > 0 ) {
$addSection.show();
} else {
$addSection.hide();
}
}
Finaly events and logic:
$addShelf.on("click", function(e) {
e.preventDefault();
var newShelfNumber = currentShelfNumber + 1;
var $shelfElement = generateAccordion( newShelfNumber, "shelf" );
currentShelfNumber = newShelfNumber;
$page.append( $shelfElement );
manageSectionButton();
});
$addSection.on("click", function(e) {
e.preventDefault();
var newShelfSectionNumber = currentShelfSectionNumber + 1;
var $shelfSectionElement = generateAccordion( newShelfSectionNumber, "section" );
var $activeShelfElement = $page.children().last().find(".accordion-content");
$activeShelfElement.append( $shelfSectionElement );
});
... And thats about it.
Hope this helps,
Cheers

Related

view all products with the replicate of the list of products presented in html in un click JQuery

I've this code https://jsfiddle.net/oj20rwk3/
The goal is to create a 'View all' button under the product sheets which, when clicked, adds clones of the latter at the bottom of the page, filling all available spaces (in this case replicate the products).
When I click a button "view all", I want to see all products with the replicate of the list of products presented in html in alphabetical order. Can you help me to move on?
ACC.plp = {
_autoload: [
["hideLinkOnSearchBox", $('.js-hide').length > 0],
"viewAll"
],
hideLinkOnSearchBox: function () {
$(window).on('scroll', function() {
scroll_top = $(this).scrollTop();
if(scroll_top <=1000) {
$('.js-hide').removeClass("d-none");
}
else if( scroll_top >1000){
$('.js-hide').addClass("d-none");
}
});
},
viewAll: function() {
$(".plp-products-container").ready(function(){
$(".button-row [name=viewALL]").click(function(){
$(".product-item").show();
});
$(".button-row [name=viewALL]").click(function(){
$(".product-item").hide();
});
});
},
}
Thank you for helping
You would need a wrapped element for all your product-item so that we can easily clone its children with matching class name and append to the wrapper.
let cloned = false;
$('button[name=viewALL]').click(function(){
/* Below check is to prevent cloning more than once */
if (cloned === false ) {
cloned = true;
$(".product-wrapper").children('.product-item').clone().appendTo(".product-wrapper");
}
});
<div class="product-wrapper">
<div class="product-item">.A.</div>
<div class="product-item">.B.</div>
<div class="product-item">.C.</div>
</div>
Jsfiddle - https://jsfiddle.net/kaop69zg/

Opening Accordion from external link

I found some code that might work, but I can't decipher how to change it so it works with my current accordion structure.
Here is the fix I had found:
$(function () {
$(".tab-content").hide().first().show();
$(".inner-nav li:first").addClass("active");
$(".inner-nav a").on('click', function (e) {
e.preventDefault();
$(this).closest('li').addClass("active").siblings().removeClass("active");
$($(this).attr('href')).show().siblings('.tab-content').hide();
});
var hash = $.trim( window.location.hash );
if (hash) $('.inner-nav a[href$="'+hash+'"]').trigger('click');
});
and Here is part of the accordion on my page:
<div class="container">
<div class="accordion-trigger">
<h3>Wedding</h3>
</div>
<div class="accordion-container">
<p>
<tab>
<bgcolor class="shadow">
<font color="black" size="+1"><strong>Wedding Packages PDF</strong></font>
</bgcolor>
</tab>
</p>
<hr class="separator1">
</div>
Inside the div container are several other div class="accordion-trigger"'s that get activated when you click. Of course, only the first accordion is active on the page on load.
The fix above is supposed to check for a hash ID and do a Click event on the hash id.
Since you are using CSS you haven't provided, to open navigation:
$(function () {
var hash = parseInt($.trim(window.location.hash)), // hash as number
$triggers = $('.accordion-trigger'); // list of triggers
if (hash) { // if hash exists
if($triggers.length >= hash) { // if not greater than number of triggers
$triggers.eq(hash+1).trigger('click'); // open n-th item
}
}
});
example.com/site/#4 should open 4th item, if it exists.
That's terrible code, by the way.

JQuery closest() + find() tree traversal

Given a structure like this:
<div class="portlet">
<div class="portlet-config">
<p>Some configuration</p>
</div>
<div class="portlet-header">Configurable portlet</div>
<div class="portlet-content">This has a configuration window. Click on pencil icon to open.</div>
</div>
First, I append these DIVs to portlet-header (to display some buttons)
<div class="portlet-button-container">
<div class="portlet-button portlet-btn-delete ui-icon ui-icon-close"></div>
<div class="portlet-button portlet-btn-toggle ui-icon ui-icon-minusthick"></div>
<div class="portlet-button portlet-btn-config ui-icon ui-icon-pencil"></div>
</div>
Then I apply a jquery-ui dialog() plugin to the portlet-config DIVs
$(".portlet-config").dialog({
autoOpen: false,
show: {
effect: "fade",
duration: 200
},
hide: {
effect: "fade",
duration: 500
},
modal: true,
buttons: {
Ok: function () {
$(this).dialog("close");
}
}
});
Then I add come click handlers
$(".portlet-btn-toggle").click(function () {
var icon = $(this);
icon.toggleClass("ui-icon-minusthick ui-icon-plusthick");
icon.closest(".portlet").find(".portlet-content").toggle();
});
$(".portlet-btn-delete").click(function () {
var icon = $(this);
icon.closest(".portlet").hide();
});
$(".portlet-btn-config").click(function () {
var icon = $(this);
icon.closest(".portlet").find(".portlet-config").dialog("open");
});
It seems that the portlet-config DIV could not be found when the user clicks on the pencil.
More precisely it seems that:
$(this) // OK, returns an object
$(this).closest(".portlet") // OK, returns an object
$(this).closest(".portlet").find(".portlet-config") // NOK, returns null
Here is a fiddle to reproduce the problem: http://jsfiddle.net/silenzioso/M6LmS/
Thanks in advance
Your call to $(".portlet-config").dialog is doing a little more than you expect it to. If you look in the DOM, you can see that the div has been moved out of its original location and added to the end of the document. Presumably it does this for the overlayed dialog effect.
You could consider putting a unique ID on the dialog div so that you can find it again. Perhaps you could use a data attribute to store the associated dialog div ID in the button.
<div class="portlet">
<div class="portlet-config" id="dialog1">
<p>Some configuration</p>
</div>
<div class='portlet-button' data-config="dialog1"></div>
</div>
...
var id = $(this).data('config');
var config = $('#'+id);
If You are dynamically creating new DOM elements in jQuery make sure You add event click on body or document or other element that is defined from the very first page display (I mean server response):
$('body').on('click', '.portlet-btn-config', function(e){
});

JQuery replace entire DIV using .load()

I want to refresh a <div> on the close of a jQuery UI Modal Dialog.
My code is:
var dialog = jQuery('#divPopup').dialog({
autoOpen: false,
height: 450,
width: 650,
modal: true,
open: function(event, ui) {
jQuery('body').css('overflow', 'hidden');
},
close: function(event, ui) {
jQuery('#divPopup').dialog('destroy').remove();
jQuery("#bodyId").load("http://www.xyz.com/ #bodyId");
}
});
But instead of replacing it, that adds the new <div> inside the old <div>:
<div id="bodyId">
<div id="bodyId">
New Response
</div>
</div>
I want to replace old div bodyId with new div bodyId.
Try to replace this:
jQuery("#bodyId").load("http://www.xyz.com/ #bodyId");
... with this:
jQuery("#bodyId").load("http://www.xyz.com/ #bodyId > *");
This works because you can use any selector after the URL. By using #bodyId > * instead of just #bodyId, you match everything that is inside the div, instead of the div itself.
You need this because .load() will not replace an element; it will append the result of the AJAX call to the element.
Alternatively, you could use .get() to load the data and manually perform the selection, like so:
$.get('http://www.xyz.com/', function(data) {
var newContent = $(data).find('#bodyId').children();
$('#bodyId').empty().append(newContent);
});
Examples of both methods are online here: http://jsfiddle.net/PPvG/47qz3/
You could also use jquery.get.
$.get('http://www.xyz.com/', function(data) {
$('#bodyId').html(data);
});
you may be use this code like
$('#bodyID').remove();
$('#bodyID').load();

Stuck on structure of this jquery plugin

I'm practicing jquery plugins and need help finishing this one, especially the outside skeleton.
Let's say I have this markup
<div class="tochange"></div>
<div class="tochange"></div>
<div class="tochange"></div>
and I want the plugin to add to div.tochange this markup
<div class="root">Root</div>
so that it's
<div class="tochange">
<div class="root">Root</div>
</div>
Then if the root is clicked, replace it with 2 divs so the markup looks like this
<div class="tochange">
<div class="child">Child</div>
<div class="child">Child</div>
</div>
If the child is clicked, it goes back to parent
<div class="tochange">
<div class="root">Root</div>
</div>
I'm following documentation but I don't know if I need methods for this. My guess is that I do but I can't finalize the structure of this plugin in my head. This is my first plugin and I thought a practical idea of my own is the best way to learn, but I'm stuck. Can someone who's done this before set me on the right track. I'm a little lost on this.
(function($){
$.fn.sample = function(options) {
var settings = {
'possibleparam1' : 'value1',
};
var methods = {
init: function( options ) { },
tochildren : function( ) { },
toparent : function( ) { },
};
return this.each(function() { /*(i) {*/
// If options exist, merge them with our default settings
if (options) {
$.extend(settings, options);
}
// plugin code goes here
});
};
})( jQuery );
You can use several methods:
Try $("field_name").update("New text"); or $(this).replaceWith.
I have something like this in my site and I'm using: (don't mind the func name - its my ajax callback)
function setOutput()
{
if(httpObject.readyState == 4)
{
document.getElementById('photos').innerHTML = "<div id=\"gallery\" clas.....</ul></div>";
}
}

Categories

Resources