jQuery: Select elements with Incrementing ID names? - variables

and thanks in advance for your help!
Here's my situation: I have a set of divs whose IDs have an incrementing number applied to the end of the name using PHP. Each of these divs are added dynamically with PHP (They are a series of FAQ questions with a hidden div container with the answers, that slide down when the question is clicked.) [Live Example][1]
There is no limit to the number of questions that appear on the page, because this is being used for a Wordpress theme and my client wants to add new questions as they go along.
Here's an example of the structure for each FAQ question using the PHP:
<?php var $faqnum = 0; $faqnum++; ?>
<div id="faqwrap<?php $faqnum; ?>">
<h4>What data is shared?</h4>
<div id="faqbox<?php $faqnum; ?>" class="slidebox">
<p>Data sharing is defined by the type of service:</p>
<ul class="list">
<li>Third-party access to data (Enhanced Services only is strictly controlled and determined by the SDA)</li>
<li>All members must participate in points of contact and conjunction assessment but can choose whether to participate in other services</li>
<li>Participation in a service requires the member to provide associated data<br />
</ul>
</div>
</div>
Now this is what I have currently in jQuery, and it works, but only if I add a new one every time my client wants to add a new question.
$(document).ready(function() {
$('.slidebox*').hide();
// toggles the slidebox on clicking the noted link
$("#faqwrap1 a:not(div.slidebox a)").click(function() {
$("#faqbox1.slidebox").slideToggle('normal');
$('div.slidebox:not(#faqbox1)').slideUp('normal');
return false;
});
});
I thought of maybe doing something with a declared variable, like this:
for (var x = 0; x < 100; x++;) {
$('#[id^=faqwrap]'+ x 'a:not(div.slidebox a)')...
}
I hope this is clear enough for you! Again, I thank you in advance. :)

The best way to handle this is to not use the IDs, but use classes for the outer element. So your PHP would be altered like this:
<?php var $faqnum = 0; $faqnum++; ?>
<div id="faqwrap<?php $faqnum; ?>" class="question">
<h4>What data is shared?</h4>
<div id="faqbox<?php $faqnum; ?>" class="slidebox">
<p>Data sharing is defined by the type of service:</p>
<ul class="list">
<li>Third-party access to data (Enhanced Services only is strictly controlled and determined by the SDA)</li>
<li>All members must participate in points of contact and conjunction assessment but can choose whether to participate in other services</li>
<li>Participation in a service requires the member to provide associated data<br />
</ul>
</div>
</div>
Your JQuery would be rewritten with the selector for the class "question".
$(document).ready(function() {
$('.slidebox*').hide();
// toggles the slidebox on clicking the noted link
$(".question a:not(div.slidebox a)").click(function() {
/* close everything first */
$('div.slidebox').slideUp('normal');
/* selects and opens the the slidebox inside the div */
$(".slidebox", this).slideToggle('normal');
return false;
});
});
This will get you the effect you are looking for. The key differences in the JQuery is the way you get the slidebox inside the question that got clicked. I'm using the scoped selection $(".slidebox", this) to get just the slidebox inside the clicked ".question" element.
The subtle visual difference is that the slideUp() happens before the slideToggle(). This will essentially close any open queries before it opens the desired one. If you keep your animations fast, this will be more than fine. The advantage of this approach is that you don't have to worry about the count of questions on a page, and the selectors are most likely more optimized than the for loop.
Edit
I adjusted the PHP code to use a class for "slidetoggle" instead of an id. It's technically an HTML error to have multiple IDs that are the same. It can throw off some assistive technologies for people with dissabilities. I'm assuming that section of code was repeated several times on the page.

Without changing your current markup, this would work:
// toggles the slidebox on clicking the noted link
$("div[id=^faqwrap]").each(function () {
var $faqwrap= $(this);
$faqwrap.find("h4 > a").click(function () {
var $currentSlidebox = $faqwrap.children(".slidebox");
$currentSlidebox.slideToggle('normal');
$('div.slidebox').not($currentSlidebox).slideUp('normal');
return false;
});
});
Maybe you can find a few suggestions in the above code that help you.
Like #Berin, I'd also recommend giving a separate CSS class to the outer DIV and using that as a selector, instead of $("div[id=^faqwrap]").

