Selecting a DOM Element when (auto-generated) HTML is not well formed - dom

I'm trying to select a control in order to manipulate it but I'm having a problem: I can't select it. Maybe it's because the xml structure, but I really can't change it because it is externally created. SO I have this:
<span class="xforms-value xforms-control xforms-input xforms-appearance xforms-optional xforms-enabled xforms-readonly xforms-valid " id="pName">
<span class="focus"> </span>
<label class="xforms-label" id="xsltforms-mainform-label-2_2_4_3_">Name:</label>
<span class="value">
<input readonly="" class="xforms-value" type="text">
</span>
<span class="xforms-required-icon">*</span>
<span class="xforms-alert">
<span class="xforms-alert-icon"> </span>
</span>
</span>
And what I need is to get the input (line 5). I tryed a lot, for example:
var elem01 = document.getElementById("pName");
console.log("getElementById: " + elem01);
var elem02 = document.evaluate(".//*[#id='pName']" ,document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null );
console.log("evaluate: " + elem02);
console.log(elem02.singleNodeValue);
var elem03 = document.querySelector("#pName");
console.log("querySelector: " + elem03);
But none of that allows me to get a reference to the control. What's wrong?
With XPath, the problem seems to be the XML is no well formed, so document.getElementById("pName") doesnt return anything.
http://jsfiddle.net/wmzyqqja/7/

The problem with your example is that you are executing your Javascript before the relevant DOM elements are loaded (i.e. your code is in the head element):
This will fix the example:
window.onload = changeControlValue;
JSFiddle: http://jsfiddle.net/TrueBlueAussie/wmzyqqja/8/

Try this
var elem01 = document.getElementById("pName");
var inp = elem01.getElementsByTagName("input")[0];
(in JSFiddle the "onload" setting is required.)

Related

How to use result of .length in selector Cypress

I'm trying to perform an action based on the results of an earlier assertion. I have the following situation, I want to determine the number of versions for a document, this is represented in the follwing html:
<ul data-testhook-id="accordion-body">
<li data-testhook-id="accordion-body-item">
<div>
<div data-testhook-id="version-1">
<div data-testhook-id="avatar">
<div data-id="tooltip">John Doe</div>
</div>
</div>
<span data-testhook-id="content">1. 17-08-2018 at 15:26</span>
</div>
<div data-testhook-id="version-2">
<div data-testhook-id="avatar">
<div data-id="tooltip">John Doe</div>
</div>
</div>
<span data-testhook-id="content">2. 20-08-2018 at 13:05</span>
</div>
<div data-testhook-id="version-3">
<div data-testhook-id="avatar">
<div data-id="tooltip">Jane Doe</div>
</div>
</div>
<span data-testhook-id="content">3. 20-08-2018 at 13:11</span>
</div>
<div data-testhook-id="version-4">
<div data-testhook-id="avatar">
<div data-id="tooltip">No Body</div>
</div>
</div>
<span data-testhook-id="content">4. 21-08-2018 at 13:11</span>
</div>
<svg width="12" height="12" data-testhook-id="icon-active-version"><path d="path-here"></path></svg>
</div>
</div>
</li>
Each element with test id data-testhook-id="version-xxx" is a line containing version information and its these div elements I want to count. for this I have set up the following:
cy.get('[data-testhook-id="accordion-body-item"] > div > div').its('length').as('versions')
Now if I add the following assertion, this passes without any problem
cy.get('#versions').should('equal', 4)
But if I try to use the outcome of the number of div's found as a variable in a console.log I no longer get '4' but [object, Object]. Tried this by:
var size = cy.get('[data-testhook-id="asset-versions"] [data-testhook-id="accordion-body-item"] > div > div').its('length')
console.log('foo ' + size)
Which results in foo [object Object] being printed to the console.
What I want to do is use the number of items in a selector to select an element, like:
cy.get('[data-testhook-id="accordion-body-item"] > div > div:nth-child(' + size + ')').find('svg').should('have.attr', 'data-testhook-id', 'icon-active-version')
But as the var is not a number I get the msg
Error: Syntax error, unrecognized expression: :nth-child
[data-testhook-id="asset-versions"] [data-testhook-id="accordion-body-item"] > div > div:nth-child([object Object])
Is it possible to use the number of elements found as a variable for a next selector?
Try this:
cy.get('[data-testhook-id="accordion-body-item"] > div > div').its('length').then((size) => {
cy.get('[data-testhook-id="accordion-body-item"] > div > div:nth-child(' + size + ')').find('svg').should('have.attr', 'data-testhook-id', 'icon-active-version')
});
You cannot assign or work with the return values of any Cypress command. Commands are enqueued and run asynchronously. What commands really return are Chainable<typeOfValueYouWant>, in another words, it's kind of queue object which resolves with desired value.
Read more here
BTW: I think you should consider change your approach for selecting elements. Read more here.
For those who are using Typescript - I wrote plugin for tslint which prevents making this mistake: https://github.com/krzysztof-grzybek/tslint-plugin-cypress

