Protractor code to extract multiple paragraph text - javascript

how to fetch the values of all paragraph (p) at a time ..
for example below is how my inspect view looks like
"testing sample one."
"testing sample two."
and below is my code sample to extract the value of id 'run'
browser.findElement(by.css('[id=run]')).getText()
this just extract the first value or I can modify and get the second value of id.. my need is I need to get both values at one go.. in the same line of code.. could you please advise

Though missing an html-example and a bit more description of what you like to extract, I'll give it a try.
In general you could/should use element.all(by.css()), aka $$(), instead of browser.findElements, except you know exactly, why you use findElements.
Read some details about the difference here.
Then as mentioned in a comment already, there is a findElements() (see API-Doc for findElements() here), returning an array of all values, matching the criteria. Just you can't immediately use getText() on it, as you get an array of elements and getText() requires a single element (see API-Doc for getText() here). Therefore you'd need to pass it through some loop.
Without knowing enough context here a small set of ideas to pick from.
var allP = new Array();
var allPString = null; //if one long string is desired
//here I'm using now element.all() instead of browser.findElements
var allPEl = $$('p#run'); //equal to element.all(by.css('p[id=run]')); //returns array of all found elements
var allPElBrowser = browser.findElements(by.id('run')); //returns array of all found elements
var i = allPEl.length();
var j = 0;
allPEl.each().getText().then(function(text){ //getAttribute('value') instead of getText(), if getText doesn't work.
allP.push(text); //add it to Array
allPString += text+' '; //add to String with a space at the end
j++; //counter
if(i === j-1){continueTest()}; //call continuation at the end of last loop, due to asynchronous nature of 'then()'.
});
continueTest = function(){
allP.toString() //in case of comma separated list from Array is desired
// here comes the rest of your test case logic
};
Note, that I go with the assumption that you need resolved promises, so the content of your <p>'s to continue.
If you can continue just with the array of <p>-objects, which you later resolve within an expect() all you need is $$('p#id');.
If the solution doesn't work for you, let me know, what part is still missing or where problems occur.

Related

Traverse XML with jQuery to get element value

I have some XML that looks like so:
<closure1>
<topClosure>
<ellipsoidalHead>
<standardComponentData>
<variousElements>
<idNumber>234567</idNumber>
<nominalThickness units="in">0.3750</nominalThickness>
</standardComponentData>
</ellipsoidalHead>
</topClosure>
</closure1>
<shell>
<standardComponentData>
<various_elements>
<nominalThickness units="in">0.6250</nominalThickness>
<idNumber>123456</idNumber>
</standardComponentData>
</shell>
<nozzle>
<standardComponentData>
<various_elements>
<attachedToidNumber>123456</attachedToidNumber>
</standardComponentData>
<nozzle>
In my JS code, I already have the <nozzle> element bomNode as a jQuery set, i.e.
var bomNode = $("nozzle");
So, for each nozzle element, I need to
Get the value of <attachedToidNumber> in the <nozzle> element.
Find the element that contains the <idNumber> that matches
<attachedToidNumber> (<shell> in this case).
Get the value in the <nominalThickess>
element.
As you can see, the depth of the desired <idNumber> element can vary. This is also a very small subset of the whole XML structure, so it can be very large.
I've tried something like this:
var attachedToElement = bomNode.parents().find('idNumber').text() === attachedToId;
but I get false returned. What's the easiest way to get the desired idNumber value? I'm sure it's something simple, but I'm just missing it.
Thanks.
UPDATE: I realized that bomNode is at the top level, I don't need to go up. a level. Doing something like this
var attachedToElement = bomNode.parents().siblings().find('idNumber')
gives me a list of children elements that have an <idNumber> element. So, I need to find the one that has the desired value. My thought is to use .each(). However, that value is defined outside of the .each() function, so I don't have anything to match against. Once I have the list of matches, what's the easiest way to get the set that has the <idNumber> value I want?
You were right - you missed a simple thing:
shell is not a parent of nozzle. They are siblings. Try this:
var attachedToElement = bomNode.siblings().find('idNumber').text() === attachedToId;
But this would return true (if true) - not the actual value.