Related

flying saucer page number + page count

I'm trying to configure a nice footer on a pdf document I'm generating using Flying Saucer.
But I'm having problems getting the page number and page count in a nice position.
Consider this bit of css:
div#page-footer {
position : running(footer);
// .. more styling .. //
}
div.page-number:before {
content: counter(page);
}
Using this bit of html will not give me a page number:
<div id="page-footer">
<div class="page-number"></div>
</div>
The only way I manage to get a page number if I move the class a level up.
<div id="page-footer" class="page-number">
</div>
But this does not allow me to add additional content in the footer or makes it really difficult to apply styling. I could add a separate footer just for the page number, but it would be quite hard to get the position just right.
Is there a way to get page number + page count in a footer that also contains other elements and styling?
Extra notes:
I simplified the footer a bit, in the original there is more in there, but even this simple example it is giving problems.
using span or div for the element does not make a difference.
You should use the id instead of the class to identify the div containing the page number.
This will work:
div#page-number:before {
content: counter(page);
}
<div id="page-footer">
<div id="page-number"></div>
</div>

How to check if there is a strikethrough on some text in selenium webdriver?

There are many planbox, which are having same class and ids, inside them there are a number of <p> tags and decorated text.
<div class="planbox">
<p class="baseprice">
<span>
<strike> $70 </strike>
</span>
</p>
<p> New discount price is etc. </p>
</div>
<div class="planbox">
<p class="baseprice">
<span> $70 </span>
</p>
</div>
Now, My test case is - if the base price is strikethrough, only then <p> 'New discount price .. </p> will show, otherwise not.
How to check whether a text is strikethrough or not? And even if we get this how will I check that <p> New discount.. </p> should not show if the text is not striked.
As there is no class in <p> tag on which I can check whether it displayed or not.
One solution in my mind was - add one dummy class in <span> tag and using findChildren('span.dummyCLass') it will result all the webelements having dummyClass.
Now I will check whether web-elements have strike tag or not, and this is the place where I got stuck.
Initially, i was thinking of a Jquery solution, but is it possible to do without adding new class and jquery?
You don't need to add a class to any element to accomplish this task. In general, you don't want to edit the HTML. Another issue is... if you can find the element to add a class, then you don't need to add the class to find the element. :)
The way I approach tasks like these is to find the outermost element that contains all the elements that you are interested in. I refer to this as a "container". What you want to do in this case is to find the containers and loop through them looking for the strikethrough price and for the "New discount price..." text.
The containers are DIVs with the planbox class. The strikethrough price is indicated by the STRIKE tag. The "New discount price..." text is in a P tag. With this info we can write some code. This is Java because I don't know what language you want and I'm not familiar with the Galen framework.
// gets the collection of containers using a CSS selector
List<WebElement> containers = driver.findElements(By.cssSelector("div.planbox"));
// loops through the containers
for (WebElement container : containers)
{
// determine if the STRIKE tag exists
boolean strikeExists = !container.findElements(By.tagName("strike")).isEmpty();
// determine if the "New discount price is..." text exists in the 2nd P tag
boolean discountPriceExists = container.findElements(By.tagName("p")).get(1).getText().trim().contains("New discount price is");
// if both are true log a pass, otherwise log a fail
if (strikeExists && discountPriceExists)
{
// log a pass
}
else
{
// log a fail
}
}
I haven't used much of selenium. But you can port this jquery code to selenium,
//if there is a strike element
if($(".baseprice span strike").length > 0){
//next() will select the sibling of the p tag with baseprice class
$("p.baseprice).next() != undefined){
return true
}else{
return false
}
}
you can use Galen for this. There you can verify certain CSS properties.

Two-Way binding in Windows 8 HTML / JavaScript Metro Apps