Using Protractor to select elements with by.repeater()

Using the following Protractor element and by.repeater() API methods below:
var targetRowText = 'Sales';
var targetGridName = 'myGrid';
var sel = 'grid-directive[grid-name="' + targetGridName + '"] .col-freeze .grid-wrapper';
var gridRows = element(by.css(sel).all(by.repeater('row in vm.sourceData.data'));
var result = gridRows.all(by.cssContainingText('span', targetRowText)).first();
I am able to select the following row element from a grid which I have labeled, myGrid:
<div id="rowId_21" ng-class-odd="'row-2'" ng-class-even="'row-3'" ng-class="vm.hideRow(row)" class="row-3 height-auto">
<div ng-repeat="column in vm.sourceData.columns" >
<div ng-if="!column.subCols" class="ng-scope">
<div ng-if="row[column.field].length !== 0" class="ng-scope highlight21">
<span ng-bind-html="row[column.field] | changeNegToPrenFormat" vm.highlightedrow="" class="ng-binding">
Sales
</span>
</div>
</div>
</div>
</div>
Please note that I have used by.cssContainingText() to look up the "Sales" span element.
MY PROBLEM:
That that I have located this row in var result, how can I retrieve the id attribute of that outer-most div ?
In other words, I need to selected <div id="rowId_21" so that I can reuse id="rowId_21" in a subsequent Protractor selector.
In jQuery, for example, I could use brute force to get that outer div id as follows :
var el = $('grid-directive[grid-name="Sales"] .col-freeze .grid-wrapper #rowId_21 span')
el.parentElement.parentElement.parentElement.parentElement;
Here's a high-level outlines of what I mean. The grid actually separates the left-most column from the actual data rows, so there are two distinct divs that accomplish this:
<div grid-directive grid-name="myGrid">
<div class="col-freeze" >
<!-- CONTAINS LEFT-MOST "CATEGORIES" COLUMN -->
</div>
<div class="min-width-grid-wrapper">
<!-- CONTAINS THE DATA ROWS-->
</div>
However, I'm struggling to do this in Protractor.
Advice is appreciated...
Bob
A straight-forward option would be to get to the desired parent element using the ancestor axis:
element(by.xpath("./ancestor::div[starts-with(#id, 'rowId')]")).getAttribute("id").then(function (parentId) {
// use parentId here
});
Though, I think that this going down and then up the tree should be considered as a sign that you are not approaching the problem in an easy and correct way.

Declare variable to use inside #helper.repeat - PlayFramework

I want to use helper.repeat to create several input elements. But I want to declare the input tags as html instead of using #helper.input methods. But to do that I have to use a #index inside this loop. I am unable to instantiate and increase this variable. I tried something like the code below but I this output appear in html page:
BaseScalaTemplate(play.twirl.api.HtmlFormat$#5a8a0ced) = {0}
is output in html.
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
#index = {0}
#helper.repeat(questionForm("answer.alternatives"), min = 7) { (alternative) =>
<div class="checkbox">
<input type="checkbox" value="#alternative("correct") ">
<input type="text" id="answer_alternatives_(#index)_text" name="answer.alternatives[#index].text" value="">
</div>
}
</div>
</div>
Is there another maybe cleaner way to do what I want? Maybe with #for?
I use playframework 2.4.6 with Java8.
Playframework will let you do what you need, but you will have to do it in another way.
1) Your form definition will have a Seq[String] to save the results that come from the template.
2) Your form definition will need to include this change. In your case:
"answer_alternatives" -> seq(nonEmptyText)
3) Change the name and id from the template to #{alternative.name} so Playframework can link your input text to the sequence of String.
<input type="text" id="#{alternative.name}" name="#{alternative.name}" value="">

