Show/hide loop js issue - javascript

I need a little help with the JS for this show/hide function
Essentially in the site there is PHP loop which echos out the HTML code below X-number of times.
I needed some JS to allow me to target each individual instance with a show/hide function, unfortunately my knowledge of JavaScript is low - I had some assistance from a developer with the code below but I seem to have gone wrong somewhere down the line as the console returns this error message "Uncaught SyntaxError: Unexpected identifier"
Any insight or help into this will be much appreciated!
Thanks in advance
The HTML
<span class="contentShow" >Dropdown Text Here...</span>
<a id="prod_more_trigger" ><span>More...</span></a>
The JS
<script type="text/javascript">
$(document).ready(function()
{
var i = 0;
$(document).find('span.contentShow').each(function() {
$(this).attr('data-id', i++);
$('span.contentShow').hide();
});
i = 0;
$(document).find('a.prod_more_trigger').each(function() {
$(this).attr('data-id', i++);
$(this).click(function() {
var $span = $(document).find('span.content[data-id="' + $(this).attr('data-id) + "]');
$('span.contentShow').toggle('fast');
});
});
});
</script>

You are missing couple of quotes in this line below
find('span.content[data-id="' + $(this).attr('data-id) + "]');
supposed to be
find('span.content[data-id="' + $(this).attr('data-id') + '"]');
^ ^
| |
Missing the closing quote
Also your anchor looks like this
<a id="prod_more_trigger">
Supposed to be
<a class="prod_more_trigger">
Since you are using class selector in your JS
You need not create a local variable i to assign a value. $.each passes a index. And you do not need to nest the event handler inside the $.each loop
Code
$(document).ready(function () {
// Cache your selectors when using multiple times
var $content = $('span.contentShow'),
$trigger = $('a.prod_more_trigger');
$content.each(function (i) {
$(this).attr('data-id', i);
});
// This can be outside the loop
$content.hide();
$trigger.each(function (i) {
$(this).attr('data-id', i);
});
$trigger.click(function () {
var $span = $('span.content[data-id="' + $(this).attr('data-id') + '"]');
$content.toggle('fast');
});
});
Check Fiddle

On your code you specified prod_more_trigger as id, it should be class
HTML
<span class="contentShow" >Dropdown Text Here...</span>
<a class="prod_more_trigger" ><span>More...</span></a>

Related

For Loop to Programmatically hide elements

I am currently trying to programmatically hide div elements on a page using an Array and loop in jQuery, but it doesn't seem to work.
I have done alerts and console.log to confirm the array is firing and the loop is working through the items, but it's the .hide() method that seems to be giving issue. Any help would be appreciated.
Thanks
$(document).ready(function(){
var divsToHide = ["fin_0", "fin_1", "fin_2", "fin_3", "fin_4", "fin_5",
"fin_6", "fin_7", "fin_8", "fin_9", "fin_10", "fin_10-1", "fin_10-2", "fin_10-3",
"fin_10-4", "fin_10-5", "fin_10-6", "fin_10-7", "fin_10-8", "fin_10-9", "fin_20",
"fin_21", "fin_22", "fin_23"];
$.each(divsToHide, function(index, value)
{
var currentDiv = "div#" + value;
var stringCurrent = currentDiv.toString();
var currentHide = $(' stringCurrent ');
console.log(currentDiv);
currentHide.hide();
});
});
You should probably use:
var currentHide = $(stringCurrent);
Your code
var currentHide = $(' stringCurrent ');
has no reference to stringCurrent variable, it just try to find <stringCurrent> element.
Even better, you should use
$.each(divsToHide, function(index, value)
{
$("#" + value).hide()
});
since an element id should be unique to the document
You need to remove the ' around stringCurrent. Otherwise your string is not interpreted but jquery searches for ' stringCurrent '

jQuery 'not' function giving spurious results

Made a fiddle: http://jsfiddle.net/n6ub3/
I'm aware that the code has a LOT of repeating in it, its on the list to refactor once functionality is correct.
The behaviour i'm trying to achieve is if there is no selectedTab on page load, set the first tab in each group to selectedTab. If there is a selectedTab present, then use this as the default shown div.
However, as you can see from the fiddle its not working as planned!
If anyone has any ideas how to refactor this code down that'd be great also!
Change
if($('.tabs1 .tabTrigger:not(.selectedTab)')){
$('.tabs1 .tabTrigger:first').addClass('selectedTab');
}
to
if ( !$('.tabs1 .tabTrigger.selectedTab').length ) {
$('.tabs1 .tabTrigger:first').addClass('selectedTab');
}
Demo at http://jsfiddle.net/n6ub3/1/
They way you are doing it (the first code part) you are adding the .selectedTab class if there is at least one of the tabs in that group that is not selected at start .. (that means always)
Update
For a shortened version look at http://jsfiddle.net/n6ub3/7/
Your selector are doing exactly what you're writing them for.
$('.tabs3 .tabTrigger:not(.selectedTab)') is true has long as there is at least one tab that has not the selected tab (so always true in your test case).
So you should change the logic to !$('.tabs3 .tabTrigger.selectedTab').length which is true only if there are no selectedTab
WORKING DEMO with simplified code
$('.tabContent').hide();
$('.tabs').each(function(){
var search = $(this).find('div.selectedTab').length;
if( search === 0){
$(this).find('.tabTrigger').eq(0).addClass('selectedTab')
}
var selectedIndex = $(this).find('.selectedTab').index();
$(this).find('.tabContent').eq(selectedIndex).show();
});
$('.tabTrigger').click(function(){
var ind = $(this).index();
$(this).addClass('selectedTab').siblings().removeClass('selectedTab');
$(this).parent().find('.tabContent').eq(ind).fadeIn(700).siblings('.tabContent').hide();
});
That's all! You don't need all that ID's all around. Look at the demo!
With a couple of very minor changes you code can be reduced to:
$('.tabContent').hide();
$('.tabs').each(function(){
if($('.tabTrigger.selectedTab',$(this)).length < 1)
$('.tabTrigger:first').addClass('selectedTab');
});
$('.tabTrigger').click(function(){
var content = $(this).data('content');
$(this).parents('div').children('.tabContent').hide();
$(this).parents('div').children('.tabTrigger').removeClass('selectedTab');
$(this).addClass('selectedTab');
$('#' + content).show();
});
$('.tabTrigger.selectedTab').click();
Those changes are
Change the class on the surrounding div to just class="tabs.
Add a data-content attribute with the name of the associated content div
Live example: http://jsfiddle.net/gsTBQ/
Well, I'm a bit behind the times obviously; but, here's my updated version of your demo...
I have updated your fiddle as in the following fiddle: http://jsfiddle.net/4y3Xp/1/.
Basically I just tidied it up a bit, and to refactor I put everything in a separate function instead of having each of the cases in their own. This is basically just putting a new function in that does similar to what yours was doing (e.g. not modifying your HTML model), but I tried to clean it up a bit, and I also just made a function that took the tab number and did each of the items that way rather than needing a separate copy for each.
The main issue with the 'not' part of your query is that the function doesn't return a boolean; like all JQuery queries, it's returning all matching nodes. I just updated that part to return whether .selected was returning more than 0 results; if not, I go ahead and call the code to select the first panel.
Glad you got your problem resolved :)
$(document).ready(function(){
var HandleOne = function (i) {
var idxString = i.toString();
var tabName = '.tabs' + idxString;
var tabContent = tabName + ' .tabContent';
$(tabContent).hide();
var hasSelected = $(tabName + ' .tabTrigger.selectedTab').length > 0;
if (!hasSelected)
$(tabName + ' .tabTrigger:first').addClass('selectedTab');
var selectedTabId =
$(tabName + ' .tabTrigger.selectedTab').attr('id');
var selectedContentId = selectedTabId.replace('tab','content');
$('#' + selectedContentId).show();
$(tabName + ' .tabTrigger').click(function() {
$(tabName + ' .tabTrigger').removeClass('selectedTab');
$(tabName + ' .tabContent').hide();
$(this).addClass('selectedTab');
var newContentId = $(this).attr('id').replace('tab','content');
$('#' + newContentId).show();
});
}
HandleOne(1);
HandleOne(2);
HandleOne(3);
});

How to create an hyperlink whose onclick handler is an anonymous function?

I am trying to generate dynamically the onclick event handlers of the cells of a flexigrid-generated table:
// ...
preProcess: function (data) {
var rows = data.rows;
for (var i = 0; i < rows.length; ++i) {
var row = rows[i];
// If and only if this condition is true, then
// row.cell[0] must be converted into a hyperlink.
if (row.cell[1] != '0') {
// I don't want to use the href attribute, because that would
// force me to define a non-anonymous function.
row.cell[0] = '<a href="javascript:void(0)" id="E'
+ i + '">' + row.cell[0] + '</a>';
// So I'm going to try assigning the onclick attribute.
$('#E' + i).click(function () {
window.open('doc.php?q=' + this.id, 'D' + this.id,
'menubar=0,toolbar=0,directories=0,location=0,status=0,' +
'resizable=0,scrollbars=0,width=600,height=300');
});
$('#E' + i).click().id = row.cell[4];
}
}
return data;
}
// ...
However, when I click on the generated hyperlinks, they don't work. What's the problem? My use of closures? The <a> tag doesn't accept the onclick attribute?
NOTE: Since I began using jQuery, my policy is all functions shall be anonymous functions. Please don't suggest me using an ordinary function.
Sounds like what you're looking for is live():
Attach a handler to the event for all elements which match the current selector, now and in the future
In effect, it allows you to create event handlers for elements that do not exist yet.
I get the feeling you only want to make minimal changes to your current code in order to make this work. In that case, live() is your best option since your code would only change from
$('#E' + i).click(function () { ...
to
$('#E' + i).live('click', function () { ...
Create the element using jQuery (or the browser's native dom functions) and attach an event handler:
$('<a href="#" id="E' + i + '"/>').html(row.cell[0]).click(function(e) {
e.preventDefault();
// your code
});
It looks like you're creating the <a> using raw string concatenation, and then assigning it... where? If the link isn't part of the DOM, then $('linkID') won't find anything, effectively assigning your click handler to nothing. jQuery selectors only search the DOM.
Firstly, it doesn't look like you're appending your with id='#E' + i.
So, I'd guess that when you call $('#E' + i), it's returning an empty jQuery object. You can check for this by alerting $('#E' + i).length. 0 means nothing was found.
Second, you don't need to the javascript:void(0) call. Just replace it with '#' and call event.preventDefault() in your anonymous function. You'll need to pass event as a parameter to the anonymous function, as well.
You are trying to hook up the onclick event on an element that doesn't exist yet. At the time, the element only exist as text in the array, as the code hasn't been added to the DOM, the selector can't find it.
If you want to use an anonymous function for the event handler, you have to wait to hook up the event until the element has been created so that it exists as an object.
Use jQuery's live event.
For ease of seeing what's going on, I'm also adding a class to the link because I'm assuming that there's other links on the page, .
function preProcess(data) {
...
row.cell[0] = '' + row.cell[0] + '';
}
jQuery("a.clickMe").live("click", function(event) {
event.preventDefault();
window.open('doc.php?q=' + this.id, 'D' + this.id, .....
});
Disclaimer: I've never used flexigrid, but from your other comments, it appears you are able to modify the content before flexigrid puts it in the DOM.
The live event lets up hook up a single handler (anonymous or not) before the element is added to the DOM.
See: jQuery live()
.live()
Attach a handler to the event
for all elements which match the
current selector, now and in the
future
I copied your code and, after a few minor corrections, I made it work. I assumed that data was referring to a table object. Here's my code together with dummy HTML.
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
</head>
<body>
<table id='myTable'>
<tr>
<td>x</td><td>1</td><td>a</td><td>f</td><td>p</td>
</tr>
<tr>
<td>y</td><td>2</td><td>b</td><td>g</td><td>q</td>
</tr>
</table>
<script>
function preProcess(data) {
var rows = data.rows;
for (var i = 0; i < rows.length; ++i) {
var row = rows[i];
// If and only if this condition is true, then
// row.cell[0] must be converted into a hyperlink.
if (row.cells[1] != '0') {
// I don't want to use the href attribute, because that would
// force me to define a non-anonymous function.
row.cells[0].innerHTML = '<a href="javascript:void(0)" id="E' + i + '">'
+ row.cells[0].innerHTML + '</a>';
// So I'm going to try assigning the onclick attribute.
$('#E' + i).click(function () {
window.open('doc.php?q=' + this.id, 'D' + this.id,
'menubar=0,toolbar=0,directories=0,location=0,status=0,' +
'resizable=0,scrollbars=0,width=600,height=300');
});
//$('#' + id).click().id = row.cells[4];
}
}
return data;
}
$(document).ready(function() {
preProcess(document.getElementById('myTable'));
});
</script>
</body>
</html>
My corrections were the following (I think some might be due to transcription when you were copying the code for the post):
I replaced cell with cells
I added innerHTML after the cell index
I set the link to javascript:void instead of javascript.void
I commented out the line $('#' + id).click().id = row.cells[4];, because I had no idea what it did.
With those changes it worked like a charm.
I hope this helps.

Javascript running twice

I have to develop a small application for school and I first designed in photoshop a bit and "converted" it into html. That went all fine. I created a custom dropdown with javascript and it worked smoothly. I've just tried implementing CodeIgniter into the design but the javascript started running twice.
I've tried comparing the code of the plain html version with the codeigniter result but I can't seem to find any difference.
Can any of you maybe help me?
Here's the CodeIgniter result:
http://intellia.itforit.net/index.htm
As asked by Krof Drakula here are the most important pieces of code:
The actual jquery plugin: (styleForm.js)
;(function($){
$.fn.styleForm = function() {
var form = this;
/* Select */
$('select', this).each(function(){
var div = '<div class="styledSelect"><ul>';
var first = false;
$('option', this).each(function(){
var cssclass = "";
if(!first) {
first = true;
cssclass = 'class="first"'
}
div += '<li ' + cssclass + ' id="' + $(this).attr("value") + '">' + $(this).text() + '</li>';
});
div += '</ul></div>';
$(this).hide();
$(this).after(div);
});
$('.styledSelect ul').toggle(function(){
$('li:not(.first)', this).show("fast");
}, function(){
$('li:not(.first)', this).hide("fast");
});
$('.styledSelect ul li:not(.first):not(.selected)').click(function(){
var id = $(this).attr('id');
var content = $(this).text();
$('.styledSelect ul li.first').attr('id', id).text(content);
$('.styledSelect ul li').css({'font-weight': 'normal'});
$(this).css({'font-weight': 'bold'});
/* SELECT in Select form item */
var selected = $('select option[value="' + id + '"]:not(.first)', form).get(0);
selected.setAttribute("selected", "selected");
//$(form).submit();
});
};
})( jQuery );
And here's where it gets launched: (canvasDrawing.js)
$(document).ready(function(){
$('form').styleForm();
//Unimportant canvas stuff
});
Thanx in advance,
Duckness
The problem is that your canvasDrawing.js, in the "unimportant canvas stuff", causes a javascript error. If the canvas it describes actually exists, your styleForm stuff only runs once. So add this to your HTML:
<canvas id="floorplan"></canvas>
And magic will happen. Or, in your canvasDrawing file, add clause like this right after styleForm:
var canvas = document.getElementById('floorplan');
if (!canvas)
return;
I'm not actually all that clear why having an error in that function causes it to run twice, but it's definitely the problem. See it: your code + a canvas element = working.

Read more/less without stripping Html tags in JavaScript

I want to implement readmore/less feature. i.e I will be having html content and I am going to show first few characters from that content and there will be a read more link in front of it. I am currently using this code :
var txtToHide= input.substring(length);
var textToShow= input.substring(0, length);
var html = textToShow+ '<span class="readmore"> … </span>'
+ ('<span class="readmore">' + txtToHide+ '</span>');
html = html + '<a id="read-more" title="More" href="#">More</a>';
Above input is the input string and length is the length of string to be displayed initially.
There is an issue with this code, suppose if I want to strip 20 characters from this string:
"Hello <a href='#'>test</a> output", the html tags are coming between and it will mess up the page if strip it partially. What I want here is that if html tags are falling between the range it should cover the full tag i.e I need the output here to be "Hello <a href='#'>test</a>" . How can I do this
Why not just hide the hidden part of the content instead of adding it later? I usually just use a display: none for hidden content and have it set to display: block when the read more is clicked..
Edit:
I'm sorry I didn't read the question good enough.
This should work though:
<div id="test">
This links to google
<strong>and</strong> some random text to make it a little bit longer!
</div>
<script type="text/javascript">
$(document).ready(function() {
var max_length = 21;
var text_to_display = "";
var index = 0;
var full_contents = $("#test").contents();
// loop through contents, stop after maxlength is reached
$("#test").contents().each(function(i) {
if ($(this).text().length + text_to_display.length < max_length) {
text_to_display += $(this).text();
index++;
} else {
return false;
}
});
// second loop removes unwanted content
$("#test").contents().each(function(i) {
if (i > index) {
$(this).remove();
}
return true;
});
// add link to show the full text
$('read more...').click(
function(){
$("#test").html($(full_contents));
$(this).hide();
}).insertAfter($("#test"));
});
</script>
This can be accomplished quite easilly using jQuery
<div id="test">This is a link to google</div>
<script type="text/javascript">
$(document).ready(function() {
alert($("#test").text());
});
</script>
Good luck!
You stated that the html tags would become an issue, so why not remove in the string conversion and replace with plain text, then on the Show More click, Toggle plain + Html
$(document).ready(function(){
var Contents = $('#post p'); //Object
var Plain = Contents.text(); //truncate this
//Hide the texts to Contents
Contents.hide();
var PlainContainer = $("<div>").addClass("Plain_Container").val(Plain)
//Add PlainContainer div after
Contents.append(PlainContainer);
var $('.show_hide').click(function(){
$(Plain_Container).remove(); //Delete it
Contents.Show(); //Show the orginal
$(this).remove(); //Remove the link
return false; //e.PreventDefault() :)
});
});
This way using the text() function will convert html tags to there values and remove the tag itself, all you have to do is toggle them :)
Note: The code above is not guaranteed to work and is provided as example only.

Categories

Resources