Reusable jQuery truncate function - javascript

So I have created the following code to deal with one instance of a string that requires truncating with expandable and collapsable click events.
$(document).ready(function () {
var Element = $("[class*='truncate']");
var FullText = $(".truncate").text();
var Show = "<span class='show'> [...]</span>";
var Hide = "<span class='hide'> [ ]</span>";
var shortString = FullText.substring(0, 5);
if (FullText.length > 5) {
$(Element).html(shortString + Show);
}
$(Element).on("click", ".show", function () {
$(Element).html(FullText + Hide);
});
$(Element).on("click", ".hide", function () {
$(Element).html(shortString + Show);
});
});
Which truncates the following HTML
<div class="truncate">MBK-40B-FRLBBLCSLWLHBLHSLSALSAS32PDL</div>
The above code works perfectly for one instance of the class .truncate but when adding more things get a bit messy. How can I make this code work when there are many elements with this class, some of which will need to be truncated while others won't?

We can learn about the .each() jQuery method, here are some docs: http://api.jquery.com/each/
.each() will go through each element that was found with the selector and give you access to it through the this keyword, allowing you to run your code for one element at a time.
$(document).ready(function () {
var Show = "<span class='show'> [...]</span>";
var Hide = "<span class='hide'> [ ]</span>";
$(".truncate").each(function(){
var Element = this;
var FullText = $(Element).text();
var shortString = FullText.substring(0, 5);
if (FullText.length > 5) {
$(Element).html(shortString + Show);
}
$(Element).on("click", ".show", function () {
$(Element).html(FullText + Hide);
});
$(Element).on("click", ".hide", function () {
$(Element).html(shortString + Show);
});
});
});
There are better ways to do this, but .each() is a quick fix. What I would be concerned about is turning all those listeners off, I'm not sure what you are doing with your code later, but you don't want memory problems. Any suggestions?

https://jsfiddle.net/5dtmm9kn/
The JS
$('[truncate]').each(function( index ) {
var howmuch = $(this).attr('truncate');
var title = $( this ).text();
var shortText = jQuery.trim(title).substring(0, howmuch)
.split(" ").slice(0, -1).join(" ") + " <span>...</span>";
$( this ).html(shortText);
});
The html
<h3 truncate="40">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</h3>
The css
[truncate] span{
font-size: 0.6em;
opacity: 0.6;
}

Related

jquery cannot get div to show using this selector

I am querying the Twitch API for a list of users in my database, to see if they are online.
I am essentially listing them all, with "display: none" and then unhiding if online:
$('.online_list').each(function (index) {
var tnick = $(this).data('tnick');
$.getJSON("https://api.twitch.tv/kraken/streams?client_id={:twitch_key}&channel="+tnick+"", function(a) {
if (a["streams"].length > 0)
{
alert(tnick);
$(this).show();
console.log(index + ": " + $( this ).text());
}
});
});
In my testing, the alert(tnick) works perfectly, so I know it's running. The problem is $(this).show(); just isn't working.
Here's example HTML:
<div class="online_list" data-tnick="test" style="display: none;">test:Twitch <span>(Online)</span></div>
<div class="online_list" data-tnick="test2" style="display: none;">test2:Twitch <span>(Online)</span></div>
this is the current scope object!
to fix your code you can do the following:
$('.online_list').each(function (index) {
var $that = $(this); // create a temp var that
var tnick = $that.data('tnick');
$.getJSON("https://api.twitch.tv/kraken/streams?client_id={:twitch_key}&channel="+tnick+"", function(a) {
if (a && a["streams"] && a["streams"].length > 0) {
alert(tnick);
$that.show(); // use that instead of this
console.log(index + ": " + $that.text());
}
});
});
Check out this resource for more information on scope & this: http://javascriptplayground.com/blog/2012/04/javascript-variable-scope-this/
EDIT:
Also, like #djxak suggests, you can use the element parameter of the callback, that is more simple and clean in my opinion.
The #djxak suggests:
$('.online_list').each(function (index, element) {
//... (scope1 code)
$.getJSON("", function(a) {
//... (scope2 code)
$(element).show();
});
});
My approach:
$('.online_list').each(function (index) {
//... (scope1 code)
var $current = $(this);
$.getJSON("", function(a) {
//... (scope2 code)
$current.show();
});
});
Info about each function and element parameter in jQuery docs: https://api.jquery.com/each/#each-function

repeating jquery function many times

