word counting Jquery function - javascript

here is the script for counting words.
Can it be made simple?
on deleting all or partial of the words it does not update the values. i tried but could not come up with anything. How can it be done?
"Can it be made simple?" This shall be counted as FIVE words. But check this [without quotes] this script copunts it SIX. What is wrong?
HTML
Message:
Total word Count : 0 words.
jquery
$(document).ready(function () {
$('#word_count').wordCount();
});
jQuery.fn.wordCount = function (params) {
var p = {
counterElement: "display_count"
};
var total_words;
if (params) {
jQuery.extend(p, params);
}
//for each keypress function on text areas
this.keypress(function () {
total_words = this.value.split(/[\s\.\?]+/).length;
jQuery('#' + p.counterElement).html(total_words);
});
};
fiddle
http://jsfiddle.net/ZmbxS/

Can it be made simple?
sure can, use a word boundary matching anything that isn't whitespace :
$('#word_count').on('keyup', function() {
$('#display_count').text(this.value.split(/\b\S+\b/g).length-1)
});
FIDDLE
and it seems like a wasted use of a plugin for something that can be done that easily ?

See this:
Demo
You need to "trim" your value to ensure that there are no leading/trailing spaces (which produce mentioned +1)
I've attached this handler to keyup event instead.
Code:
this.keyup(function () {
my_value = this.value.replace(/^\s+|\s+$/, '');
total_words = my_value.split(/[\s\.\?]+/).length;
jQuery('#' + p.counterElement).html(total_words);
});

I think it is a matter on the event you're using. I'd suggest you to bind the function to the change event.
For the regexp, it is not enough to make the split just by?:
stringValue.split(/\s/);
Best regards.

Related

How can I loop variables with Jquery

