Parent siblings not showing after hiding/showing - javascript

I have a simple in-page search function which shows only topics which contain words searched for.
Each section has a heading, a <h2> - I want the headings for the blocks which are not hidden, to show.
The problem: The h2 header does not always show after the search
This is a fiddle to test the issue
Fail/success examples:
One of the headings is Complaints and cancellations - sub section titled: How do I cancel
If you search for how do then you'll see the first block show, with header... the second block titled Guides disappears. This is correct.
If you search for I cancel - again, the second block disappears, which is correct, but, the heading for the first block hides too, which it shouldn't.
This is the javascript:
$("#faq_search").on("input", function () {
var v = $(this).val().toLowerCase();
$(".vc_tta-panel").each(function () {
var eachPlace = $(this).html().toLowerCase();
if (v != "" && eachPlace.search(v) == -1) {
$(this).parent().parent().parent().siblings('h2').hide();
$(this).fadeOut();
} else {
$(this).fadeIn('fast', function(){
$(this).parent().parent().parent().siblings('h2').show();
});
}
});
});
Is there a better way to do this?

The problem is that a hide of the h2 can occur after a show for the same section, depending on the order of matches in the section.
The quick solution is to do all the hides first, then the shows:
$("#faq_search").on("input", function () {
var v = $(this).val().toLowerCase();
$(".vc_tta-panel").each(function () {
var eachPlace = $(this).html().toLowerCase();
if (v != "" && eachPlace.search(v) == -1) {
$(this).closest('.vc_tta').siblings('h2').hide();
$(this).fadeOut();
}
});
$(".vc_tta-panel").each(function () {
var eachPlace = $(this).html().toLowerCase();
if (v == "" || eachPlace.search(v) > -1) {
$(this).fadeIn('fast', function(){
$(this).closest('.vc_tta').siblings('h2').show();
});
}
});
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/L0m3z98y/2/
Notes:
parent().parent().parent() is a not a maintainable solution. Any change to the DOM structure will break the code. Instead use closest() with an appropriate target selector. This is shorter and safer

Related

Sorting List Items by First Letter

I am trying to sort list items by their first letter. I am filtering by the .list-title div and then showing the .list-item which holds all of the contents. The problem is, I am using the show method directly on the filter method which is causing nothing to show as it needs to show the .list-item (parent) for the returned results. I am not sure how to rewrite this in any other way. How can I show the list item for each item returned?
$(document).ready(function() {
function filterResults(letter){
$('.list-item').hide();
$('li.list-item .list-title').filter(function() {
return $(this).text().charAt(0).toUpperCase() === letter;
}).show();
};
filterResults('A');
$('a').on('click',function(){
var letter = $(this).text();
filterResults(letter);
});
});
var $listItem = $('.list-item')
$('a').addClass(function(){
var s = this.textContent;
return $listItem.filter(function(){
return this.textContent.charAt(0) === s
}).length ? '' : 'grey';
})
JS Fiddle:
http://jsfiddle.net/2ewgr2mt/2/
You hide .list-item at first which contains everything else.So, when you show .list-title it won't be shown because its parent (.list-item) is hidden. The correct code should be
$(document).ready(function() {
function filterResults(letter){
$('.list-item').hide();
$('.list-item').filter(function() {
return $(this).find('.list-title').text().charAt(0).toUpperCase() === letter;
}).show();
};
filterResults('A');
$('a').on('click',function(){
var letter = $(this).text();
filterResults(letter);
});
var $listItem = $('.list-item')
$('a').addClass(function(){
var s = this.textContent;
return $listItem.filter(function(){
return this.textContent.charAt(0) === s
}).length ? '' : 'grey';
});
});
P/s: Remember to put everything inside ready, and also be careful when using the selector, in your original code you missed . in front of the class name selectors

Table Sorting with Javascript

I'm working on a table with filtering, I can get it to kind of function in fiddle but when I pop it back into DW and test the page it loses functionality. I have tried with the script on the page and inserted into the page, I'm at a loss of where to turn next so any help will be appreciated. I realize it's not complete and all the checkboxes arent set up properly but I really want to know (at this point) is why I lose functionality in dreamweaver - Correction when I test in a browser through Dreamweaver,I've also uploaded to a test server and still no functionality.
fiddle
$("input[name='filterStatus'], select.filter").change(function () {
var classes = [];
var stateClass = ""
$("input[name='filterStatus']").each(function() {
if ($(this).is(":checked")) {
classes.push('.'+$(this).val());
}
});
$("select.filter").each(function() {
if ($(this).val() != 'ZZ') {
stateClass += "." + $(this).val();
}
});
if (classes == "" && stateClass == "") {
// if no filters selected, show all items
$("#StatusTable tbody tr").show();
} else {
// otherwise, hide everything...
$("#StatusTable tbody tr").hide();
// then show only the matching items
rows = $("#StatusTable tr" + stateClass).filter(classes.length ? classes.join(',') : '*');
if (rows.size() > 0) {
rows.show();
}
}
I am sure JTable will solve your problem.
You need to pass the data in the given example's format and it will allow to filter, search and paginate the data.
http://jtable.org/GettingStarted

Accordion like form, will not work for me, can anyone see what i've done wrong here?

I'm make a rather long form, and I want to be able to break the form down into tabbable section, then when leaving that last input/select box, the next section will slide open, while the previous slides shut. I'm also wantning to have the fieldset legend, clickable to achieve the same thing.
A good example of what I'm looking for can be found here: http://jsfiddle.net/s4vcX/
Here is what I'm currently working with: http://jsfiddle.net/AUf3U/
If you'd like, you can see the current JavaScript code here:
$("fieldset label").hide();
$("fieldset ul").hide();
$("fieldset:first label").show();
// show when legend is clicked while hiding rest
$("legend").bind("click", function () {
$("fieldset label").not($(this).nextAll("label")).hide();
$(this).nextAll("label").show();
});
//handle shift-tab on first input of each field set
$("fieldset").find("input:first").bind("keydown", function (e) {
if( e.shiftKey && e.which == 9 ) {
$(this).closest(".hidesfieldset").find("label").hide();
var previous = $(this).closest(".hidesfieldset").prev(".hidesfieldset");
if(previous.length==0)
previous = $(this).closest("form").find(".hidesfieldset:last");
previous.find("label").show();
previous.find("input").last().focus();
e.preventDefault();
}
});
//handle tab on last input of each field set
$("fieldset").find("input:last").bind("keydown", function (e) {
if( !e.shiftKey && e.which == 9 ) {
$(this).closest(".hidesfieldset").find("label").hide();
var next = $(this).closest(".hidesfieldset").next(".hidesfieldset");
if(next.length==0)
next = $(this).closest("form").find(".hidesfieldset:first");
next.find("label").show();
next.find("input").first().focus();
e.preventDefault();
}
});
If someone can point out what`s going wrong here, I would be incredibly greatful, this has become a huge pain in the ass, and have to impelment this across about 50 forms, so changing the structure of my form is not necessarily a good thing.
The problem is your input selector, since you are using element selector it selects only elements with tag input but in your first fieldset the last element is a select element.
Try to use the :input selector
//handle shift-tab on first input of each field set
$("fieldset").find(":input:last").bind("keydown", function (e) {
if (e.shiftKey && e.which == 9) {
$(this).closest(".hidesfieldset").find("label").hide();
var previous = $(this).closest(".hidesfieldset").prev(".hidesfieldset");
if (previous.length == 0) previous = $(this).closest("form").find(".hidesfieldset:last");
previous.find("label").show();
previous.find("input").last().focus();
e.preventDefault();
}
});
//handle tab on last input of each field set
$("fieldset").find(":input:last").bind("keydown", function (e) {
if (!e.shiftKey && e.which == 9) {
$(this).closest(".hidesfieldset").find("label").hide();
var next = $(this).closest(".hidesfieldset").next(".hidesfieldset");
if (next.length == 0) next = $(this).closest("form").find(".hidesfieldset:first");
next.find("label").show();
next.find(":input").first().focus();
e.preventDefault();
}
});
Demo: Fiddle

How to match children innerText with user input using jQuery

I have the following structure:
<div id="campaignTags">
<div class="tags">Tag 1</div>
<div class="tags">Tag 2</div>
<div class="tags">Tag 3</div>
</div>
And I'm trying to match user input against the innerText of each children of #campaignTags
This is my latest attempt to match the nodes with user input jQuery code:
var value = "Tag 1";
$('#campaignTags').children().each(function(){
var $this = $(this);
if(value == $(this).context.innerText){
return;
}
The variable value is for demonstration purposes only.
A little bit more of context:
Each div.tags is added dynamically to div#campaignTags but I want to avoid duplicate values. In other words, if a user attempts to insert "Tag 1" once again, the function will exit.
Any help pointing to the right direction will be greatly appreciated!
EDIT
Here's a fiddle that I just created:
http://jsfiddle.net/TBzKf/2/
The lines related to this question are 153 - 155
I tried all the solutions, but the tag is still inserted, I guess it is because the return statement is just returning the latest function and the wrapper function.
Is there any way to work around this?
How about this:
var $taggedChild = $('#campaignTags').children().filter(function() {
return $(this).text() === value;
});
Here's a little demo, illustrating this approach in action:
But perhaps I'd use here an alternative approach, storing the tags within JS itself, and updating this hash when necessary. Something like this:
var $container = $('#campaignTags'),
$template = $('<div class="tags">'),
tagsUsed = {};
$.each($container.children(), function(_, el) {
tagsUsed[el.innerText || el.textContent] = true;
});
$('#tag').keyup(function(e) {
if (e.which === 13) {
var tag = $.trim(this.value);
if (! tagsUsed[tag]) {
$template.clone().text(tag).appendTo($container);
tagsUsed[tag] = true;
}
}
});
I used $.trim here for preprocessing the value, to prevent adding such tags as 'Tag 3 ', ' Tag 3' etc. With direct comparison ( === ) they would pass.
Demo.
I'd suggest:
$('#addTag').keyup(function (e) {
if (e.which === 13) {
var v = this.value,
exists = $('#campaignTags').children().filter(function () {
return $(this).text() === v;
}).length;
if (!exists) {
$('<div />', {
'class': 'tags',
'text': v
}).appendTo('#campaignTags');
}
}
});
JS Fiddle demo.
This is based on a number of assumptions, obviously:
You want to add unique new tags,
You want the user to enter the new tag in an input, and add on pressing enter
References:
appendTo().
filter().
keyup().
var value = "Tag 1";
$('#campaignTags').find('div.tags').each(function(){
if(value == $(this).text()){
alert('Please type something else');
}
});
you can user either .innerHTML or .text()
if(value === this.innerHTML){ // Pure JS
return;
}
OR
if(value === $this.text()){ // jQuery
return;
}
Not sure if it was a typo, but you were missing a close } and ). Use the jquery .text() method instead of innerText perhaps?
var value = "Tag 1";
$('#campaignTags').find(".tags").each(function(){
var content = $(this).text();
if(value === content){
return;
}
})
Here you go try this: Demo http://jsfiddle.net/3haLP/
Since most of the post above comes out with something here is another take on the solution :)
Also from my old answer: jquery - get text for element without children text
Hope it fits the need ':)' and add that justext function in your main customised Jquery lib
Code
jQuery.fn.justtext = function () {
return $(this).clone()
.children()
.remove()
.end()
.text();
};
$(document).ready(function () {
var value = "Tag 1";
$('#campaignTags').children().each(function () {
var $this = $(this);
if (value == $(this).justtext()) {
alert('Yep yo, return');)
return;
}
});
//
});

How to get link containing known text

A page contains a link with the text "Open Help". How to get the anchor containing that text with YUI?
YUI2 provides therefore the getElementsBy function. It has a filter methode attribute and with it you can check if the current element matches your purpose. Notice that you get an array with all matched elements. So you can pick the first if there was a hit.
http://developer.yahoo.com/yui/docs/YAHOO.util.Dom.html#method_getElementsBy
var elements,
searchText = "Open Help";
elements = YAHOO.util.Dom.getElementsBy(function (element) {
return (element.innerHTML === searchText) ? true : false;
}, "a", document);
if (elements.length > 0) {
//do something with elements[0]
}
On the other hand the YUI3 solution is in my opinion a cleaner way:
var searchText = "Open Help";
Y.all("a").each(function (el) {
if (el.getContent() === searchText) {
//do something with the el
}
});

Categories