How to handle execution of javascript in infinite scroll? - javascript

I am using infinite scroll to load posts and tried to integrate a custom like button for every single posts that needs a small jquery script to work. My problem is I added this Jquery directly after the sucess in ajax load posts. But when I load eg the 3. page my jquery script executes twice and on the posts of the 2nd page the lke buttons are not working correctly. How can I handle this? If I dont execute the code after the ajax request and only call this jquery code globally the like buttons do not work in the new loaded posts of the ajax infinite scroll. Maybe I need to stop the sript of before when eg loadin 3. page through the ajax infinite scroll but how? This is my code:
function load_more_posts(selector){
var url = $(selector).attr('href');
var data;
loading = true;
$.ajax({
url: url,
data: data,
success: function( data ) {
var $items = $( '.loading-content .item', data );
$new_anchor = $( selector, data );
$items.addClass('hidden');
if ( $('#cooked-plugin-page .result-section.masonry-layout .loading-content').length ){
$( '.loading-content').isotope( 'insert', $items );
} else {
$( '.loading-content').append($items);
setTimeout(function() {
$items.removeClass('hidden');
}, 200);
}
if($new_anchor.length) {
$(selector).attr('href', $new_anchor.attr('href'));
} else {
$(selector).remove();
}
loading = false;
$('.like-btn').each(function() {
var $button = $(this),
$icon = $button.find('> i'),
likedRecipes = $.cookie('cpLikedRecipes'),
recipeID = $button.attr('data-recipe-id');
cookied = $button.attr('data-cookied');
userLiked = $button.attr('data-userliked');
if ( cookied == 1 && typeof likedRecipes !== 'undefined' && likedRecipes.split(',').indexOf(recipeID) > -1 || userLiked == 1 ) {
$icon.removeClass('fa-heart-o').addClass('fa-heart');
}
});
$('#cooked-plugin-page .like-btn').on('click', function() {
var $button = $(this),
$icon = $button.find('> i'),
$count = $button.find('.like-count'),
count = parseInt($count.text()),
likedRecipes = $.cookie('cpLikedRecipes'),
recipeID = $button.attr('data-recipe-id'),
cookied = $button.attr('data-cookied'),
likeURL = $button.attr('href'),
likeAction;
if ( $icon.hasClass('fa-heart-o') ) {
$icon.removeClass('fa-heart-o').addClass('fa-heart');
count++;
if (cookied == 1){
if ( typeof likedRecipes === 'undefined' ) {
likedRecipes = recipeID;
} else {
likedRecipes = likedRecipes + ',' + recipeID;
}
$.cookie('cpLikedRecipes', likedRecipes, { expires: 365 } );
}
likeAction = 'like';
} else {
$icon.removeClass('fa-heart').addClass('fa-heart-o');
count--;
if (cookied == 1){
if ( typeof likedRecipes === 'undefied' ) {
return false;
}
}
if (cookied == 1){
var likedSplit = likedRecipes.split(','),
recipeIdx = likedSplit.indexOf(recipeID);
if ( recipeIdx > -1 ) {
likedSplit.splice( recipeIdx, 1 );
likedRecipes = likedSplit.join(',');
$.cookie('cpLikedRecipes', likedRecipes, { expires: 365 } );
likeAction = 'dislike';
}
} else {
likeAction = 'dislike';
}
}
$.ajax({
'url' : likeURL,
'data': {
'action' : 'cp_like',
'likeAction': likeAction
},
success: function(data) {
$count.text(data);
}
});
return false;
});
$('#cooked-plugin-page .tab-links a').on('click', function() {
var tab = $(this).attr('href');
if ( !$(this).is('.current') ){
$(this).addClass('current').siblings('.current').removeClass('current');
$('#cooked-plugin-page.fullscreen .tab').removeClass('current');
$(tab).addClass('current');
$win.scrollTop(0);
}
return false;
});
if($('.rating-holder').length) {
$('.rating-holder .rate')
.on('mouseenter', function() {
var $me = $(this);
var $parent = $me.parents('.rating-holder');
var my_index = $me.index();
var rated = $parent.attr('data-rated');
$parent.removeClass(function(index, css) {
return (css.match (/(^|\s)rate-\S+/g) || []).join(' ');
});
$parent.addClass('rate-' + (my_index + 1));
})
.on('mouseleave', function() {
var $me = $(this);
var $parent = $me.parents('.rating-holder');
var my_index = $me.index();
var rated = $parent.attr('data-rated');
$parent.removeClass(function(index, css) {
return (css.match (/(^|\s)rate-\S+/g) || []).join(' ');
});
if(rated !== undefined) {
$parent.addClass('rate-' + rated);
}
})
.on('click', function() {
var $me = $(this);
var $parent = $me.parents('.rating-holder');
var my_index = $me.index();
$('.rating-real-value').val(my_index + 1);
$parent.attr('data-rated', my_index + 1);
$parent.addClass('rate-' + (my_index + 1));
});
}
setTimeout(function() {
masonry();
}, 500);
}
});
}