I need to improve my jquery code where I repeat my function 6 times!!!
is there away to do a loop to shorten the code ?
(function( jQuery ){
jQuery.fn.vesta = function(imgN){
var imgPath = "http://localhost:8080/mhost/media/magentohost/vesta/vesta"
var currImg = imgPath + imgN + ".png";
var targetImg = jQuery('.img-browser img');
jQuery('.img-browser img').attr('src', currImg);
}
})( jQuery );
jQuery('.vesta1').on('click', function (e) {
jQuery('.vesta1').vesta(1);
});
jQuery('.vesta2').on('click', function (e) {
jQuery('.vesta2').vesta(2);
});
jQuery('.vesta3').on('click', function (e) {
jQuery('.vesta3').vesta(3);
});
jQuery('.vesta4').on('click', function (e) {
jQuery('.vesta4').vesta(4);
});
jQuery('.vesta5').on('click', function (e) {
jQuery('.vesta5').vesta(5);
});
jQuery('.vesta6').on('click', function (e) {
jQuery('.vesta6').vesta(6);
});
You can DRY this up by using a common class, and a data attribute to specify the parameter to send to your vesta function:
<div class="vesta" data-vesta="1">1</div>
<div class="vesta" data-vesta="2">2</div>
<div class="vesta" data-vesta="3">2</div>
Then there is no need to loop at all:
$('.vesta').on('click', function (e) {
$(this).vesta($(this).data('vesta'));
});
Use a common class and a data attribute
jQuery('.vesta').on('click', function (e) {
var elem = $(this);
elem.vesta(elem.data("ind"));
});
and the HTML
<div class="vesta vesta1" data-ind="1">
Just put it into a for loop, and take advantage of the dynamic nature of JavaScript:
for (var i = 1; i <= 6; i++) {
$('.vesta' + i).on('click', (function (index) {
return function (e) {
$('.vesta' + index).vesta(index);
};
})(i));
}
I suppose you need the this reference along with some hack kind of thing
$('[class*=vespa]').on('click', function(e){
$(this).vesta(+(this.className.match(/vespa(\d+)/)[1]))
});
Here, we capture elements which have a class that matches at least vespa and then we use some bit of regex to match the digits after vespa and + unary operator changes the String version of numbers into actual numbers.
It would be quite easy if you can alter the structure of the HTML.
You would give all elements the same class, say vesta. But you also give them an attribute, say data-number. For example, like this:
<div class="vesta" data-number="4"></div>
Then, your jQuery code would be as simple as:
$(document).on({
click: function() {
var $this = $(this),
number = +$this.data('number');
$this.vesta(number);
}
}, '.vesta');
Edit:
I was a bit lazy with explaining the code snippet that I have provided an hour ago, but I am modifying my post now in response to the comments.
This code snippet will allow you to apply listeners from '.vesta1' elements to '.vestaN'
[#Variable]
NumberOfClasses - is the positive integer after 'vesta'. Eg: vesta1 ,vesta2, vesta100 ... etc
var NumberOfClasses=6;
for(var i=1;i<=NumberOfClasses;i++){
var className = '.vesta'+(i+1);
jQuery(className ).on('click', function (e) {
$(this).vesta(i);
});
}

Limit textarea characters by ID jquery

The goal: I'm trying to limit all my text boxes in all DIV ID named #boom1.
The problem: Can't get them all (a problem with the loop method in my opinion)
$(function () {
var maxL = 300;
$('#boom1').each(function (i, div) { //I got lost with syntax over here
var text = $('#boom1').text();
if(text.length > maxL) {
var begin = text.substr(0, maxL),
end = text.substr(maxL);
$('#boom1').html(begin)
.append($('<a class="readmore"/>').attr('href', '#').html('read more...'))
.append($('<div class="hidden" />').html(end));
}
});
$(document).on('click', '.readmore', function () {
$(this).next('.hidden').slideDown(750);
})
})
I'll be glad to get some help, with syntax if possible..
Thanks.
Attaching a DEMO
try using following code, working fine
$(function () {
var maxL = 300;
$('.wp-caption-text').each(function (i, div) {
//alert("dfs");
var text = $(this).text();
if(text.length > maxL) {
var begin = text.substr(0, maxL),
end = text.substr(maxL);
$(this).html(begin)
.append($('<a class="readmore"/>').attr('href', '#').html('read more...'))
.append($('<div class="hidden" />').html(end));
}
});
$(document).on('click', '.readmore', function () {
$(this).next('.hidden').slideDown(750);
})
})
$(function () {
var maxL = 300;
$('#boom1').each(function () { // If you don't use them you won't need them here
var text = $('#boom1').text();
if(text.length > maxL) {
var begin = text.substr(0, maxL),
end = text.substr(maxL);
$('#boom1').html(begin)
.append($('<a class="readmore"/>').attr('href', '#').html('read more...'))
.append($('<div class="hidden" />').html(end));
}
});
$(document).on('click', '.readmore', function () {
$(this).next('.hidden').slideDown(750);
});
});
DEMO
id must be unique.
Use classes for multiple usage .
added class boom to each div.
added read less... and read more... toggling feature too.
$(this) refers to the current element in the loop.
$(function () {
var maxL = 300;
$('.boom').each(function (i, div) {
var text = $(this).text();
if (text.length > maxL) {
var begin = text.substr(0, maxL),
end = text.substr(maxL);
$(this).html(begin)
.append($('<a class="readmore"/>').attr('href', '#').html('read more...'))
.append($('<div class="hidden" />').html(end));
}
});
$(document).on('click', '.readmore', function () {
$(this).html(function(_,ctr){
return (ctr == 'read more...') ? 'read less...':'read more...'
});
$(this).next('.hidden').slideToggle(750);
});
});
.each() makes you loop through all instances of an element, so you shouldn't use an ID. The following would iterate on every "some-class" element.
<div class="some-class"></div>
<div class="some-class"></div>
$('.some-class').each(function (i, div) {/* code*/ });
I don't think you can use each on an id - it will only get you the first one. Identifiers should be unique and only appear once per page. So only the first one will be used.
Try adding a class to each '#boom1'.. for example '.boom-class' and then doing jQuery each on it.

Event doesn't get added in a for-loop

This is the html. If a link is clicked I want to replace the span-element in front of it with some text.
<p><span id="sp1">that1</span> Update1</p>
<p><span id="sp2">that2</span> Update2</p>
<p><span id="sp3">that3</span> Update3</p>
<p><span id="sp4">that4</span> Update4</p>
<p><span id="sp5">that5</span> Update5</p>
As you can see, my idea was to give the spans en the anchors identical id's and a number.
In my jquery-code I loop through all the anchor-elements, give them a click-event that causes the span-element in front of it to be replaced.
<script type="text/javascript" >
$(document).ready(function() {
var numSpans = $("span").length;
for (n=0;n<=numSpans;n++) {
$("a#update" + n).click(function(e){
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
});
</script>
For some reason this does not work.
What am I doing wrong?
The problem with your original code is that you're creating a closure on the variable n. When the event handler is called, it is called with the value of n at the point of invocation, not the point of declaration. You can see this by adding an alert call:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(function(e) {
alert(n); //Alerts '6'
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
})
One way to fix this is to create a closure on the value of n in each iteration, like so:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(
(function(k) {
return function(e) {
alert(k);
$('span#sp' + k).replaceWith('this');
e.preventDefault();
}
})(n)
);
}
})
However, this is messy, and you'd do better to use a more jQuery-y method.
One way to do this would be to remove the ids from your code. Unless you need them for something else, they're not required:
<p><span>that1</span> Update1</p>
<p><span>that2</span> Update2</p>
<p><span>that3</span> Update3</p>
<p><span>that4</span> Update4</p>
<p><span>that5</span> Update5</p>
jQuery:
$(function() {
$('a.update').live('click', function() {
$(this).siblings('span').replaceWith("Updated that!");
});
});
jsFiddle
Don't create functions in a loop. With jQuery, there's no need for an explicit loop at all.
$(function()
{
$('span[id^=sp]').each(function(n)
{
$('#update' + n).click(function(e)
{
$('#sp' + n).replaceWith(this);
return false;
});
});
});
Demo: http://jsfiddle.net/mattball/4TVMa/
You can do way better than that, though:
$(function()
{
$('p > a[id^=update]').live('click', function(e)
{
$(this).prev().replaceWith(this);
return false;
});
});
Demo: http://jsfiddle.net/mattball/xySGW/
Try this:
$(function(){
$("a[id^='update']").click(function(){
var index = this.id.replace(/[^0-9]/g, "");
$("span#sp" + index).replaceWith(this);
e.preventDefault();
});
});

