applying jScrollPane to a div appended with ajax - jscrollpane

I have a tabbed widget that shows three separate loops. Under the third tabbed section which is hidden by default, I show a search that gives ajax results. My problem is that I can't figure how to apply jScrollPane to the container div of the results. Everytime the search is entered, the container div is emptied and new results are appended so I need to reapply it each time. Here is the code I'm using to trigger the search.
jQuery( function( $ ) {
// search filed
var $s = $( '#s' );
// the search form
var $sForm = $s.closest( 'form' );
console.log( $sForm );
$sForm.on( 'submit', function( event) {
event.preventDefault();
$.post(
T5Ajax.ajaxurl,
{
action: T6Ajax.action,
search_term: $s.val()
},
function( response ) {
$("#music-results").empty();
$("#music-results").append( response );
},
);
});
});
Now I have the basic call to setup jscrollpane for the other loops but that doesn't get applied to the div in question because it is hidden by default I guess.
$(document).ready(function(){
$('#music-results').jScrollPane({showArrows: true,autoReinitialise: false});
});
So how can I apply jscroll to the div each time it's emptied and new results are added?

You're right, jscrollpane doesn't apply to content that is not displayed (display:none).
To fix your problem, you simply need to call jscrollpane when the content is apended.
So instead of putting $('#music-results').jScrollPane({showArrows: true,autoReinitialise: false}); in the document ready(), simply put it after $("#music-results").append( response );. It should then work.
$.post(
T5Ajax.ajaxurl,
{
action: T6Ajax.action,
search_term: $s.val()
},
function( response ) {
$("#music-results").empty();
$("#music-results").append( response );
$('#music-results').jScrollPane({showArrows: true,autoReinitialise: false});
},
);
There is another way of doing what you want using the api.
Declare a global variable for the api, that will be available to all functions and then set it the document.ready()
var api;
$(document).ready(function(){
var element = $('##music-results').jScrollPane({showArrows: true,autoReinitialise: false});
api = element.data('jsp'); //you can now access the api through this variable.
});
Then, when you append the content to #music-results, simply reinitialize the scrollpane using the api.
$.post(
T5Ajax.ajaxurl,
{
action: T6Ajax.action,
search_term: $s.val()
},
function( response ) {
$("#music-results").empty();
$("#music-results").append( response );
api.reinitialise();
},
);
But remember, in order to do this, your content needs to be visible because jscrollpane needs to calculate the height and if it's not displayed, the height will not be found.
So if you append the content and the tab is not visible, simply reinitialize jscrollpane on the tab switch.
Hope this helps.

Related

Bigcommerce Infinite scroll not working after faceted search is made

Infinite scroll to our Custom PLP page is only working for page load alone. After selecting the faceted search, the infinite scroll feature is not working after the faceted response is appended. Please someone help us to have the Infinite scroll feature working after the faceted search result is appended.
Thanks in Advance
BigCommerce does not offer an Infinite Scroll feature by default, so I'm going to assume you followed this guide: https://medium.com/bigcommerce-developer-blog/how-to-add-infinite-scroll-to-category-pages-6c991750a8d5
The thing to keep in mind is that the category page gets reloaded via AJAX when a filter is applied. The fix for this should be as simple as duplicating the infiniteScroll function inside the this.facetedSearch function.
Look for the following code in your category.js file:
this.facetedSearch = new FacetedSearch(requestOptions, (content) => {
$productListingContainer.html(content.productListing);
$facetedSearchContainer.html(content.sidebar);
$('html, body').animate({
scrollTop: 0,
}, 100);
});
And add the infinite scroll function here as well:
this.facetedSearch = new FacetedSearch(requestOptions, (content) => {
$productListingContainer.html(content.productListing);
$facetedSearchContainer.html(content.sidebar);
function infiniteScroll() {
const elem = document.querySelector('.productGrid');
const infScroll = new InfiniteScroll(elem, {
// options
path: '.pagination-item--next .pagination-link',
append: '.product',
history: false,
});
return infScroll;
}
infiniteScroll();
$('html, body').animate({
scrollTop: 0,
}, 100);
});

AG-Grid render Bootstrap-Select as a dropdwon