There's a great plugin for scrolling. He has methods such as bund, unbind, destroy and e.t.c.:
https://github.com/infinite-scroll/infinite-scroll#methods

Related

Angular js: Everything works fine but the buttons created in html inside compile does not work

Everything is working fine in my code except the line of HTML below
> $compile('<button class="btn btn-link ng-scope" data-ng-click="Flow.GetFarePriceRule('+ start_point +','+ end_point +')">'+ $scope.fare_base_code_array[i-1].FareBasis["#attributes"].Code +'</button>');
$timeout(() => {
console.log($el.prop('outerHTML'))
});
The button links are showing correctly but when I click on them they do not work. I guess the HTML is not binding with angular because the function in that HTML does not call after clicking.
$scope.ptc_break = function(variable , index , key)
{
$scope.fbc=[];
if (Array.isArray(variable) == false) {
$scope.fbc.push(variable);
}else{
$scope.fbc = variable;
}
$scope.fare_base_code_array = $scope.fbc;
$scope.temp_array = [];
var fare_base_var = '';
var count = 0 ;
var comma = '';
var start_point = 1;
var end_point = 0;
var fare_base_include = "";
for (var i = 0; i <= $scope.fare_base_code_array.length; i++) {
if (i == $scope.fare_base_code_array.length) {
fare_base_include = "";
}else{
fare_base_include = $scope.fare_base_code_array[i].FareBasis["#attributes"].Code;
}
if ($scope.temp_array.includes(fare_base_include) == false) {
count++;
if (count>0) {
comma = ",";
}else{
comma = '';
}
if (i > 0) {
var $el = $compile('<button class="btn btn-link ng-scope" data-ng-click="Flow.GetFarePriceRule('+ start_point +','+ end_point +')">'+ $scope.fare_base_code_array[i-1].FareBasis["#attributes"].Code +'</button>')($scope);
$timeout(() => {
console.log($el.prop('outerHTML'))
});
fare_base_var = fare_base_var + $el.prop('outerHTML') + comma;
}
start_point = end_point + 1;
setTimeout(function() {
delayFunction1();
}, 1000);
function delayFunction1(){
// if (key == 0) {//$('#fare_base_'+index).html(fare_base_var);
// el = document.getElementById('#fare_base_'+index);
// angular.element(el).append( $compile(fare_base_var)($scope) )
// }
if (key == 0) {$('#fare_base_'+index).html(fare_base_var);}
if (key == 1) {$('#private_fare_base_'+index).html(fare_base_var);}
if (key == 2) {$('#fare_base_best_buy_'+index).html(fare_base_var);}
if (key == 3) {$('#private_fare_base_best_buy_'+index).html(fare_base_var);}
if (key == 4) {$('#fare_base_alternative_'+index).html(fare_base_var);}
}
}
if (i != $scope.fare_base_code_array.length) {
$scope.temp_array.push($scope.fare_base_code_array[i].FareBasis["#attributes"].Code);
}
end_point++;
}
}
and this is the function that i am calling..
$scope.GetFarePriceRule = function(start , end_number){
alert("hello");
$scope.price_rule_para = "";
$('#private_fare_base_'+index)
alert(start);
alert(end_number);
$('#myModal2').modal('show');
$scope.select_traveler_type = $scope.send_passenger_type;
$( ".rule_modal_loader" ).addClass( "loader" );
var url = base_url+"/start_soap_fare_price_rule_workflow.php";
$scope.getfarerules = {
'ItneraryNo': $scope.pnr_number,
'FlightSegment': $scope.send_pasenger_segment,
'PassengerType': $scope.send_passenger_typee,
'rule_passenger_type': $scope.rule_passenger_type ,
'FareType': "Public",
'carrier_code': null,
'kind_of_fare' : "retain",
'start_point':start,
'end_point':end_number
};
$http({
method: 'POST',
url: url,
data: $.param($scope.getfarerules),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).success(function(response) {
console.log(response);
var myar = response.RulesFromPriceRS.FareRuleInfo.Rules.Paragraph.Text.replace(/-/g, "");
var myarr = myar.split(".");
$scope.price_rule_para = myarr;
$('#Price_head').show();
$('#Price_itinerary_table').show();
$('#price_itinerary_btn').hide();
$('#Issue_air_ticket_btn').show()
$( ".rule_modal_loader" ).removeClass( "loader" );
}).error(function(response) {
console.log(response);
alert(response);
alert("error");
alert('This is embarassing. An error has occured. Please check the log for details');
});
};
please help me out to get out of the situation
outerHtml return string, simple string. So you discard all bindings.
This wont work:
var $el = $compile...
vat html = $el.prop('outerHTML')
someElement.html(html);
This will:
var $el = $compile...
someElement.append($el);
P.S. I see you are fan of Jquery, but better stop using it in Angular projects at all.

Wordpress enqueue jquery not working

I installed an plugin on my current clean wordpress installation. However I always get the following error as soon as the widget for the plugin gets laoded
TypeError: $ is not a function
I checked the js files for the addon and they all seem to make proper use of jQuery instead of $ also the register_script function requires jquery as dependency
Below you can see the add_action function
if (!is_admin()) {
function woocommerce_ogonecw_add_frontend_css() {
wp_register_style('woocommerce_ogonecw_frontend_styles', plugins_url('resources/css/frontend.css', __FILE__));
wp_enqueue_style('woocommerce_ogonecw_frontend_styles');
true);
wp_register_script('ogonecw_frontend_script', plugins_url('resources/js/frontend.js', __FILE__), array(
'jquery'
));
wp_enqueue_script('ogonecw_frontend_script');
wp_localize_script('ogonecw_frontend_script', 'woocommerce_ogonecw_ajax',
array(
'ajax_url' => admin_url('admin-ajax.php')
));
}
add_action('wp_enqueue_scripts', 'woocommerce_ogonecw_add_frontend_css');
frontend.js looks like this
jQuery(function (jQuery) {
var isSubmitted = false;
var CheckoutObject = {
cssClass: '',
successCallback: '',
placeOrder: function() {
var form = jQuery('form.checkout');
var form_data = form.data();
// WGM: Back Button
if(jQuery("input[name=cw-wgm-button-back]").length > 0) {
return true;
}
//WGM: MultiStep
if(jQuery("input[name=wc_gzdp_step_submit]").length > 0) {
if(jQuery("input[name=wc_gzdp_step_submit]").val() == "address"){
return true;
}
}
var selectedPaymentMethodElement = jQuery('input:radio[name=payment_method]:checked');
var selectedPaymentMethod = selectedPaymentMethodElement.val();
var secondRun = false;
if(jQuery("input[name=ogonecw_payment_method_choice]").length > 0) {
secondRun = true;
selectedPaymentMethodElement = jQuery("input[name=ogonecw_payment_method_choice]");
selectedPaymentMethod = selectedPaymentMethodElement.val();
}
var moduleName = 'ogonecw';
var selectedModuleName = (selectedPaymentMethod != undefined) ?
selectedPaymentMethod.toLowerCase().substring(0, moduleName.length) : '';
onOgoneCwCheckoutPlaceObject = this;
if (moduleName == selectedModuleName) {
form.addClass('processing');
if ( form_data["blockUI.isBlocked"] != 1 ) {
form.block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
}
this.successCallback = previewAuthorization;
this.cssClass = 'ogonecw-preview-fields';
onOgoneCwCheckoutPlaceObject = this;
if(secondRun) {
this.generateOrder(form, selectedPaymentMethod);
return false;
}
var validateFunctionName = 'cwValidateFields'+selectedPaymentMethod.toLowerCase();
var validateFunction = window[validateFunctionName];
if (typeof validateFunction != 'undefined') {
validateFunction(function(valid){onOgoneCwCheckoutPlaceObject.successCall();}, function(errors, valid){onOgoneCwCheckoutPlaceObject.failureCall(errors, valid);});
return false;
}
onOgoneCwCheckoutPlaceObject.successCall();
return false;
}
},
failureCall: function(errors, valid){
alert(errors[Object.keys(errors)[0]]);
var form = jQuery('form.checkout');
form.removeClass('processing').unblock();
form.find( '.input-text, select, input:checkbox' ).trigger( 'validate' ).blur();
},
successCall : function(){
var form = jQuery('form.checkout');
var selectedPaymentMethodElement = jQuery('input:radio[name=payment_method]:checked');
var selectedPaymentMethod = selectedPaymentMethodElement.val();
onOgoneCwCheckoutPlaceObject = this;
if(selectedPaymentMethodElement.parents('li').find('.ogonecw-validate').length > 0){
var ajaxUrl;
if(typeof wc_checkout_params != 'undefined') {
ajaxUrl = wc_checkout_params.ajax_url;
}
if(typeof checkoutUrl == 'undefined') {
ajaxUrl = woocommerce_params.ajax_url;
}
var separator = ajaxUrl.indexOf('?') !== -1 ? "&" : "?";
ajaxUrl = ajaxUrl+separator+"action=woocommerce_ogonecw_validate_payment_form";
var inputData = getFormFieldValues('ogonecw-preview-fields', selectedPaymentMethod.toLowerCase());
var postData = "&";
jQuery.each(inputData, function(key, value) {
postData += encodeURIComponent(key)+"="+encodeURIComponent(value)+"&";
});
jQuery.ajax({
type: 'POST',
url: ajaxUrl,
data: form.serialize()+postData+ onOgoneCwCheckoutPlaceObject.cssClass + "=true",
success: function( code ) {
var response = '';
try {
response = jQuery.parseJSON(code);
if ( response.result == 'success' ) {
onOgoneCwCheckoutPlaceObject.generateOrder(form, selectedPaymentMethod);
return false;
}
else if ( response.result == 'failure' ) {
throw 'Result failure';
} else {
throw 'Invalid response';
}
}
catch(err ){
// Remove old errors
jQuery( '.woocommerce-error, .woocommerce-message' ).remove();
// Add new errors
if ( response.message ) {
form.prepend(response.message);
} else {
form.prepend(code);
}
// Cancel processing
form.removeClass( 'processing' ).unblock();
// Lose focus for all fields
form.find( '.input-text, select, input:checkbox' ).trigger( 'validate' ).blur();
// Scroll to top
jQuery( 'html, body' ).animate({
scrollTop: ( jQuery( 'form.checkout' ).offset().top - 100 )
}, 1000 );
}
},
dataType: 'html'
});
return false;
}
else {
onOgoneCwCheckoutPlaceObject.generateOrder(form, selectedPaymentMethod);
return false;
}
},
generateOrder: function(form, selectedPaymentMethod) {
onOgoneCwCheckoutPlaceObject = this;
var checkoutUrl;
if(typeof wc_checkout_params != 'undefined') {
checkoutUrl = wc_checkout_params.checkout_url;
}
if(typeof checkoutUrl == 'undefined') {
checkoutUrl = woocommerce_params.checkout_url;
}
jQuery.ajax({
type: 'POST',
url: checkoutUrl,
data: form.serialize() + "&" + onOgoneCwCheckoutPlaceObject.cssClass + "=true",
success: function( code ) {
var response = '';
try {
if (code.indexOf("<!--WC_START-->") >= 0) {
code = code.split("<!--WC_START-->")[1];
}
if (code.indexOf("<!--WC_END-->") >= 0) {
code = code.split("<!--WC_END-->")[0];
}
try {
// Check for valid JSON
response = jQuery.parseJSON( code );
} catch ( e ) {
// Attempt to fix the malformed JSON
var validJson = code.match( /{"result.*"}/ );
if ( null === validJson ) {
throw 'Invalid response';
} else {
response = jQuery.parseJSON(validJson[0]);
}
}
if ( response.result == 'success' ) {
onOgoneCwCheckoutPlaceObject.successCallback(response, selectedPaymentMethod);
}
else if ( response.result == 'failure' ) {
throw 'Result failure';
} else {
throw 'Invalid response';
}
}
catch( err ) {
if ( response.reload === 'true' ) {
window.location.reload();
return;
}
// Remove old errors
jQuery( '.woocommerce-error, .woocommerce-message' ).remove();
// Add new errors
if ( response.messages ) {
form.prepend( response.messages );
} else {
form.prepend( code );
}
// Cancel processing
form.removeClass( 'processing' ).unblock();
// Lose focus for all fields
form.find( '.input-text, select, input:checkbox' ).trigger( 'validate' ).blur();
// Scroll to top
jQuery( 'html, body' ).animate({
scrollTop: ( jQuery( 'form.checkout' ).offset().top - 100 )
}, 1000 );
// Trigger update in case we need a fresh nonce
if ( response.refresh === 'true' ) {
jQuery( 'body' ).trigger( 'update_checkout' );
}
jQuery( 'body' ).trigger( 'checkout_error' );
}
},
dataType: 'html'
});
},
};
var getFormFieldValues = function(parentCssClass, paymentMethodPrefix) {
var output = {};
jQuery('.' + parentCssClass + ' *[data-field-name]').each(function (element) {
var name = jQuery(this).attr('data-field-name');
if(name.lastIndexOf(paymentMethodPrefix, 0) === 0) {
name = name.substring(paymentMethodPrefix.length);
name = name.substring(1, name.length -1 );
if(this.type == "radio") {
if(this.checked) {
output[name] = jQuery(this).val();
}
}
else{
output[name] = jQuery(this).val();
}
}
});
return output;
};
var generateHiddenFields = function(data) {
var output = '';
jQuery.each(data, function(key, value) {
output += '<input type="hidden" name="' + key + '" value="' + value + '" />';
});
return output;
};
var removeNameAttributes= function(cssClass) {
// Remove name attribute to prevent submitting the data
jQuery('.' + cssClass + ' *[name]').each(function (element) {
jQuery(this).attr('data-field-name', jQuery(this).attr('name'));
if(jQuery(this).is(':radio')){
return true;
}
jQuery(this).removeAttr('name');
});
}
var addAlias = function(cssClass){
// Add listener for alias Transaction selector
jQuery('.' + cssClass).parents('li').find('.ogonecw-alias-input-box > select').bind('change', function() {
jQuery('body').trigger('update_checkout');
});
}
var registerCheckoutObject = function(){
bindOrderConfirmEvent(CheckoutObject);
};
var bindOrderConfirmEvent = function (CheckoutObject) {
var form = jQuery('form.checkout');
var attached = form.attr('data-ogonecw-attached');
if (attached != 'true') {
form.attr('data-ogonecw-attached', 'true');
form.bind('checkout_place_order', function() {
return CheckoutObject.placeOrder();
});
return false;
}
};
// We have to make sure that the JS in the response is executed.
jQuery( document ).ready(function() {
if (typeof window['force_js_execution_on_form_update_listener'] === 'undefined') {
window['force_js_execution_on_form_update_listener'] = true;
jQuery('body').bind('updated_checkout', function() {
removeNameAttributes('ogonecw-preview-fields');
addAlias('ogonecw-preview-fields');
if (jQuery('.ogonecw-preview-fields').length > 0) {
registerCheckoutObject();
}
});
}
});
jQuery( document ).ajaxStop(function(event, xhr, settings) {
removeNameAttributes('ogonecw-preview-fields');
addAlias('ogonecw-preview-fields');
if (jQuery('.ogonecw-preview-fields').length > 0) {
registerCheckoutObject();
}
});
var previewAuthorization = function (result, selectedPaymentMethod) {
if(typeof result.redirect !== 'undefined') {
var additionalFields = jQuery('<div class="ogonecw-preview-fields" style="display: none;"></div>');
jQuery('.' + 'ogonecw-preview-fields' + ' *[data-field-name]').each(function (element) {
var name = jQuery(this).attr('data-field-name');
if(name.lastIndexOf(selectedPaymentMethod.toLowerCase(), 0) === 0) {
jQuery(additionalFields).append(jQuery(this));
}
});
var redirectUrl;
if ( result.redirect.indexOf( "https://" ) != -1 || result.redirect.indexOf( "http://" ) != -1 ) {
redirectUrl = result.redirect;
} else {
redirectUrl = decodeURI( result.redirect );
}
jQuery.get(redirectUrl, function(data){
var newBodyString = data.replace(/^[\S\s]*<body[^>]*?>/i, "").replace(/<\/body[\S\s]*jQuery/i, "");
var newBody = jQuery("<div></div>").html(newBodyString);
if(newBody.find('.wgm-go-back-button').length > 0){
jQuery('body').html(newBody.html());
jQuery('form.checkout').append(additionalFields);
jQuery('form.checkout').append('<input type="hidden" name="ogonecw_payment_method_choice" value="'+selectedPaymentMethod+'"/>');
jQuery('.wgm-go-back-button').on('click', function() {
jQuery('form.checkout').append('<input type="hidden" name="cw-wgm-button-back" value="back"/>');
});
jQuery('form.checkout').on('submit', function(){
return CheckoutObject.placeOrder();
});
jQuery("html, body").animate({
scrollTop: jQuery("form.checkout").offset().top - 100
}, 1e3);
}
else {
window.location = decodeURI( redirectUrl );
}
});
}
else if(typeof result.ajaxScriptUrl !== 'undefined'){
jQuery.getScript(result.ajaxScriptUrl, function() {
eval("var callbackFunction = " + result.submitCallbackFunction);
callbackFunction(getFormFieldValues('ogonecw-preview-fields', selectedPaymentMethod.toLowerCase()));
});
}
else {
var newForm = '<form id="ogonecw_preview_form" action="' + result.form_action_url + '" method="POST">';
newForm += result.hidden_form_fields;
newForm += generateHiddenFields(getFormFieldValues('ogonecw-preview-fields', selectedPaymentMethod.toLowerCase()));
newForm += '</form>';
jQuery('body').append(newForm);
jQuery('#ogonecw_preview_form').submit();
}
}
});
So what exactly is causing this error since the plugin seems to be setup correctly

Jquery Not Synchronized with the DOM

I found a new problem where when i manipulate the dom using jquery. The dom is not updated.
Here we go.
var PostCard = function($root) {
this.$root = $root;
this.stuff_id = this.$root.data('stuff_id');
this.id = this.$root.data('id');
this.is_owner = this.$root.data('is_owner');
this.$propose_button = null;
this.$favorite_button = null;
this.init();
this.initEvents();
};
PostCard.prototype.init = function () {
this.$propose_button = this.$root.find("." + PostCard.prototype.CSS_CLASSES.PROPOSE_BUTTON);
this.$proposal_box_modal = this.$root.find("." + PostCard.prototype.CSS_CLASSES.PROPOSAL_MODAL);
this.$proposal_box = this.$root.find("." + PostCard.prototype.CSS_CLASSES.PROPOSAL_BOX);
this.$favorite_button = this.$root.find(".post-card-button-favorite");
this.$total_favorite = this.$root.find('.post-card-total-favorite');
this.$image_view_editor = this.$root.find("#" + this.id + "-image-view");
this.image_view_editor = new ImageViewEditor(this.$image_view_editor);
this.proposal_box = new HomeProposalBox(this.$proposal_box);
};
PostCard.prototype.initEvents = function() {
var self =this;
$(document).on("click", "#" + this.id,function(e) {
if(e.target && $(e.target).hasClass('post-card-button-propose') ){
if(self.is_owner ) {
return false;
}
if(CommonLibrary.isGuest()) {
return false;
}
self.$proposal_box_modal.modal("show").load($(this).attr("value"));
} else if(e.target && $(e.target).hasClass('post-card-button-favorite')) {
self.clickFavoriteButton_();
}
});
PostCard.prototype.clickFavoriteButton_ = function() {
this.markFavorite();
};
PostCard.prototype.markFavorite = function() {
this.$favorite_button.addClass('post-card-button-red');
};
When Favorite button is clicked, the clickFavoriteButton() will be trigerred, and markfavorite method will be fired next.
The problem is although this.$favorite_button is updated (the class is added to the variable), the dom in the page is not updated
this only happens to dynamically loaded element, and does not happen to element that has been around since the page is loaded.
The PostCard is created in PostList class
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
var PostList = function($root) {
this.$root = $root;
this.stuff_ids = '';
this.id = $root.data('id');
this.location = $root.data('location');
this.query = '';
this.post_cards = [];
this.$post_list_area = null;
this.permit_retrieve_post = true;
this.init();
this.initEvents();
};
PostList.prototype.SCROLL_VALUE = 95;
PostList.prototype.init = function() {
$.each($(".post-card"), function(index, value) {
this.post_cards.push(new PostCard($(value)));
if(this.stuff_ids === '' ) {
this.stuff_ids += $(value).data('stuff_id');
} else {
this.stuff_ids += "," + $(value).data('stuff_id');
}
}.bind(this));
this.$post_list_area = this.$root.find('.post-list-area');
};
PostList.prototype.initEvents = function() {
$(window).scroll({self:this}, this.retrievePostWhenScroll_);
};
PostList.prototype.retrievePostWhenScroll_ = function(e) {
var self = e.data.self;
var scrollPercentage =
((document.documentElement.scrollTop + document.body.scrollTop) /
(document.documentElement.scrollHeight - document.documentElement.clientHeight) * 100);
if(scrollPercentage > PostList.prototype.SCROLL_VALUE) {
if(self.permit_retrieve_post) {
self.permit_retrieve_post = false;
$.ajax({
url: $("#base-url").val() + "/site/get-more-posts",
type: 'post',
data: {'ids' : self.stuff_ids, query: self.query, location: self.location},
success: function(data) {
var parsedData = JSON.parse(data);
if(parsedData['status'] === 1) {
self.$post_list_area.append(parsedData['view']);
$(parsedData['view']).filter('.post-card').each(function(index, value) {
self.post_cards.push(new PostCard($(value)));
self.stuff_ids += "," + $(value).data('stuff_id');
});
}
self.permit_retrieve_post = true;
},
error : function(data) {
self.permit_retrieve_post = true;
}
});
}
}
};
When you scroll the page, the retrieveWhenScroll method will be fired and PostCard will be dynamically added

Uncaught TypeError: Cannot read property 'contains' of null

I'm currently working on a project, where I'm using the following slider in the overal site:
S3Slider
For the particular page I'm currently working on I'm also making use of Walter Zorns' Drag&Drop image library. (Link Here)
Now when I start to make use of the SET_DHTML function, which is required for using the D&D library, my slider starts throwing errors:
Uncaught TypeError: Cannot read property 'contains' of null
The line number given, sends me to the following line:
if($(itemsSpan[currNo]).css('bottom') == 0) {
Which lies in the following piece of code:
s3Slider = function(id, vars) {
var element = this;
var timeOut = (vars.timeOut != undefined) ? vars.timeOut : 2000;
var current = null;
var timeOutFn = null;
var faderStat = true;
var mOver = false;
var items = $("#sliderContent .sliderTopstory");
var itemsSpan = $("#sliderContent .sliderTopstory span");
items.each(function(i) {
$(items[i]).mouseover(function() {
mOver = true;
});
$(items[i]).mouseout(function() {
mOver = false;
fadeElement(true);
});
});
var fadeElement = function(isMouseOut) {
var thisTimeOut = (isMouseOut) ? (timeOut/2) : timeOut;
thisTimeOut = (faderStat) ? 10 : thisTimeOut;
if(items.length > 0) {
timeOutFn = setTimeout(makeSlider, thisTimeOut);
} else {
console.log("Poof..");
}
}
var makeSlider = function() {
current = (current != null) ? current : items[(items.length-1)];
var currNo = jQuery.inArray(current, items) + 1
currNo = (currNo == items.length) ? 0 : (currNo - 1);
var newMargin = $(element).width() * currNo;
if(faderStat == true) {
if(!mOver) {
$(items[currNo]).fadeIn((timeOut/6), function() {
/* This line -> */if($(itemsSpan[currNo]).css('bottom') == 0) {
$(itemsSpan[currNo]).slideUp((timeOut/6), function( ) {
faderStat = false;
current = items[currNo];
if(!mOver) {
fadeElement(false);
}
});
} else {
$(itemsSpan[currNo]).slideDown((timeOut/6), function() {
faderStat = false;
current = items[currNo];
if(!mOver) {
fadeElement(false);
}
});
}
});
}
} else {
if(!mOver) {
if($(itemsSpan[currNo]).css('bottom') == 0) {
$(itemsSpan[currNo]).slideDown((timeOut/6), function() {
$(items[currNo]).fadeOut((timeOut/6), function() {
faderStat = true;
current = items[(currNo+1)];
if(!mOver) {
fadeElement(false);
}
});
});
} else {
$(itemsSpan[currNo]).slideUp((timeOut/6), function() {
$(items[currNo]).fadeOut((timeOut/6), function() {
faderStat = true;
current = items[(currNo+1)];
if(!mOver) {
fadeElement(false);
}
});
});
}
}
}
}
makeSlider();
};
Why is this error being thrown?
Thanks.
I think your problem lies in these two lines:
var currNo = jQuery.inArray(current, items) + 1
currNo = (currNo == items.length) ? 0 : (currNo - 1);
If jQuery doesn't find the item in the array, it's going to send you a value of -1 (on the top line) which will then be changed to 0 because you added 1. Now, if currNo is 0 on the second line, it's going to change it back to -1, which will return you undefined. Maybe try and change it to do this instead:
var currNo = jQuery.inArray(current, items);
if (currNo === items.length - 1) {
currNo = 0;
}
I'm not positive this is the problem, but I can see this becoming an issue if it's not the problem you're currently having.

Up/Down/Left/Right keyboard navigation with jQuery?

I have a list of div's all with a set and equal height/width that are float:left so they sit next to each other and fold under if that parent is smaller than the combined with of the items.
Pretty standard.
This is to create a list of the twitter bootstrap icons, it gives something like this:
I have added next/previous keyboard navigation using the code below, however you will notice that the up/down arrow keys are mapped to call the left/right functions. What I have no idea how to do is to actually do the up/down navigation?
JsFiddle
(function ($) {
$.widget("ui.iconSelect", {
// default options
options: {
},
$select: null,
$wrapper: null,
$list: null,
$filter: null,
$active: null,
icons: {},
keys: {
left: 37,
up: 38,
right: 39,
down: 40
},
//initialization function
_create: function () {
var that = this;
that.$select = that.element;
that.$wrapper = $('<div class="select-icon" tabindex="0"></div>');
that.$filter = $('<input class="span12" tabindex="-1" placeholder="Filter by class name..."/>').appendTo(that.$wrapper);
that.$list = $('<div class="select-icon-list"></div>').appendTo(that.$wrapper);
//build the list of icons
that.element.find('option').each(function () {
var $option = $(this);
var icon = $option.val();
that.icons[icon] = $('<a data-class="' + icon + '"><i class="icon ' + icon + '"></i></a>');
if ($option.is(':selected')) {
that.icons[icon].addClass('selected active');
}
that.$list.append(that.icons[icon]);
});
that.$wrapper.insertBefore(that.$select);
that.$select.addClass('hide');
that._setupArrowKeysHandler();
that._setupClickHandler();
that._setupFilter();
that.focus('selected');
},
focus: function (type) {
var that = this;
if (that.$active === null || that.$active.length == 0) {
if (type == 'first') {
that.$active = that.$list.find('a:visible:first');
} else if (type == 'last') {
that.$active = that.$list.find('a:visible:last');
} else if (type == 'selected') {
that.$active = that.$list.find('a.selected:visible:first');
that.focus('first');
}
}
that.$active.addClass('active');
var toScroll = ((that.$list.scrollTop() + that.$active.position().top)-that.$list.height()/2)+that.$active.height()/2;
//that.$list.scrollTop((that.$list.scrollTop() + top)-that.$list.height()/2);
that.$list.stop(true).animate({
scrollTop: toScroll,
queue: false,
easing: 'linear'
}, 200);
if (type === 'selected') {
return false;
}
that.$select.val(that.$active.data('class'));
that.$select.trigger('change');
},
_setupArrowKeysHandler: function () {
var that = this;
that.$wrapper.on('keydown', function (e) {
switch (e.which) {
case that.keys.left:
that.moveLeft();
break;
case that.keys.up:
that.moveUp();
break;
case that.keys.right:
that.moveRight();
break;
case that.keys.down:
that.moveDown();
break;
case 16:
return true;
case 9:
return true;
break;
default:
that.$filter.focus();
return true;
}
return false;
});
},
_setupFilter: function(){
var that = this;
that.$filter.on('keydown keyup keypress paste cut change', function(e){
that.filter(that.$filter.val());
});
},
_setupClickHandler: function () {
var that = this;
that.$list.on('click', 'a', function () {
that.$wrapper.focus();
that.$active.removeClass('active');
that.$active = $(this);
that.focus('first');
});
},
moveUp: function () {
var that = this;
return that.moveLeft();
},
moveDown: function () {
var that = this;
return that.moveRight();
},
moveLeft: function () {
var that = this;
that.$active.removeClass('active');
that.$active = that.$active.prevAll(':visible:first');
that.focus('last');
return false;
},
moveRight: function () {
var that = this;
that.$active.removeClass('active');
that.$active = that.$active.nextAll(':visible:first');
that.focus('first');
return false;
},
filter: function(word){
var that = this;
var regexp = new RegExp(word.toLowerCase());
var found = false;
$.each(that.icons, function(i, $v){
found = regexp.test(i);
if(found && !$v.is(':visible')){
$v.show();
} else if(!found && $v.is(':visible')){
$v.hide();
}
});
}
});
})(jQuery);
Perhaps something like this: http://jsfiddle.net/QFzCY/
var blocksPerRow = 4;
$("body").on("keydown", function(e){
var thisIndex = $(".selected").index();
var newIndex = null;
if(e.keyCode === 38) {
// up
newIndex = thisIndex - blocksPerRow;
}
else if(e.keyCode === 40) {
// down
newIndex = thisIndex + blocksPerRow;
}
if(newIndex !== null) {
$(".test").eq(newIndex).addClass("selected").siblings().removeClass("selected");
}
});
Basically, you set how many items there are in a row and then find the current index and subtract or add that amount to select the next element via the new index.
If you need to know how many blocks per row there are, you could do this:
var offset = null;
var blocksPerRow = 0;
$(".test").each(function(){
if(offset === null) {
offset = $(this).offset().top;
}
else if($(this).offset().top !== offset) {
return false;
}
blocksPerRow++;
});
To deal with your 'edge' cases, you could do:
if(newIndex >= $(".test").length) {
newIndex = $(".test").length - newIndex;
}
moveUp: function () {
var that = this;
var index = $(this).index();
var containerWidth = parseInt( $('.select-icon-list').innerWidth(), 10);
var iconWidth = parseInt( $('.select-icon-list > a').width(), 10);
var noOfCols = Math.floor( containerWidth / iconWidth );
var newIndex = ( (index - noOfCols) < 0 ) ? index : (index - noOfCols);
var elem = $('.select-icon-list > a')[index];
},
Cache what ever remains static.

Categories