I'm new with Javascript and Jquery and I'm facing a small problem.
I'm trying to make sure that if a given link exists, hovering over this link will bring up a popup with the fadeToggle().
So I wrote this code that works:
if ($('.link-1')) {
$('.link-1').mouseover(function () {
$('.popup-1').fadeToggle();
})
.mouseout(function () {
$('.popup-1').fadeToggle();
})
}
But, instead of repeating it ten times, I wanted to write a loop, like this:
var number = 0;
while (number < 10) {
var popup = '.popup-' + number;
var link = '.link-' + number;
if ($(link)) {
$(link).mouseover(function () {
$(popup).fadeToggle();
})
.mouseout(function () {
$(popup).fadeToggle();
})
}
number++;
}
But it does not work. Could you help me please ?
I thank you in advance !
Based on your comments, I'd recommend this approach.
Add a data attribute to each link that corresponds with the popup you want to fire. This will look something like this:
<a href='#' class='link-1' data-popup='popup-1'> Link </a>
Then add a hover event to ALL links, that performs an action if it has the data type:
//hover event on all links(assumes anchor tags)
$('a').mouseover(function () {
if ($(this).attr('data-popup')) {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
}})
.mouseout(function () {
if ($(this).attr('data-popup')) {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
}})
You could also make this a single line function using .hover instead of .mouseover and .mouseout if it fits your use case
**refactoring process is added here:
//start with the original function
$('a').hover(function () {
if ($(this).attr('data-popup')) {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
}})
//consolidate the enter and exit events using .hover()
$('a').hover(function () {
if ($(this).attr('data-popup')) {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
}})
//remove the if statement, because the function firing without a pop up won't result in any effect
$('a').hover(function () {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
})
//substitute the variable directly into the jquery tag
$('a').hover(function () {
$(`'.${$(this).attr('data-popup')}`).fadeToggle();
})
// use an ES6 arrow function to make this a one line function
$('a').hover(() => $(`.${$(this).attr('data-popup')}`).fadeToggle())
//as is, this function won't work, because the arrow function binds the "this" keyword differently.
//Event handlers have an optional parameter that is an event JSON object, so we pass that into the function.
//Because it is a parameter, and is used as a variable we can call event "e" for short
//target is a property of the JSON object 'event' that indicates what specific element is triggering the event
// You can console log "e" to see what other values are baked into the event
$('a').hover((e) => $(`.${$(e.target).attr('data-popup')}`).fadeToggle())
//lastly, because we are using an anonymous arrow function with only one parameter, we can omit the parenthesis around the paremeter
$('a').hover(e => $(`.${$(e.target).attr('data-popup')}`).fadeToggle())
The end result is the one liner below!
$('a').hover(e => $(`.${$(e.target).attr('data-popup')}`).fadeToggle())
Additional info on data attributes can be found here:
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
welcome to the web community :-)
My jQuery skills are a bit rusty, but I recall, that there is an Attribute Contains Selector, which you could combine with .each() like so:
$('[class*="link-"]').each(function (index, link) {
$('[class="popup-"' + index + '"]').each(function (_, popup) {
$(link)
.mouseover(function () {
$(popup).fadeToggle();
})
.mouseout(function () {
$(popup).fadeToggle();
})
}
}
The second index is not interesting, that's why I named the argument „_”.
Let me know, whether it still works
If your objects are in order from link-1 to link-10, you can try this method
Loop object that has class "link-[number]" using each function
save number using index + 1
give action to object that have been hovered
so the code will be like this:
$('[class*="link-"]').each(function (index) {
var number = index + 1; //index start from 0, so it need to add + 1
$(this)
.mouseover(function () {
$('[class="popup-' + number+ '"]').fadeToggle();
})
.mouseout(function () {
$('[class="popup-' + number+ '"]').fadeToggle();
})
});
But if your object are not in order from link-1 to link-10, I recommend to use custom data attribute in your HTML code.
Example:
<a class="link-1" data-number="1">test 1</a>
<div class="popup-1" style="display:none">
test 1 popup
</div>
Then change number variable to this code:
var number = $(this).attr("data-number");
It will more save.
Hope it helps.

jquery variable using input field Name

I have a code like this:
var formFocus = formFocus || {
spanElement: ".focusOnLoad form input[name="FirstName"]";
init: function () {
$(document).ready(function() {
//come other computation
$(formFocus.spanElement).focus();
});
},
};
I am running into issues with this line: spanElement: ".focusOnLoad form input[name="FirstName"]";
I get an error at name="FirstName"
I tried escaping " with spanElement: ".focusOnLoad form input[name=\"FirstName\"]";Then I get Unexpected token ; error.
I can get the code working if I just use .focusOnLoad form input[name="FirstName"] as selector. But I need to use a variable since ist a shared code and some others without the knowledge of this part has to use this variable.
Is there a way to fix this?
var formFocus = formFocus || {
spanElement: ".focusOnLoad form input[name='FirstName']",
init: function () {
$(document).ready(function() {
//come other computation
$(formFocus.spanElement).focus();
}); }, };
You have here, you wrote
form input[name="FirstName"]";
Instead of:
form input[name='FirstName']",
The difference is: you terminated the line with semicolon instead of a comma, and also, you used double quote inside another double quote
Hope my answer helps 😉

Hiding images with same data value jquery

Im trying to code a site where the objective is to click on two identical images and it hides the both the images you've managed to match to eachother.
$(document).ready(function(){
var animal1;
var animal2;
$(".memory1").on("click", function(){
animal1 = $(this).data('animal');
});
$(".memory2").on("click", function(){
animal2 = $(this).data('animal');
if (animal1==animal2){
$(this).data('animal').hide();
}
else {
alert("Wrong, Try again!");
}
});
});
so the line where its going wrong is obviously
$(this).data('animal').hide();
But I cant figure out a way to hide both images, or a better way of going about it.. :/
http://jsfiddle.net/4vgfca76/
This doesn't work the way you think it does
$(this).data('animal').hide();
When data is used with one argument, it get's the data attribute, which you should already know as you're doing it a few lines above.
What you get is the string hund etc. and that string doesn't have a hide() method.
You should be using the attributes selector to select the elements with that attribute instead
$(document).ready(function () {
var animal1, animal2;
$(".memory1").on("click", function () {
animal1 = $(this).data('animal');
});
$(".memory2").on("click", function () {
animal2 = $(this).data('animal');
if (animal1 == animal2) {
$('img[data-animal="'+animal1+'"]').hide();
} else {
alert("Fel! Försök igen");
}
});
});

Refactoring Code

Let's say I have the following code:
$(function () {
$(".buy-it-now.ribbon").click(function () {
$(".bid-to-beat.ribbon.active").removeClass("active");
$(".bid-to-beat.ribbon").addClass("inactive");
$(".buy-it-now.ribbon.inactive").removeClass("inactive");
$(".buy-it-now.ribbon").addClass("active");
$(".bid-now").hide();
$(".buy-now").show();
$(".add-to-cart").hide();
})
$(".bid-to-beat.ribbon").click(function () {
$(".buy-it-now.ribbon.active").removeClass("active");
$(".buy-it-now.ribbon").addClass("inactive");
$(".bid-to-beat.ribbon").removeClass("inactive");
$(".bid-to-beat.ribbon").addClass("active");
$(".buy-now").hide();
$(".bid-now").show();
$(".add-to-cart").show();
});
});
It is a simple function that allows for multiple UI related things to happen on the front-end of a site I am working on. I am fairly (very) new to jQuery and JavaScript in general and am learning about refactoring and making my code more condensed now. The way I currently write code is sort of line per thought I have. So my question is how would an experienced developer write this same code? Or rather, how could I refactor this code?
Try the following:
$(function () {
var $handlers = $('.buy-it-now.ribbon, .bid-to-beat.ribbon');
$handlers.click(function() {
$handlers.toggleClass("active inactive");
var $elements = $(".bid-now, .add-to-cart"),
$buyElement = $(".buy-now");
if($(this).is('.buy-it-now.ribbon')) {
$elements.hide();
$buyElement.show();
} else {
$elements.show();
$buyElement.hide();
}
});
});
This question would be better suited for codereview, but yes it can be condensed a little using method chaining.
$(function () {
$(".buy-it-now.ribbon").click(function () {
$(".bid-to-beat.ribbon").removeClass("active").addClass("inactive");
$(".buy-it-now.ribbon").removeClass("inactive").addClass("active");
$(".bid-now").hide();
$(".buy-now").show();
$(".add-to-cart").hide();
})
$(".bid-to-beat.ribbon").click(function () {
$(".buy-it-now.ribbon").removeClass("active").addClass("inactive");
$(".bid-to-beat.ribbon").removeClass("inactive").addClass("active");
$(".buy-now").hide();
$(".bid-now").show();
$(".add-to-cart").show();
});
});
You could condense it further by pre selecting the elements and caching them in variables before the click events as long as no elements are added or removed during the life of the page.
As your code it is you can combine some of the selectors into a single line. And also because your elements looks to be static you can cache them into a variable and use them later as it reduces the number of times a element is looked up in the DOM reducing the accessing time..
Also you can limit the scope of these variables or selectors by encasing them in an object or a closure..
Maybe something in these lines..
$(function () {
cart.init();
});
var cart = {
elems : {
$buyRibbon : null,
$bidRibbon : null,
$bidNow: null,
$buyNow: null,
$addToCart: null
},
events : {
},
init : function() {
this.elems.$buyRibbon = $(".buy-it-now.ribbon");
this.elems.$bidRibbon = $(".bid-to-beat.ribbon");
this.elems.$bidNow = $(".bid-now") ;
this.elems.$buyNow = $(".buy-now") ;
this.elems.$addToCart = $(".add-to-cart") ;
this.events.buyClick();
this.events.bidClick();
}
};
cart.events.buyClick = function() {
cart.elems.$buyRibbon.on('click', function(){
cart.elems.$bidRibbon.removeClass('active').addClass('inactive');
cart.elems.$buyRibbon.removeClass('inactive').addClass('active');
cart.elems.$bidNow.hide();
cart.elems.$buyNow.show();
cart.elems.$addToCart.hide();
});
}
cart.events.bidClick = function() {
cart.elems.$bidRibbon.on('click', function(){
cart.elems.$buyRibbon.removeClass('active').addClass('inactive');
cart.elems.$bidRibbon.removeClass('inactive').addClass('active');
cart.elems.$bidNow.show();
cart.elems.$buyNow.hide();
cart.elems.$addToCart.show();
});
}
So basically in here your whole cart is a object ..And the cart has different properties which are related to this.. You follow the principles of object oriented programming here..
Using closures I heard gives you better design limiting the scope of your code..
Might I suggest something like this:
$(function () {
var buyNowButton = $('buy-it-now.ribbon'),
bidToBeatButton = $('.bid-to-beat.ribbon'),
buyNowEls = $('.buy-now'),
bidToBeatEls = $('.bid-now,.add-to-cart');
var toggleButtons = function(showBuyNow){
buyNowButton.toggleClass('active', showBuyNow);
bidToBeatButton.toggleClass('active', !showBuyNow);
buyNowEls.toggle(showBuyNow);
bidToBeatEls.toggle(!showBuyNow);
}
buyNowButton.click(function(){ toggleButtons(true) });
bidToBeatButton.click(function(){ toggleButtons(false) });
});
You could save a some lines by removing the selectors at the start and just do the selection in place, if the saved space would be more important than the minor performance hit. Then it would look like this:
$(function () {
var toggleButtons = function(showBuyNow){
$('buy-it-now.ribbon').toggleClass('active', showBuyNow);
$('.bid-to-beat.ribbon').toggleClass('active', !showBuyNow);
$('.buy-now').toggle(showBuyNow);
$('.bid-now,.add-to-cart').toggle(!showBuyNow);
}
$('buy-it-now.ribbon').click(function(){ toggleButtons(true) });
$('.bid-to-beat.ribbon').click(function(){ toggleButtons(false) });
});
The first version selects the elements once and holds them in memory; the second selects them each time the button is clicked. Both solve the problem I believe would occur with the selected answer where clicking the same button twice would cause the .active and .inactive classes to get out of sync with the shown/hidden elements.

jQuery: Call a function twice

I'm trying to run a function twice. Once when the page loads, and then again on click. Not sure what I'm doing wrong. Here is my code:
$('div').each(function truncate() {
$(this).addClass('closed').children().slice(0,2).show().find('.truncate').show();
});
$('.truncate').click(function() {
if ($(this).parent().hasClass('closed')) {
$(this).parent().removeClass('closed').addClass('open').children().show();
}
else if ($(this).parent().hasClass('open')) {
$(this).parent().removeClass('open').addClass('closed');
$('div').truncate();
$(this).show();
}
});
The problem is on line 13 where I call the truncate(); function a second time. Any idea why it's not working?
Edit jsFiddle here: http://jsfiddle.net/g6PLu/
That's a named function literal.
The name is only visible within the scope of the function.
Therefore, truncate doesn't exist outside of the handler.
Instead, create a normal function and pass it to each():
function truncate() { ...}
$('div').each(truncate);
What's the error message do you get?
You should create function and then call it as per requirement
Define the function
function truncate(){
$('div').each(function(){
});
}
Then call the function
truncate();
Another approach is to establish, then trigger, a custom event :
$('div').on('truncate', function() {
$(this).......;
}).trigger('truncate');
Then, wherever else you need the same action, trigger the event again.
To truncate all divs :
$('div').trigger('truncate');
Similarly you can truncate just one particular div :
$('div#myDiv').trigger('truncate');
The only prerequisite is that the custom event handler has been attached, so ...
$('p').trigger('truncate');
would do nothing because a truncate handler has not been established for p elements.
I know there's already an accepted answer, but I think the best solution would be a plugin http://jsfiddle.net/g6PLu/13/ It seems to be in the spirit of what the OP wants (to be able to call $('div').truncate). And makes for much cleaner code
(function($) {
$.fn.truncate = function() {
this.addClass('closed').children(":not('.truncate')").hide().slice(0,2).show();
};
$.fn.untruncate = function() {
this.removeClass('closed').children().show();
};
})(jQuery);
$('div').truncate();
$('.truncate').click(function() {
var $parent = $(this).parent();
if ($parent.hasClass('closed')) {
$parent.untruncate();
} else {
$parent.truncate();
}
});

Categories