I have implemented editable AG-Grid. In the grid, one of the column displays country of the player as shown below:
Now in last column, when user click on the cell, I want to display list of available countries as a dropdown.
Here by default AG-Grid displays normal dropdown. Which I want to replace with Bootstrap-select.
To achieve this, I have implemented custom selector and using Bootstrap-select library.
But when cell is clicked, Dropdown is not being rendered. I am not getting any error though in console.
Here is the code of my custom cell-editor:
var selectCellEdior = function () { };
selectCellEdior.prototype = {
init: function (params) {
selector = document.createElement('select');
for(var i = 0; i < params.values.length; i++) {
var option = params.values[i];
$('<option />', { value: option, text: option }).appendTo(selector);
}
this.cellSelector = selector;
$(this.cellSelector).selectpicker({ size: 'auto' });
},
getValue: function () {
return $(this.cellSelector).find('.btn-text').text();
},
getGui: function () {
return this.cellSelector;
},
destroy: function () {
$(this.cellSelector).remove();
}
};
Here is the Sample Code
I dont understand what is the issue.
The problem is the selectpicker jQuery method seems to add a display: none to the select element. Ag-Grid is adding it to the DOM you just can't see it. Additionally the getValue function is not returning the selected option's text.
The following changes to getValue and getGui will make the grid work:
...
getValue: function () {
return $(this.cellSelector).val();
},
getGui: function () {
this.cellSelector.style.display = 'block';
return this.cellSelector;
},
...
Here is the modified Plunker
For anyone looking at this now.... Ag-grid has a method afterGuiAttached that is called after the GUI has been attached to the Grid's cell. If you're noticing that the bootstrap-select still isn't "quite right" after following the instructions above, put ALL of the calls to selectpicker in afterGuiAttached instead of init or getGui. This will place the bootstrap-select into a div with the right classes it needs (dropdown, bootstrap-select, etc), and create all of the bootstrap-select elements that are properly shown/hidden.

Jquery-ias breaking clickable row

I am using jQuery 2.1.1, and have been using it to add 'clickable' to rows returned from a database using this:
<script type="text/javascript">
jQuery( function($) {
$('tbody tr[data-href]').addClass('clickable').click( function() {
window.location = $(this).attr('data-href');
});
});
</script>
That has been working fine. I have now added jquery-ias (2.1.2), and only the first page of returned results has clickable rows.
My jquery-ias code is as follows:
<script type="text/javascript">
$(document).ready(function() {
// Infinite Ajax Scroll configuration
jQuery.ias({
container : '.wrap', // main container where data goes to append
item: '.item', // single items
pagination: '.nav', // page navigation
next: '.nav a', // next page selector
negativeMargin: 250,
});
});
</script>
Jquery-ias is working fine, the pages are loading as needed, but the resultant rows are not clickable.
Inspecting the page in Chrome shows that the subsequently loaded rows have not had the clickable attribute added.
The relevant row in the php is this:
<tr class='resultsrow item' <?php echo "data-href='carddetail.php?setabbrv={$row['setcode']}&number={$row['number']}&id={$row[1]}'"; ?>>
All works fine if I use either, but how do I get them to play nicely together?
EDIT.....
OK, I have worked around it using the jquery-ias built-in pageChange event.
jQuery.ias().on('pageChange', function(pageNum, scrollOffset, url) {
var delay=1000;
setTimeout(function(){
jQuery( function($) {
$('tbody tr[data-href]').addClass('clickable').click( function() {
window.location = $(this).attr('data-href');
});
});
},delay);
});
This way when ias finds a page change, it waits a second for the page structure to load, and then applies the clickable class.
I can't see this working if it's waiting for images though... doesn't have to for this instance, but there's got to be a better way to do this.
Any pointers?
the better way would be to use the rendered event, for example:
jQuery.ias().on('rendered', function(item) {
var $items = jQuery(items);
$items.each(function() {
jQuery('tr[data-href]', $this).addClass('clickable').click(function() {
window.location = $(this).attr('data-href');
});
});
});

Dynamically updating a TinyMCE 4 ListBox