syntax error in GAS script editor

I have an error in the following code and I can't find why...
Using UiApp I define a couple of ListBox like this in a for loop
var critGlist = app.createListBox().setName('critGlist'+n).setId('critGlist'+n).addChangeHandler(refreshGHandler).addChangeHandler(cHandlerG).setTag(listItem[n]);
I added a TAG to be able to retrieve a value in the handler function because when I add items to this list I do it like this :
for(var c=0;c<listItem[n].length;++c){
critGlist.addItem(listItem[n][c],c);// the returned value is c, the value shown is listItem[n][c]
}
Then in my handler function I retrieve the value c that is the index of an element of the array listItem[n]
Since I stored a stringified value of this array as a tag I have to retrieve the tag first and then using the index I get the desired value...
That's where it becomes problematic !
I tried the 3 following codes :
var idx = Number(e.parameter['critGlist'+c]);// this works and I get the index
var item = e.parameter.critGlist0_tag.split(',')[idx];// this also works for a fixed index (0 here) but I need to use it in a for loop so I tried the code below
var item = e.parameter['critGlist'+c]_tag.split(',')[idx];// this generates an syntax error
// error message :"Signe ; manquant avant l'instruction. (ligne 129, fichier "calculatrice Global")"
// which means : missing ; before statement (line 129...
Am I missing something obvious ? How should I write it differently ?
Obviously it is the underscore that is not accepted... but how could I not use it ?
Well, I have a few other possibilities to get the result I want (using a hidden widget for example or some other temporary storage of even let the listBox return the value instead of the index) but still I'd like to know why this syntax is wrong ...
I'm not asking for a different code (as mentioned before there are a lot of other ways to go) , just some explanation about what is wrong in this code and this #!##å»ÛÁØ underscore ;)
You will need to put the whole property within the brackets as below
var item = e.parameter['critGlist'+c+'_tag'].split(',')[idx];// this generates an syntax error

JQuery each() function code is running even when there are no elements in the collection

