I'm looking to get index position of matched element within repeater and would like to know how I can find.
List of books below
element.all(by.repeater('books'))
within those rows, some rows will have below element
element(by.css('[ng-click="download"]')
and I want to do following
find element of download button (more than 1)
get index position of first download button (so I can do other stuffs later with .get(3) for specific row)
So here what I have tried.
element.all(by.css('some-css')).first().element(by.tagName('tag-within-css')).get(index);
element.all(by.css('some-css')).get(index).element(by.tagName('tag-within-css'));
Finding Sub-Elements - Protractor locators guide
some error such as index not defined or no method of 'get'.
Thanks.
I think you don't need to operate using element positions/indexes inside the repeater. Instead, find download buttons and operate with the current row using context/element specific element searches by chaining element and element.all:
var books = element.all(by.repeater('books'));
var downloadButtons = books.all(by.css('[ng-click="download"]'));
var firstDownloadButton = downloadButtons.first();
// here is how you can, for example, get the next div element to the download button
var nextElement = firstDownloadButton.element(by.xpath('following-sibling::div'));
Related
I wanted to copy an entire row including its' siblings and contents on button click. When I click the button the element, it appears in the console but doesn't append to the page. This is my code:
It doesn't show any error messages. I've tried innerHTML/outerHTML or append() it doesn't work.
$(document).ready(function() {
$('#addSubFBtn').on('click', function() {
var itm = document.getElementById("trFb");
var wrapper = document.createElement('div');
var el = wrapper.appendChild(itm);
document.getElementById("tbFb").append(el);
console.log(el);
});
});
Seems like what you're trying to do is clone the item after you get it from your document. W3schools website explains how to accomplish this. Check out the link: https://www.w3schools.com/jsref/met_node_clonenode.asp
Once you clone the node, [appendchild] should work as intended
Not sure (as said without seeing related HTML) but i see flaw in your logic:
var itm = document.getElementById("trFb");
still exist on the document(so in the page) so you've to retrieve it before you want to add/move it to another place.
using .removeElement will return you removed element(or null if no element matche the selector) so correct script should be:
var itm=document.getElementById("trFb").parentNode.removeChild(document.getElementById("trFb"));
as shown here to remove element you've to use method on to parent element.
So you can add it to any other element existing.
For more specific use or element created in global JS variable (such an createElement not yet appended) you can see :document.createDocumentFragment(); as explained here https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment
Sample code:
<tr><td>first_button</td><td>second_button</td></tr>
<tr><td>first_button</td></tr>
<tr><td>first_button</td><td>second_button</td></tr>
<tr><td>first_button</td></tr>
<tr><td>first_button</td><td>second_button</td></tr>
function someFunc(i) {
// first button appears on every row
first_button[i].style.display="none"; // works
// second button appears randomly
second_button[i].style.display="none"; // doesn't work as intended
}
// someFunc(2) targets the third row's "first_button" but
// the last row's "second_button". I want to target the
// third row's buttons, not the third button of each type.
var i is incremented with every row. I want to target the i-th row's buttons not the i-th button of each type. What is the simplest way to do this?
Target the rows index, not the index of the nodelist containing your 'buttons'. Also put a check in there to make sure the second cell exists there:
var table = document.getElementById('mytable');
function someFunc(i) {
var row = table.getElementsByTagName('tr')[i];
var cells = row.getElementsByTagName('td');
cells[0].style.display="none";
if(typeof(cells[1]) != 'undefined'){
cells[1].style.display="none";
}
}
JSFiddle
You are probably using some document method to get references to your buttons. Maybe document.getElementsByClassName() or document.querySelectorAll(). Those methods are also available on individual elements. So, you can get a reference to the <tr> element and call row.getElementsByClassName() to get just the elements that are descendents of the row.
What I am trying to do is populate data in a select element. I'm using the following code, where a user selects a SubjectCategory from one drop down, which then should populate the next select element's html. The handler itself is working just fine, it returns the correct html I need to place inside the select element.
Also, keep in mind that I eventually clone both of these select elements and will need to populate them accordingly.
The problem is that $elem is always returning null.
I'm guessing that it's a problem with this line of code, however not quite sure (keeping in mind that I'm also cloning these two select elements):
var $elem = $this.closest('div').prev().find('select');
$(".SubjectCategory").live("click", function () {
var $this = $(this);
var $elem = $this.closest('div').next().find('select');
var a = $this.val();
$.get("/userControls/BookSubjectHandler.ashx?category=" + a, {}, function (data) {
$elem.html(data);
});
});
<div class="singleField subjectField">
<label id="Category" class="fieldSml">Subject Matter</label>
<div class="bookDetails ddl"><select id="ddlSubjectMatter" class="fieldSml SubjectCategory"></select></div>
<label id="Subjects" class="fieldSml">Category</label>
<div class="bookDetails ddl" id="subjectMatter"><select id="ddlSubjects" class="fieldSml Subjects"></select></div>
</div>
You're searching inside the <label>, not the next <div> as you want. next only gets one element after the current one.
Try this: It searches for the first div next to your parent element.
var $elem = $this.closest('div').nextAll('div').first().find('select');
Given that the source element has an id of ddlSubjectMatter and the target select element has an id of subjectMatter, it may be a lot simpler to capitalise the first letter of the second id (i.e. make SubjectMatter) then you get the second element by:
var elem = document.getElementById(this.id.replace(/^ddl/,''));
It makes the element relationship independent of the document layout.
Incidentally, it is invalid HTML to have select elements with no options, not that it is a big issue.
Why are you creating an extraneous $this variable? Unless you've omitted code that requires it for a different scope, just call $(this). That might be causing the problem, too.
HTML
<tr id="rowId"><td><textarea class="inputTextarea"></textarea></td><td><textarea class="inputTextarea"></textarea></td></tr>
<tr id="rowId2"><td><textarea class="inputTextarea"></textarea></td><td><textarea class="inputTextarea"></textarea></td></tr>
<tr id="rowId3"><td><textarea class="inputTextarea"></textarea></td><td><textarea class="inputTextarea"></textarea></td></tr>
Provided I know rowId, how do I find the next textarea ON THIS PAGE, starting at any arbitary point. I don't mean ANY input, textarea only. I need to be able to start AT ANY row, and progress on to the next textarea, essentially going down the rows.
EDIT
Based on answers, I used the following code to traverse the textareas row by row:
var curElt = $('#' + startAt); //startAt is the first row id
for(var i=1; i < 10; i++) {
$(curElt).find('textarea').eq(0).val(i);
$(curElt).find('textarea').eq(1).val(i+1);
curElt = $(curElt).next();
}
You can use the next and find methods:
$('#' + current_row_id).next().find('textarea').eq(0);
next will get the next sibling, and then find will find all of the elements within the set that match the passed-in selector(s), then eq(0) will grab the first element in the resulting set returned from find.
$('#rowId2').find('textarea');
That will find both children of the row. If you want the first one, either:
$('#rowId2').find('textarea').eq(0); //jQuery object
$('#rowId2').find('textarea')[0]; //DOM Element
Edit: If you only know one row and want to find the first textarea in the next row:
$('#rowId').next().find('textarea').eq(0);
$textarea = $('#rowId textarea').eq(0);
$nextarea = $textarea.closest('tr').next().find('textarea').eq(0);
Just to clarify, $.fn.next() finds the next sibling in the DOM.
Starting from the textarea, first
you have to find its parent-tr (
$textarea.closest('tr') ).
From there, use next to find the next tr
( .next() )
Finally, find the first
textarea within that tr (
.find('textarea').eq(0) )
Try this:
$("#rowID textarea:first-child").val()
Perhaps I'm using $.data incorrectly.
Assigning the data:
var course_li = sprintf('<li class="draggable course">%s</li>', course["fields"]["name"]);
$(course_li).data('pk', course['pk']);
alert(course['pk']); // shows a correct value
alert($(course_li).data('pk')); // shows null. curious...
course_li is later appended to the DOM.
Moving the li to a different ul:
function moveToTerm(item, term) {
item.fadeOut(function() {
item.appendTo(term).fadeIn();
});
}
Trying to access the data later:
$.each($(term).children(".course"), function(index, course) {
var pk = $(course).data('pk');
// pk is undefined
courses.push(pk);
});
What am I doing wrong? I have confirmed that the course li on which I am setting the data is the same as the one on which I am looking for it. (Unless I'm messing that up by calling appendTo() on it?)
When you store the data:
$(course_li).data('pk', course['pk']);
you're creating an element but not saving it, so it's lost. Your alert test test the wrong value; it should be:
$(course_li).data('pk', course['pk']);
alert($(course_li).data('pk'));
which is null. Consider:
$(course_li);
$(course_li);
This creates two different elements with source equal to course_li, which are then promptly lost. What you need to do is create the element first, then work with that single element (i.e. don't call $(course_li) more than once). For example,
var course_li = $(sprintf('<li class="draggable course">%s</li>',
course["fields"]["name"]));
course_li.data('pk', course['pk']);
parent.append(course_li);
Note that course_li now holds an element, rather than a string.
try checking to see if the element being created by this call:
$(course_li)
is a single 'li' element, or a div. From the doco:
When the HTML is more complex than a single tag without attributes, as it is in the above example... snip ...Specifically, jQuery creates a new <div> element and sets the innerHTML property of the element to the HTML snippet that was passed in
So it's probably creating a div that you are assigning the data to, so when you select the 'li' itself, you are getting a child of the actual element that you set the data on.