How to obtain the id of an item which the mongo db is currently displaying

I use meteor for my project and I have the following code:
<div class="col-md-4 activities_text">
<center><h2>Learn</h2><br/><br/></center>
{{getContent.description}}
</div>
<div class="col-md-8">
<div class="button_absolute">
<button class="button_ahead"><span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span></button>
</div>
<img class="activities_image" name="image" src="{{getContent.src}}"/>
</div>
</div>
And I want to obtain the id or (subsequently the whole information in the database) about the item which my HTML currently uses for the "src" of the image subsequently for title and description. So I could swap them when the button is clicked. I tried this:
'click .button_ahead':function(event){
var infoNumber = this.number;
console.log("this is the number of the image"+this._id+" "+ this.number);
infoNumber = infoNumber + 1;
Session.set("number", infoNumber);
}
but both this.number and this._id remain undefined. Maybe the problem is that when I click the button I should obtain the data about the image etc.. but not for the button itself.
The context is the button element, so, this is probably not what you want to use, if you really want to use this try changing the context with .call() or .apply() functions.
PS: I'd like to leave a comment under question but I can't due to the rep points
$(event.currentTarget)[0].id would give you the id of the button in
'click .button_ahead':function(event){
var id = $(event.currentTarget)[0].id
var infoNumber = this.number;
console.log("this is the number of the image"+id+" "+ this.number);
infoNumber = infoNumber + 1;
Session.set("number", infoNumber);
}
so in your template you can simply put
<button class="button_ahead" id="this._id"><span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span></button>
to get the id of the current resource you're displaying.
you can also use more simply event.currentTarget.id

Jquery selector seems not to work in google chrome

I want to update the value from a input/textfield with a calculated value from the cookie.It's like a mini local cookie cart.
Saving and retrieving the json from the cookie is a piece of cake.
In my behavior I fail to make the following work:
I added a class for every node in the input field, it's constructed like the example below.
Myid = 'webform_cart_nid_10';
formElement = $('.' + Myid);
console.log(formElement);
The html is quite nested and can be seen http://it2servu.be/broodjes/bestellen (if I may link?) .
the field whose value I want to update looks like this:
<input class="webform_cart_nid_10 webform_cart_nid form-text" type="text" id="edit-submitted-cart-item-cart-elements-10" name="submitted[cart_item][cart_elements][10]" value="0" size="3" maxlength="128">
Is contained in drupal output with severe div-itis.
<div class="page clearfix" id="page">
<div id="section-content" class="section section-content">
<div id="zone-content-wrapper" class="zone-wrapper zone-content-wrapper clearfix">
<div id="zone-content" class="zone zone-content clearfix container-12">
<div class="grid-12 region region-content" id="region-content">
<div class="region-inner region-content-inner">
<div class="block-inner clearfix">
<div class="content clearfix">
<div class="node node-webform node-promoted view-mode-full clearfix ">
<div class="field field-name-title field-type-ds field-label-hidden">
<form class="webform-client-form" enctype="multipart/form-data" action="/broodjes/bestellen" method="post" id="webform-client-form-5" accept-charset="UTF-8">
<div>
<fieldset class="collapsible form-wrapper collapse-processed" id="edit-submitted-cart-item-cart-elements">
<div class="fieldset-wrapper">
<div class="form-item form-type-textfield form-item-submitted-cart-item-cart-elements-10">
<input class="webform_cart_nid_10 webform_cart_nid form-text" type="text" id="edit-submitted-cart-item-cart-elements-10" name="submitted[cart_item][cart_elements][10]" value="0" size="3" maxlength="128">
...
probably it's something stupid, I just can't figure out what it is?
Your problem is with jQuery. If you pop open the console in Chrome and type jQuery, it returns the jQuery function. If you type $ it returns undefined. You have some sort of collision causing $ not to be set to jQuery.
use "jQuery" instead of "$"
Myid = 'webform_cart_nid_10';
formElement = jQuery('.' + Myid);
console.log(formElement);
the "$" never worked for me in Drupal 7.