I have the following code in my application. It is supposed to build a comma separated string from a JQuery collection. The collection is retrieved from some xml. I use JQuery each() to iterate. This is standard code that I use all the time. I declare and define the result variable (patientConditions) first and set it to blank. Within the function I add the found string to the result variable along with a comma. I am not bothered by the trailing comma this leaves if there are results. The problem is that with no results the second line within my each() is running - they probably both are. After the loop has completed (with no matching elements in the xml) the value of the result is ','. It should be blank. I think this is something to do with closures, or hoisting, but I am unable to figure out how its happening. I have hacked a solution to this scenario, but am more worried about the hole in my js knowledge :(
var patientConditions = '';
$xml.find('patient>prescription>conditions').each(function() {
var conditionName = $(this).find('condition>name');
patientConditions += conditionName.text() + ',';
});
From what I can understand there is a match for patient>prescription>conditions, but not for condition>name, in that case $(this).find('condition>name') will return a zero elemet set. then .text() on that set will return a empty string
$xml.find('patient>prescription>conditions').each(function() {
var conditionName = $(this).find('condition>name');
if(conditionName.length){
patientConditions += conditionName.text() + ',';
}
});
Whenever a jQuery object is used to find non existant nodes, in this case $(this).find('condition>name'). The jQuery object still exists, it just contains no association to a node. This will allow you to run all jQuery functions on this object despite it not having any reference. This is why conditionName.text() returns an empty string despite no node being present. The solution, check if the node exists before doing anything.
var patientConditions = '';
$xml.find('patient>prescription>conditions').each(function() {
var conditionName = $(this).find('condition>name');
if (conditionName.length > 0) {
patientConditions += conditionName.text() + ',';
} else {
// Do something if node doesnt exist
}
});

javascript/jquery - dynamically add data by id to an array

Attempting to build a resume creator as a project for codeacademy.
I'm using a button to "save" the user's input to an array so it can later be appended into the resume.
However, I'm failing at getting the data to "save" to the array. I've looked at similar questions here on stackoverflow and I cannot for the life of me figure out what I am doing wrong.
here's my fiddle
specific code block I'm having trouble with:
$('#experiencesave').click(function(){
for (var i = 0; i < jobs; i++){
jobtitle.push = $('#jobtitle'+i).val();
}
$('#morejobs').append(jobtitle);
});
Well, .push [MDN] is a function which has to be called:
jobtitle.push($('#jobtitle'+i).val());
As an alternative solution, instead of using a for loop, you might want to use .map to collect the values:
var jobtitle = $('input[id^=jobtitle]').map(function() {
return this.value;
}).get();
I don't see a reason to give each of those input elements an ID though. Just give them a class. That makes it a bit easier to bulk-process them later. E.g. the selector could then just be $('input.jobtitle').

About a loop that creates dynamic buttons, but cannot give proper values [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript infamous Loop problem?
I am having a small issue, and it would be very nice if some of you could realize about what kind of logic is missing here, since I cannot seem to find it:
I have an array with the results of some previous operation. Let's say that the array is:
var results = [0, 1];
And then I have a bunch of code where I create some buttons, and inside a for loop I assign a different function to those buttons, depending on the position of the array. The problem is that for some reason, all the buttons created (two in this case) come out with the function assigned to the last value of the array (in this case, both would come out as one, instead of the first with 0 and the second with 1)
This is the code:
for (var i = 0; i < results.length; i++) {
var br2 = b.document.createElement("br");
var reslabel = b.document.createTextNode(Nom[results[i]].toString());
var card = document.createElement("input");
card.type = "button";
id = results[i]; // this is the problematic value.
card.onclick = newcard; // this function will use the above value.
card.value = "Show card";
divcontainer.appendChild(br2);
divcontainer.appendChild(reslabel);
divcontainer.appendChild(card);
}
As it is, this code produces as many buttons as elements in the array, each with its proper label (it retrieves labels from another array). Everything is totally fine. Then, I click the button. All the buttons should run the newcard function. That function needs the id variable, so in this case it should be:
First button: runs newcard using variable id with value 0
Second button: runs newcard using variable id with value 1
But both buttons run using id as 1... why is that?
It might be very simple, or maybe is just that in my timezone is pretty late already :-) Anyways, I would appreciate any comment. I am learning a lot around here...
Thanks!
Edit to add the definition of newcard:
function newcard() {
id = id;
var toerase = window.document.getElementById("oldcard");
toerase.innerHTML = "";
generate();
}
the function generate will generate some content using id. Nothing wrong with it, it generates the content fine, is just that id is always set to the last item in the array.
Your id is a global variable, and when the loop ends it is set to the last value on the array. When the event handler code runs and asks for the value of id, it will get that last value.
You need to create a closure to capture the current results[i] and pass it along (this is a very common pitfal, see Javascript infamous Loop problem?). Since newcard is very simple, and id is actually used in generate, you could modify generate to take the id as a parameter. Then you won't need newcard anymore, you can do this instead:
card.onclick = (function(id) {
return function() {
window.document.getElementById("oldcard").innerHTML = "";
generate(id);
};
}(results[i]));
What this does is define and immediately invoke a function that is passed the current results[i]. It returns another function, which will be your actual onclick handler. That function has access to the id parameter of the outer function (that's called a closure). On each iteration of the loop, a new closure will be created, trapping each separate id for its own use.
Before going on, a HUGE thank you to bfavaretto for explaining some scoping subtelties that totally escaped me. It seems that in addition to the problems you had, you were also suffering from scoping, which bit me while I was trying to craft an answer.
Anyway, here's an example that works. I'm using forEach, which may not be supported on some browsers. However it does get around some of the scoping nastiness that was giving you grief:
<html>
<body>
<script>
var results = [0,1];
results.forEach( function(result) {
var card = document.createElement("input");
card.type = "button";
card.onclick = function() {
newcard( result );
}
card.value = "Show card";
document.body.appendChild(card);
});
function newcard(x) {
alert(x);
}
</script>
</body>
</html>
If you decide to stick with a traditional loop, please see bfavaretto's answer.

Categories

Resources