I'm trying to achieve a two way binding between an input field and a field in my JavaScript ViewModel. The binding has been wired up declarativly. Unfortunately the changes I do in the UI aren't reflected in my ViewModel.
My Code looks like that (written out of my head as I don't have the code here)
View:
<form data-win-bind="onsubmit: onCalculate">
<div class="field">
Product Name:
<input type ="number" data-win-bind="text:value1"/>
</div>
<div class="field">
Product Price:
<input type ="number" data-win-bind="text:value2"/>
</div>
<div class="field">
Result
<br />
<span data-win-bind="innerText: result" />
</div>
</form>
JavaScript
var model= WinJS.Class.define(
function() {
this.onCalculate = calculate.bind(this);
this.value1 = 0;
this.value2 = 0;
this.result = 0;
},{
value1: 0,
value2: 0,
result: 0
calculate: function() {
this.result = this.value1 + this.value2;
return false;
}
}, {});
// Make the model Observable
var viewModel = WinJS.Binding.as(new model());
WinJS.Binding.processAll(null, viewModel);
When I apply the binding, the ui shows my initial values. The form submition is correctly wired with the calculate function. The values of value1 and value2 however aren't updated with the users input.
What I'm trying to achive is to keep my JavaScript unaware of the underlying view. So I don't want to wire up change events for the html input fields in JavaScript.
Is there any way to achive this with pure WinJS? All samples I've found so far only do a one-way binding and use event listeners to update the ViewModel with changes from the UI.
WinJS only supports one-way binding for Win8. It is necessary to wire up listeners for change events in the UI elements, hence the nature of the samples you've seen. In other words, the implementation of WinJS.Binding's declarative processing doesn't define nor handle any kind of two-way syntax.
It would be possible, however, to extend WinJS yourself to provide such support. Since WinJS.Binding is just a namespace, you can add your own methods to it using WinJS.Namespace.define (repeated calls to this are additive). You could add a function like processAll which would also look for another data-* attribute of your own that specified the UI element and the applicable change events/properties. In processing of that you would wire up a generic event handler to do the binding. Since you have the WinJS sources (look under "References" in Visual Studio), you can see how WinJS.Binding.processAll is implemented as a model.
Then, of course, you'd have a great piece of code to share :)
This article provides a nice solution:
http://www.expressionblend.com/articles/2012/11/04/two-way-binding-in-winjs/

Jquery toggle div hide/show from dynamic id's

I have, essentially, an unlimited number of containers with dynamic ids and a dynamic menu to load each containers content. I have done this with static id's (but still seems such a heavy use) but do not know where to go to use dynamic.
When a nav link (from .img_select) is clicked it shows the corresponding div and hides all others in the group. It also updates the class of the menu items so the clicked item becomes selected, and the remaining become unselected.
<div id="pf1_1">
My content for pf1_1 container goes here
</div>
<div id="pf1_2">
My content for pf1_2 container goes here
</div>
<!-- This could have a dozen+ or more divs, or only 1 //-->
<p class="img_select"><span class="pf_current" id="pfc1_1">1-1</span> <span class="pf_next" id="pfc1_2">1-2</span></p>
<div id="pf2_1">
My content for pf2_1 container goes here
</div>
<div id="pf2_2">
My content for pf2_2 container goes here
</div>
<div id="pf2_3">
My content for pf2_3 container goes here
</div>
<!-- This could have a dozen+ or more divs or only 1 //-->
<p class="img_select"><span class="pf_current" id="pfc2_1">2-1</span> <span class="pf_next" id="pfc2_2">2-2</span> <span class="pf_next" id="pfc2_3">2-3</span></p>
the jquery I would like to create dynamically something similar to this
<script>
$(document).ready(function(){
$("#pf1_2").hide();
$("#pf2_2").hide();
$("#pf2_3").hide();
$('#pfc1_1').click(function(){
$("#pf1_2").hide('fast');
$("#pf1_1").show('fast');
$("#pfc1_1").removeClass("pf_next").addClass("pf_current");
$("#pfc1_2").removeClass("pf_current").addClass("pf_next");
});
$('#pfc1_2').click(function(){
$("#pf1_1").hide('fast');
$("#pf1_2").show('fast');
$("#pfc1_2").removeClass("pf_next").addClass("pf_current");
$("#pfc1_1").removeClass("pf_current").addClass("pf_next");
});
$('#pfc2_1').click(function(){
$("#pf2_2").hide('fast');
$("#pf2_3").hide('fast');
$("#pf2_1").show('fast');
$("#pfc2_1").removeClass("pf_next").addClass("pf_current");
$("#pfc2_2").removeClass("pf_current").addClass("pf_next");
$("#pfc2_3").removeClass("pf_current").addClass("pf_next");
});
$('#pfc2_2').click(function(){
$("#pf2_1").hide('fast');
$("#pf2_3").hide('fast');
$("#pf2_2").show('fast');
$("#pfc2_2").removeClass("pf_next").addClass("pf_current");
$("#pfc2_1").removeClass("pf_current").addClass("pf_next");
$("#pfc2_3").removeClass("pf_current").addClass("pf_next");
});
$('#pfc2_3').click(function(){
$("#pf2_2").hide('fast');
$("#pf2_1").hide('fast');
$("#pf2_3").show('fast');
$("#pfc2_3").removeClass("pf_next").addClass("pf_current");
$("#pfc2_2").removeClass("pf_current").addClass("pf_next");
$("#pfc2_1").removeClass("pf_current").addClass("pf_next");
});
});
</script>
If you can point me in the right direction, be much appreciated, thank you.
Seeing as I found a way, not saying was right way, but it worked, I wanted to share it with you.
I would like to point out it didn't take 2 months to sort a solution, just 2 months to post it here.
To combat this;
$("#pf1_2").hide();
$("#pf2_2").hide();
$("#pf2_3").hide();
I used this;
$("div[id^=pf_]").hide();
$("div[id$=_1]").show();
first it hides all id's starting with pf_
then it shows only the first by matching id ending in _1
To combat this;
$('#pfc1_1').click(function(){
$("#pf1_2").hide('fast');
$("#pf1_1").show('fast');
$("#pfc1_1").removeClass("pf_next").addClass("pf_current");
$("#pfc1_2").removeClass("pf_current").addClass("pf_next");
});
// etc.....
I used this;
$('span[id^=pfc_]').live("click", function(e) {
e.preventDefault();
var id = $(this).attr('id').split('_');
var classname = $(this).attr('class');
var navwidth = $("div[id^=pf_"+id[1]+"_"+id[2]+"]").width();
if(classname != 'pf_current'){
$("span[id^=pfc_"+id[1]+"_]").removeClass("pf_current").addClass("pf_next");
$("span[id^=pfc_"+id[1]+"_"+id[2]+"]").removeClass("pf_next").addClass("pf_current");
// change portfolio item
$("div[id^=pf_"+id[1]+"_]").hide();
$("div[id^=pf_"+id[1]+"_"+id[2]+"]").delay('5').show();
}
});
Hope this helps someone else

Access Elements of a DOJO DIV

I have two Hyper Links on to a DOJO DIv
var create = dojo.create("div",{
id:"create_links",
className:"iconRow1",
innerHTML:"<a class='popupLink' href='javascript:openCreateDialog()'>Create </a> <span>|</span><a href='javascript:openUploadDialog()'>Batch </a>"
},dojo.query(".ui-jqgrid-titlebar")[0]);
On click of the Batch Hyperlink , i have a function
function openUploadDialog()
{
// Here i want to disable the Create Hyper Link tried this way
dojo.byId('create_links')[1].disabled=true; // Not working
}
See whether i can answer your question.
HTML Part:
<div id="create_links">
g
h
</div>
JS Part:
dojo.addOnLoad(function() {
var a = dojo.query("#create_links a")[1];
dojo.connect(a,'click',function(e){
console.log(e.preventDefault())
})
})
#Kiran, you are treating the return of dojo.byId('create_links') like an array when that statement will return to you a node on the dom.
Also, hyperlinks don't support a disabled attribute to prevent them from being actionable. You could probably create a click handler that returns false to accomplish this type of functionality, or like #rajkamal mentioned, calling e.preventDefault(). #rajkamal also provides a good solution to selection the link properly.