I'm trying to modify the TinyMCE 4 "link" plugin to allow users to select content from ListBox elements that are dynamically updated by AJAX requests.
I'm creating the ListBox elements in advance of editor.windowManager.open(), so they are initially rendered properly. I have an onselect handler that performs the AJAX request, and gets a response in JSON format.
What I need to do with the JSON response is to have it update another ListBox element, replacing the existing items with the new results.
I'm baffled, and the documentation is terribly unclear. I don't know if I should replace the entire control, or delete items and then add new ones. I don't know if I need to instantiate a new ListBox control, or render it to HTML, etc.
Basically, I have access to the original rendered ListBox (name: "module"} with
win.find('#module');
I have the new values from the AJAX request:
var data = tinymce.util.JSON.parse(text).data;
And I've tried creating a new Control configuration object, like
newCtrlconfig = {
type: 'listbox',
label: 'Class',
values: data
};
but I wouldn't know how to render it, much less have it replace the existing one.
I tried
var newList = tinymce.ui.Factory.create(newCtrlconfig);
and then
newList.renderHtml()
but even then, the rendered HTML did not contain any markup for the items. And examining these objects is just frustrating: there are "settings", "values", "_values", "items" all of which will happily store my values, but it isn't even clear which of them will work.
Since it's a ListBox and not a simple SELECT menu, I can't even easily use the DOM to manipulate the values.
Has anyone conquered the TinyMCE ListBox in 4.x?
I found this on the TinyMCE forum and I have confirmed that it works:
tinymce.PluginManager.add('myexample', function(editor, url) {
var self = this, button;
function getValues() {
return editor.settings.myKeyValueList;
}
// Add a button that opens a window
editor.addButton('myexample', {
type: 'listbox',
text: 'My Example',
values: getValues(),
onselect: function() {
//insert key
editor.insertContent(this.value());
//reset selected value
this.value(null);
},
onPostRender: function() {
//this is a hack to get button refrence.
//there may be a better way to do this
button = this;
},
});
self.refresh = function() {
//remove existing menu if it is already rendered
if(button.menu){
button.menu.remove();
button.menu = null;
}
button.settings.values = button.settings.menu = getValues();
};
});
Call following code block from ajax success method
//Set new values to myKeyValueList
tinyMCE.activeEditor.settings.myKeyValueList = [{text: 'newtext', value: 'newvalue'}];
//Call plugin method to reload the dropdown
tinyMCE.activeEditor.plugins.myexample.refresh();
The key here is that you need to do the following:
Get the 'button' reference by taking it from 'this' in the onPostRender method
Update the button.settings.values and button.settings.menu with the values you want
To update the existing list, call button.menu.remove() and button.menu = null
I tried the solution from TinyMCE forum, but I found it buggy. For example, when I tried to alter the first ListBox multiple times, only the first time took effect. Also first change to that box right after dialogue popped up didn't take any effect.
But to the solution:
Do not call button.menu.remove();
Also, the "hack" for getting button reference is quite unnecessary. Your job can be done simply using:
var button = win.find("#button")[0];
With these modification, my ListBoxes work just right.
Whole dialogue function:
function ShowDialog() {
var val;
win = editor.windowManager.open({
title: 'title',
body: {type: 'form',
items: [
{type: 'listbox',
name: 'categorybox',
text: 'pick one',
value: 0,
label: 'Section: ',
values: categories,
onselect: setValuebox(this.value())
},
{type: 'listbox',
name: 'valuebox',
text:'pick one',
value: '',
label: 'Page: ',
values: pagelist[0],
onselect: function(e) {
val = this.value();
}
}
]
},
onsubmit: function(e) {
//do whatever
}
});
var valbox = win.find("#valuebox")[0];
function setValuebox(i){
//feel free to call ajax
valbox.value(null);
valbox.menu = null;
valbox.settings.menu = pagelist[i];
// you can also set a value from pagelist[i]["values"][0]
}
}
categories and pagelist are JSONs generated from DB before TinyMCE load. pagelist[category] = data for ListBox for selected category. category=0 means all.
Hope I helped somebody, because I've been struggling this for hours.
It looks like the tinyMCE version that is included in wordpress 4.3 changed some things, and added a state object that caches the initial menu, so changing the menu is not enough anymore.
One will probably have to update the state object as well. Here is an example of updating the menu with data coming from an ajax request:
editor.addButton('shortcodes', {
icon: 'icon_shortcodes',
tooltip: 'Your tooltip',
type: 'menubutton',
onPostRender: function() {
var ctrl = this;
$.getJSON( ajaxurl , function( menu) {
// menu is the array containing your menu items
ctrl.state.data.menu = ctrl.settings.menu = menu;
});
}
});
As far as I can tell, these other approaches are broken in TinyMCE 4.9.
After spending most of the day tinkering to fix my own usage of these approaches, this is the working function I've found:
function updateListbox(win, data) { // win is a tinymce.ui.Window
listbox = win.find('#listbox'); // Substitute your listbox 'name'
formItem = listbox.parent();
listbox.remove();
formItem.append({
label: 'Dynamic Listbox',
type: 'listbox',
name: 'listbox',
values: data
});
}

how to trigger/reload Masonry plugin on click

Because i have different tabs, masonry is not loading the hidden items, so when i click on a new tab the images stack onto each other, i know this question has been asked before and answered with trigger masonry by clicking the tab, but how would i go about doing this without messing up the first tab.
Currently calling masonry with
$(function(){
$('#container').masonry({
// options
itemSelector : '.item',
columnWidth : 260
});
});`
$(window).load(function(){ $('#container').masonry(); });
and the same for tab 2 but with a different ID - #container2
the tab one works perfectly but tab two stacks the images, until you resize the browser which fixes it and works as normal
Do it like this:
$(function(){
$('#container').masonry({
// options
itemSelector : '.item',
columnWidth : 260
});
});
var masonryUpdate = function() {
setTimeout(function() {
$('#container').masonry();
}, 500);
}
$(document).on('click', masonryUpdate);
$(document).ajaxComplete(masonryUpdate);
Never worry about it again! Or, you may call it again after other animations, like:
$('#something').slideDown(600, masonryUpdate);
Even if you don't, just click anywhere in the page and masonry will update.
Yes, you can reload masonry view on onclick event as following :-
Use $container.masonry('reload'); if it is work for you. In my case It was not work. I have done using setTimeout(function(){ $container.masonry() }, 400); . call masonry in setTimeout function.
$(document).ready(function($) {
var $container = $('#youContainerId');
$("#TabId").live("click",function(){
//$container.masonry('reload');
setTimeout(function(){ $container.masonry() }, 400);
});
});