I am using InfiniteScroll:
var infScroll = new InfiniteScroll( '.grid', {
path: function() {
var pageNumber = ( this.loadCount + 1 );
var apiUrlQuery = $('.pagination__next').attr('href') + '&page=' + pageNumber;
return apiUrlQuery;
},
responseType: 'text',
status: '.scroll-status',
history: false
});
But now I need to implement search, so that means I need to refresh the path and the grid. How to do it?
So far what I have done is:
$('.search-events').on('click', function() {
infScroll.destroy();
/* building search query */
$('.grid-item').remove(); //Remove items visually from the grid
var apiUrlQuery = baseUrl + "&" + searchBy + "=" + searchTerm;
$('.pagination__next').attr('href', apiUrlQuery); //Update search url
infScroll.create();
infScroll.isLoading = false;
infScroll.loadNextPage();
})
With this, I am doing a new request using a new URL and get results but they don't get printed on the screen, also I see that the height of the grid is still the same as if I did not remove the grid-items.
Any ideas?
I finally made it work:
$('.search-events').on('click', function() {
msnry.remove($('.grid').find('.grid-item'));
var apiUrlQuery = baseUrl + "&" + searchBy + "=" + searchTerm;
$('.pagination__next').attr('href', apiUrlQuery);
infScroll.isLoading = false;
infScroll.canLoad = true;
infScroll.create();
msnry.layout();
infScroll.loadNextPage();
})
This line removes the elements from the DOM as I did with $('.grid-item').remove(), but also remove it from some internal array that keeps data.
msnry.remove($('.grid').find('.grid-item'));
Also, I removed infScroll.destroy(); because it unbinds from the load method.
The key part is msnry.layout(); this one rebuilds the layout.
Hope it helps someone in the future.
Related
I want to make an input with autocomplete use google places API. And this is my code:
var options = {
componentRestrictions: {
country: "de"
}
};
var place = '';
var locationAutocompleteOneWay = document.getElementById('locationAutocompleteOneWay');
var autocompleteLocationOneWay = new google.maps.places.Autocomplete(locationAutocompleteOneWay, options);
google.maps.event.addListener(autocompleteLocationOneWay, 'place_changed', function() {
place = autocompleteLocationOneWay.getPlace();
});
For more customize, I want to add some custom place result when I input in the textbox. Here my code and result:
setTimeout(function() {
$(".pac-container").append('<div id="areasearch" class="pac-item areasearch"><span class="pac-icon pac-icon-areas"></span><span class="pac-item-query"><span class="pac-matched"></span>Test place</span> <span>custom place</span></div>');
}, 500);
But I want when I click on the result, it make my input locationAutocompleteOneWay has had a value of the result. But I don't know how to make it. And I want it can apply for multi-input on the page. I use it by jQuery and AngularJS. All solution of Jquery and AngularJS is good for me. Thank in advanced.
What I found is that, if you load the custom locations you're adding with attributes that can be used to set the lat/lng (and anything else you need), then you can bind to the mousedown event to assign a custom place object to the autocomplete.
In my script, I have the following snippet adding an item to the autocompletes (this adds to all auto-complete elements on the page):
$(".pac-container").append('<div id="areasearch' + i + '" class="pac-item areasearch custom" val="' + PlaceName + '" lat="' + Latitude + '" lng="' + Longitude + '" style="display: none;"><span class="pac-icon pac-icon-areas"></span><span class="pac-item-query"><span class="pac-matched"></span>' + PlaceName + '</span> <span>' + LocationName + '</span></div>');
Using the classes pac-item and custom, I then bind as follows:
setTimeout(function () {
$("div.pac-item.custom").mousedown(function () {
setCustomLocation($(this));
})
}, 100);
And the custom location function is:
setCustomLocation = function (obj) {
$("#" + currInput).val($(obj).attr("val"));
var newObj = {};
newObj["geometry"] = {}
newObj["geometry"]["location"] = {}
newObj["geometry"]["location"]["lat"] = function () { return $(obj).attr("lat"); }
newObj["geometry"]["location"]["lng"] = function () { return $(obj).attr("lng"); }
currAutocomplete.set("place", newObj);
}
The first line sets the name into the active input field, and the rest sets the place object for the active autocomplete (both variables captured in other events). The only values I needed for the project was the geometry lat/lng pair, but if you need more, just load it with whatever values you need to retrieve from the parent.
This is my first time working with pagination. The issue I am having is that I am getting multiple responses from the Instagram API after a certain amount of clicks to the pagination button. I think I have narrowed down the issue to the fact that the function is probably firing multiple times. Take a look at my functions.
Receives the data and sorts it to the other functions:
function sortAndStore(data) {
var images = data.data,
pagLink = data.pagination.next_url;
var newImages = [];
for (i = 0; i < images.length; i++) {
var link = images[i].link,
standardRes = images[i].images.standard_resolution.url,
thumb = images[i].images.thumbnail.url;
var tempImages = new Object();
tempImages.link = link;
tempImages.standard_res = standardRes;
tempImages.thumbnail = thumb;
newImages.push(tempImages);
}
createLayout(newImages);
loadMore(pagLink);
}
Creates the desired layout (sloppy right now but working):
function createLayout(data) {
var images = data;
if ($('#authorizeInsta').css('display') === 'inline') {
$('#authorizeInsta').hide();
// Adds additonal structure
$('<div id="instagramFeed" class="row-fluid" data-count="0"></div>').insertAfter('.direct_upload_description_container');
}
if (!$('#feedPrev').length > 0) {
$('<ul id="feedNav" class="pagination"><li><a id="feedPrev" href="#">Prev</a></li><li><a id="feedNext" href="#">Next</a></li></div>').insertAfter('#instagramFeed');
}
var count = $('#instagramFeed').data('count'),
countParse = parseInt(count);
newCount = countParse + 1;
$('<div id="row' + newCount + '" class="span3">').appendTo('#instagramFeed');
$('#instagramFeed').data('count', newCount);
for (i = 0; i < images.length; i++) {
var link = images[i].link,
standardRes = images[i].standard_res,
thumb = images[i].thumbnail,
newImage = '<img data-image="' + standardRes + '" src="' + thumb + '" class="feedImage" id="feedImage' + i + '"/>';
$(newImage).appendTo('#row' + newCount + '');
}
imageSelect();
}
Pagination function:
function loadMore(link) {
var pagLink = link;
console.log(pagLink);
$('#feedPrev').unbind('click').click(function(event) {
$.ajax({
url: link,
type: 'GET',
dataType: 'jsonp',
})
.done(function(data) {
sortAndStore(data);
})
.fail(function(data, response) {
console.log(data);
console.log(response);
});
return false;
});
}
I understand that the issue is probably here in the sortAndStore function
createLayout(newImages);
loadMore(pagLink);
And here is what the pagination link console logs out to. The issue being that I clicked the button three times and I got four responses. The first two times were fine. I got one pagination link, but the third time I received two response.
If you can see a different issue or suggest a different way to structure my functions it would be greatly appreciated. The data parameter in the sortAndStore function is the data from the original Instagram API call.
Thanks,
Figured it out! The issue was that every time the pagination button was clicked the browser was storing a new value for pagLink. Therefore, after clicking the button twice, there were two stored variables which made two pagination API calls.
The fix is to redefine the variable every time a new pagination link goes through the function, not to define an additional pagLink variable.
So this:
function sortAndStore(data) {
var images = data.data;
pagLink = data.pagination.next_url;
Instead of this:
function sortAndStore(data) {
var images = data.data,
pagLink = data.pagination.next_url;
So the solution was to redefine the variable, not to add an additional one, like I was doing by accident.
So I've created a google maps page with a bunch of markers generated from XML. The idea is that when you click on a marker a div will be generated that displays events information related to that marker. This all works fine but what I'm struggling with is now trying to attach an accordion to the events information. The code I have so far will show an accordion on the first marker you click on (can be any one and it returns the correct info, shows the div and has an accordion) but not on any subsequent marker clicks, even the same one for a second click.
I'm sure this must be a simple fix but I've tried a few variations (there are three attempts at the accordion that I have left in to show the different versions) and I am getting the same results.
Here is the code that binds the events to the markers as a google event listener..
function bindEvents(marker, id, venueName, website){
google.maps.event.addListener(marker, 'click', function(){
// TARGET and show eventsFeed on click
$('#eventsFeed').show(222);
var eventsList = document.getElementById('eventsList');
// ADDS styles to the events feed divs when created
// DECLARED here for the inclusion of the venueName & website as feedhead
// even when no events are present
var venueNameDiv = "<div class='venueNameFeed'>";
var webSiteDiv = "<a target='_blank' class='websiteInFeed' href='http://"+website+"'><span class='fa fa-home'></span></a>";
var titleInFeed = "<div class='"+id+" eventTitleFeed'>";
var accordDataWrap = "<h2 class='accordWrap>";
var eventInFeed = "<div class='eventDescFeed'>";
var dateInFeed = '<div class="eventDateFeed">';
var priceInFeed = "<div class='eventPriceFeed'>";
// CLOSE the divs after each entry
var divBrk = "</div>";
var closeAccordDataWrap = "</h2>";
var feedHead = venueNameDiv + venueName + divBrk;
// EMPTY array to line up matched events in
var eventsLine = [];
// CYCLE through eventsArray
for (var key in eventsArray){
var eventLoop = eventsArray[key];
// MATCH id to venue_id
var venue_id = eventLoop.venue_id;
if (venue_id == id){
// ONLY show events from todays date onward
var now = new Date();
var date = new Date(eventLoop.eventDATE);
// SET hours to 0 to ignore time part (always as 01:00:00 for event date?)
now.setHours(0,0,0,0);
if (date >= now){
//ADD all matched events to eventsLine array
eventsLine.push(titleInFeed + eventLoop.eventTitle + divBrk +
accordDataWrap + eventInFeed + eventLoop.event + divBrk +
dateInFeed + formatDate(eventLoop.eventDATE) + divBrk +
priceInFeed + "£" + eventLoop.price + divBrk + closeAccordDataWrap);
}
}
}
// TURNS the array into a string and replaces those damned, infernal commas!!
var outputString = eventsLine.toString().replace(/>,/g, '>');
// PUT the compiled array into the eventsFeed div (with venueName as title)
if (website==""){
eventsList.innerHTML = feedHead + outputString;
} else {
eventsList.innerHTML = feedHead + webSiteDiv + outputString;
}
// ADD the accordion
$(document).on('click', marker, function(){
$(eventsList).accordion({
header: "div."+id,
icons: null
})
})
// OR
$(eventsList).each(function(){
$(eventsList).accordion({
header: "div."+id,
icons: null
});
});
// OR
accordion(eventsList, id);
});
}
This third option calls a separate function which is defined as;
function accordion(placement,id){
$(placement).accordion({
header: "div."+id,
icons: null
});
}
As you can probably tell I'm pretty new to all of this so any help or advice with anything would be greatly appreciated! :)
Can you replace this code:
$(eventsList).each(function(){
$(eventsList).accordion({
header: "div."+id,
icons: null
});
});
with this code:
$(eventsList).each(function(){
$(this).accordion({
header: "div."+id,
icons: null
});
});
and try. Also it will be better if you can Create a fiddle for your code.
I have a small console that displayed the output of certain actions in my website, the need to have another console that would display a different kind of output made me want to combine both consoles in a Kendo UI TabStrip, the thing is that the information displayed on the console isn't received with AJAX so when I started to insert the HTML elements like before, the tab didn't got updated.
This is how I initialize the tab:
$('#tabConsole').kendoTabStrip({
animation: {
open: {
effects:'fadeIn'
}
}
});
This is how my HTML looks:
<div id="tabConsole">
<ul>
<li class="k-state-active">Salida</li>
<li id="notificacionTab">Notificaciones</li>
</ul>
<div id="userConsole"></div>
<div id="notificationConsole"></div>
</div>
This is how I try to update it:
function appendToConsole(content, type, optional) {
//code to append to console
var actualDate = new Date();
var prevContent = $('#userConsole').html();
if (typeof prevContent === 'undefined') {
prevContent = '';
}
var strType = '';
var iconType = '';
var moreOutput = '';
if (type == 1) {
strType = 'infoConsole';
iconType = 'infoIcon.png';
} else if (type == 2) {
strType = 'warningConsole';
iconType = 'warningIcon.png';
moreOutput = '<img id="viewDetails" value="' + optional + '" class="moreConsole" src="../Content/images/icons/arrow.png">';
} else if (type == 3) {
strType = 'errorConsole';
iconType = 'errorIcon.png';
}
var iconOutput = '<img class="iconConsole" src="../Content/images/icons/' + iconType + '">';
var dateOutput = '<div class="dateConsole">' + iconOutput + ' ' + actualDate.toLocaleDateString() + ', ' + actualDate.toLocaleTimeString() + ' : </div>';
var consoleOutput = prevContent + '<div class="outputConsole">' + dateOutput + content + moreOutput + '</div>';
$('#userConsole').html(consoleOutput.toString());
var height = $('#userConsole')[0].scrollHeight;
$('#userConsole').scrollTop(height);
//my try to update the tab
var tabStrip = $('#tabConsole'),
selectedIndex = tabStrip.data('kendoTabStrip').select().index(),
clone = original.clone(true);
clone.children('ul')
.children('li')
.eq(selectedIndex)
.addClass('k-state-active')
.end();
tabStrip.replaceWith(clone);
$('#tabConsole').kendoTabStrip({
animation: {
open: {
effects: 'fadeIn'
}
}
});
}
How can I update the contents of the DIV that are inside the TabStrip?
EDIT
It seems Kendo UI renames the DIVs' ids that represent the tabs to tabConsole-1 and tabConsole-2, explaining why the update wasn't working, still there's a lot of strange behavior, I had to specify the height for each DIV so the overflow propety would work, also the images with id viewDetails and class moreConsole when set to position absolute, get rendered outside the DIV that represents the tab, but if I change the position property to relative, the images stay inside the DIV but are displayed not at the end of the DIV like I want to, but relative to the size of the DIV that comes before them.
I'm really confused as to how to set the styles so the contents are displayed properly.
Adding content to a tabStrip can be achieved using:
$(tabConsole.contentElement(idx)).append(newContent)
where:
idx is the tab index,
newContent is what you want to add to the existing content and
tabConsole is the variable set to $("#...").kendoTabStrip(...).data("kendoTabStrip");.
You don't need to create a new tabStrip (in addition you should not re-create KendoUI elements since this is a pretty expensive operation).
About using multiple tags with the same id... you should not use it, use class instead. ids should be unique.
I'm still trying to understand your problem with the styling.
im new to jquery bbq, i've figured out most of the setup so far but i have a little issue. heres the setup.
one page with main nav links on the right
each nav link click will change the body content of the page to its corresponding data (showing and hiding divs) (with bbq)
one of the links shows a div with another set of links that when clicked will set hash B in the url
so first link click
domain.com/dir/#A=page1
second link click
domain.com/dir/#A=page1&B=set1
if i press the back button it goes back to the previous A hash, however the B hash remains in the url.
is there a way to remove the B peram when not on the specific page?
$(window).bind('hashchange', function(e) {
var state = $.bbq.getState('p');
var graphState = $.bbq.getState('n');
var base_title = '{/literal}{$smarty.const.SITE_TITLE}{literal} | Dashboard | ';
$('.profile-nav a').each(function() {
if (!state) {
$('.profile-nav a').each(function() {
$('#' + this.id).removeClass('live active');
document.title = base_title + 'Message Center';
});
$('#m').addClass('live active');
} else if (state == this.id) {
$('#' + this.id).addClass('live active');
document.title = base_title + $(this).text();
} else {
$('#' + this.id).removeClass('live active');
}
});
if (!state) {
$('.tab-content').fadeOut('fast');
$('.message-content').fadeIn('slow');
} else {
$('.tab-content').fadeOut('fast');
clicked = $('#' + state).attr('rel').split(' ')[0];
$('.' + clicked).fadeIn('slow');
}
if (state == 'r') {
if (graphState) {
$('.nick-breakdown').fadeOut('fast');
$('#' + graphState).fadeIn('slow');
document.title = base_title + 'Reports | ' + $('#' + graphState).attr('rel');
} else {
$('.item-breakdown').fadeOut('fast');
$('.nick-breakdown').fadeIn('slow');
document.title = base_title + 'Reports';
}
}
});
I've accomplished the same thing using jsbbq.pushState with merge_mode = 2 instead of just setting the # on the anchor.
Check out the docs here: http://benalman.com/code/projects/jquery-bbq/docs/files/jquery-ba-bbq-js.html#jQuery.bbq.pushState
merge_mode(Number) : Merge behavior defaults to 0 if merge_mode is not
specified (unless a hash string beginning with # is specified, in
which case merge behavior defaults to 2), and is as-follows:
0: params in the params argument will override any params in the current state.
1: any params in the current state will override params in the params argument.
2: params argument will completely replace current state.
So if your link looks like:
mysite.com#A=page1&B=page2 you could call
$.bbq.pushState({'A' : 'pageXYZ'}, 2);
And your doc location would then be:
mysite.com#A=pageXYZ
I got a way easier approach, no plugins needed:
Copy over current hashparameters to a dummy URL AS searchParameters. Now you can treat the hash parameters like search-parameters, edit them with all the functionality of searchparameters (developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) and copy them back afterwards AS hasparameters,
E.g Simple function that set and updates parameters, you could also use '.delete()' instead of '.set' to delete the parameter:
function setOrUpdateHashParameter( hashParameterName, hashParameterValue ) {
let theURL = new URL('https://dummy.com'); // create dummy url
theURL.search = window.location.hash.substring(1); // copy current hash-parameters without the '#' AS search-parameters
theURL.searchParams.set( hashParameterName, hashParameterValue ); // set or update value with the searchParams-API
window.location.hash = theURL.searchParams; // Write back as hashparameters
}
If anyone knows how to format these post properly, feel free to edit it, thanks!