my jquery code dont work?

UCCN1003Edit
<script type="text/javascript">
$(function(){
$('a.edit').click(function(event){
var change = $(this).parent('div').find('p');
var changeText = change.text();
var wrapper = $(this).parent('div');
var clone = change.clone(true);
var changeBox = $(this).parent('div').find('.editBox');
var changeBoxText = changeBox.val();
if($(this).text() == 'Edit'){
wrapper.prepend("<input class='editBox' type='text' value='"+ changeText + "'/>");
wrapper.append("<a href='#' class='save' style='margin-left:10px' >Save</a>");
change.remove();
$(this).text("cancel");
}else if($(this).text()=='cancel'){
wrapper.prepend("<p>" + changeBoxText +"</p>");
$('.editBox').remove();
$('.save').remove();
$(this).text('Edit');
}
});
$('.save').click(function(event){
var editBox = $(this).parent('div').find('.editBox');
var editBoxText = editBox.text();
var wrapper = $(this).parent('div');
wrapper.prepand("<p>" + editBoxText + "</p>");
editBox.remove();
$(this).remove();
});
});
</script>
My part that work work is
$('.save').click(function(event){
var editBox = $(this).parent('div').find('.editBox');
var editBoxText = editBox.text();
var wrapper = $(this).parent('div');
wrapper.prepand("<p>" + editBoxText + "</p>");
editBox.remove();
$(this).remove();
});
where the wrapper wont prepand the p tag and the editBox and the .save wont be remove.
i try to add alert("work") in this and it wont alert at all. anyone know why?
It's this bit: .prepand(), should be: .prepend() :)
Currently it would throw a .prepand() is not a function error, something along those lines, for a shorter complete version you can use .prependTo() as well:
$('.save').live('click', function() {
var editBox = $(this).parent('div').find('.editBox').remove();
$("<p />", { text: editBox.val() }).prependTo($(this).parent('div'));
$(this).remove();
});
At second glance I see you're adding these dynamically, in which case you should use .live() like I have above, the .click() with a selector won't find these elements created later, so it'll never run :)

Categories

Resources