I have the following DOM tree (simplified)
<div class=row-0>...</div>
<div class=row-1>
<div class=container>
<div class=panel>...</div>
</div>
</div>
<div class=row-2>...</div>
<div class=row-3>
<div class=container>
<div class=panel>...</div>
<div class=drawer>...</div>
</div>
</div>
<div class=row-4>...</div>
As you can see, all elements have a panel class=panel but not all elements have a drawer class=drawer.
I am iterating through the elements as follows:
const events = Selector('[class^="row-"]');
const eventCount = await events.count;
for (let i = 0; i < eventCount; i++) {
const event = await events.nth(i);
// Here's where I want to check if the event (class=row-x) has a child element class=drawer
const drawer = await Selector(event).child('class["drawer"]')
if (await drawer.exists) {
console.log('Found drawer')
}
}
I can successfully iterate through all the rows, but I cannot detect if a certain event has a drawer. I tried to follow the logic from this answer and also from the docs.
How can I perform this logic?
I suggest you rewrite your test as follows:
Get all "drawer" elements: Selector('div.drawer').
Get all rows that contain the "drawer" elements according to your page hierarchy.
I have created a simple example - please check it out:
index.html:
<html>
<head></head>
<body>
<div class=row-0>Row 0</div>
<div class=row-1>
Row 1
<div class=container>
<div class=panel>...</div>
</div>
</div>
<div class=row-2>Row 2</div>
<div class=row-3>
Row 3
<div class=container>
<div class=panel>...</div>
<div class=drawer>...</div>
</div>
</div>
<div class=row-4>Row 4</div>
<div class=row-5>
Row 5
<div class=container>
<div class=panel>...</div>
<div class=drawer>...</div>
</div>
</div>
</body>
</html>
test.js:
import { Selector } from 'testcafe';
fixture `Fixture`
.page `./index.html`;
test('find rows with "drawer"', async t => {
const drawerElements = Selector('div.drawer').addCustomDOMProperties({
outerHTML: el => el.outerHTML
});
const length = await drawerElements.count;
console.log('Row elements count:', length);
for (let i = 0; i < length; i++) {
console.log('//', i + 1, 'element:');
console.log(await drawerElements.nth(i).parent().parent().outerHTML);
}
});
Command:
testcafe chrome test.js
Result:
Running tests in:
- Chrome 78.0.3904 / Windows 10.0.0
Fixture
Row elements count: 2
// 1 element:
<div class="row-3">
Row 3
<div class="container">
<div class="panel">...</div>
<div class="drawer">...</div>
</div>
</div>
// 2 element:
<div class="row-5">
Row 5
<div class="container">
<div class="panel">...</div>
<div class="drawer">...</div>
</div>
</div>
√ find rows with "drawer"
1 passed (1s)
Related
I have a set of nested divs that look like this (this is just an example, the structure can vary):
<div class="container">
<div class="dummy">
<div class="target one"></div>
<div class="dummy">
<div class="target two">
<div class="dummy"></div>
<div class="target three"></div>
</div>
</div>
<div class="target four"></div>
</div>
</div>
I now want to select the <div>s with classes one, two and four. What I would need is a recursive selector (like $(.container div.target)) which aborts the search down a branch after it found an element and instead continues with the next branch.
$(.container div.target) selects all the targets, which is not what I want. $(.container div.target:first-of-type) almost does what I want; it selects one and two, but not four.
Is there a jQuery selector that can do what I want? If not how could I implement this behaviour in JavaScript?
You can try using the following code:
$('.container div.target').not(function () {
return $(this).parents('div.target').length > 0
})
It uses jquery .not() method to eliminate <div class='target'> elements having another <div class='target'> element somewhere up in the dom hierarchy.
$(document).ready(function () {
$('.container div.target').not(function () {
return $(this).parents('div.target').length > 0
}).each(function () {
console.log($(this).attr('id'));
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="dummy">
<div id="1" class="target one"></div>
<div id="-1" class="dummy">
<div id="2" class="target two">
<div id="-2" class="dummy"></div>
<div id="3" class="target three"></div>
</div>
</div>
<div id="4" class="target four"></div>
</div>
</div>
So after trying out different things, I figured that writing my own function to do this would probably be the best solution. This is what I came up with:
$.getHighestElements = function(startPoint, selector, child = false) {
var elems = [];
startPoint.children('div').each(function () {
if($(this).hasClass(selector)) {
elems.push($(this));
} else {
$.merge(elems, $.getHighestElements($(this), selector, true));
}
});
if(child)
return elems;
else
return $(elems).map(function() { return this.toArray(); });
}
const elements = $.getHighestElements($(.container), "target");
This returns a wrapped set of elements that can be used just like any other jquery wrapped set.
I have a search for items. The block in which the value is searched consists of several elements. I need to exclude the last item from the search. Those. so that this element is not affected, except for the rest.
I tried like this
$('.blog_content_item').not('.last').each(function() {...});
and
$(".blog_content_item:not('.last')").each(function() {...});
Does not help. Both that and that is not true on syntax. Please tell me how to exclude the "last" element from the search. Thank.
$('.blog_content_item').each(function() {
if($(this).text().toLowerCase().indexOf(value) === -1) {
...
return;
} else {
...
}
});
<div class="blog_content_item">
<div class="first">
<div class="middle">
<div class="last">
</div>
This might do the trick for you
Sample HTML
<div class="blog_content_item">
<div class="first">First</div>
<div class="middle">Middle</div>
<div class="last">Last</div>
</div>
Script
$('.blog_content_item >div:not(:last-child)').each(function () {
// your awesome stuffs here
console.log($(this).text());
})
Using :not() filter with descendant selector
https://api.jquery.com/descendant-selector/
A descendant of an element could be a child, grandchild,
great-grandchild, and so on, of that element.
console.log($('.blog_content_item :not(.last)').get())
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="blog_content_item">
<div class="first"></div>
<div class="middle"></div>
<div class="last"></div>
</div>
I have rows of data and each row has 2 columns.
<div class="row">
<div class="col-md-2"><strong>Natural ID:</strong></div>
<div class="col-md-4">{{ctrl.firstobject.naturalId}}</div>
<div class="col-md-2"><strong>ManulaID:</strong></div>
<div class="col-md-4">{{ctrl.firstobject.manualID}}</div>
</div>
Now, I would like to compare the value of the field called "NaturalID" with another Natural ID (accessed by ctrl.CustomObject.naturalid) and if these two values are different, I would like to highlight in red the field corresponding to Natural ID in the above HTML. How can I do this?
You can use ng-class something like
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl',function($scope, $timeout) {
$scope.firstobject={
naturalId:1,
manualID:2
}
$scope.customObj={
naturalId:2
}
});
.red{
color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl" >
<div class="row">
<div class="col-md-2"><strong>Natural ID:</strong>
</div>
<div class="col-md-4" ng-class="{'red':firstobject.naturalId !=customObj.naturalId}">{{firstobject.naturalId}}<span ng-if="firstobject.naturalId !=customObj.naturalId" class="glyphicon glyphicon-alert"></span>
</div>
<div class="col-md-2"><strong>ManulaID:</strong>
</div>
<div class="col-md-4">{{firstobject.manualID}}</div>
</div>
</div>
I have an Angular application that renders spans based on whether they're needed or not (many ng-if's). I need to wrap these spans in a div based on their content/class names.
So, for example:
<div class="1"></div>
<div class="2"></div>
<div class="3"></div>
I don't want to do anything. But with
<div class="1"></div>
<div class="2"></div>
<div class="3"></div>
<div class="4"></div>
I DO want to wrap these 4 divs in a parent div <div class="parent"></div>, but only if the four appear one after the other. Is there a way to do this in CSS? Can I just use a combo of selectors to manipulate the four elements if they appear consecutively?
so you cant do this using just css and html, like the comments above, you need to use some form of javascript to manipulate the dom. heres an example using jQuery. hope it helps!
$(document).ready(function() {
$('.wrapme').each(function() {
var myElement = $(this);
var next1 = $(this).next();
var next2 = $(this).next().next();
var next3 = $(this).next().next().next();
if (next1.hasClass('wrapme') && next2.hasClass('wrapme') && next3.hasClass('wrapme')) {
var html = '<div class="parent"></div>';
next3.after(html);
var parent = next3.next('.parent')
parent.append(myElement);
parent.append(next1);
parent.append(next2);
parent.append(next3);
}
});
});
.parent {
background-color:lightgray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapme">1</div>
<div class="wrapme">2</div>
<div class="wrapme">3</div>
<span>BREAKKKKKK</span>
<div class="wrapme">1</div>
<div class="wrapme">2</div>
<div class="wrapme">3</div>
<div class="wrapme">4</div>
<span>BREAKKKKKK</span>
<div class="wrapme">1</div>
<div class="wrapme">2<div>
<span>BREAKKKKKK</span>
<div class="wrapme">1</div>
<div class="wrapme">2</div>
<div class="wrapme">3</div>
<div class="wrapme">4</div>
<span>BREAKKKKKK</span>
<span>BREAKKKKKK</span>
<div class="wrapme">1</div>
<div class="wrapme">2</div>
hey hey
<div class="wrapme">3</div>
<div class="wrapme">4</div>
<span>BREAKKKKKK</span>
I need to loop through 4 divs arranged in a 2x2 way (cycle=highlighting the selected div) indefinitely. I can't think of the j-query required to do this.
<div class="contentwrap-black" id="current-features">
<div id="content" class="container">
<div class="row-fluid">
<div class="span12">
<div class="row-fluid">
<!-- ----------- IPHONE --------- -->
<div class="span4" id="iphone-white">
<img class="iphone-white-img" src="img/iphone-wht-front.png" alt="">
</div>
<!-- ----------- BANNER --------- -->
<div class="span8">
<h1 class="current-features-banner">CURRENT FEATURES</h1>
<div class="row-fluid">
<!-- ----------- LEFT COLUMN --------- -->
<div class="span6" id="">
<div class="row-fluid">
<div class="span12 content" id="">
<h3>Heading-1</h3>
<p> Paragraph-1</p>
</div>
<div class="span12" id="divider">
<hr>
</div>
<div class="span12 content" id="">
<h3>Heading-2</h3>
<p> Content-2</p>
<hr id="line"> <!-- THIS LINE IS HIDDEN UNTIL MOBILE SIZE-->
</div>
</div>
</div>
<!-- ----------- RIGHT COLUMN --------- -->
<div class="span6" id="">
<div class="row-fluid set">
<div class="span12 content" id="">
<h3>heading-3</h3>
<p>paragraph-3
</div>
<div class="span12 trap" id="divider">
<hr>
</div>
<div class="span12 content " id="">
<h3>heading-4</h3>
<p>paragraph-4.</p>
</div>
</div>
</div>
<!-- ----------- END OF COLUMNS --------- -->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
The 4 divs I want to loop between are the ones containing the class "content", highlighting each div for 2 seconds and then switching to the next one.
I got a fiddle for you: http://jsfiddle.net/tkjzZ/4/
EDIT: I fixed needing the flag classes. You still need to start with one highlighted though.
function changeHighlight()
{
if($(".content.highlight").is(":last"))
{
$(".highlight").removeClass("highlight");
$(".content").first().addClass("highlight");
}
else
{
$(".highlight").removeClass("highlight").next().addClass("highlight");
}
}
$(document).ready(function () {
setInterval(changeHighlight, 2000); //2 sec
});
This does not cover your animation or whatever you want to do, but it shows how to keep it cycling indefinitely
function cycle() {
$(".container .content")
.last()
.detach()
.prependTo(".container");
}
// and in the inverse sense
function cycle() {
$(".container .content")
.first()
.detach()
.appendTo(".container");
}
Example http://jsfiddle.net/XuHQv/
Ok so color cycling it is http://jsfiddle.net/XuHQv/1/
setInterval(function() {
var items = $(".container .content");
var length = items.length;
items.each(function(i, ele) {
if ($(ele).hasClass("color")) {
$(ele).removeClass("color");
if (i < (length-1)) {
$(items[i+1]).addClass("color");
}
else {
$(items[0]).addClass("color");
}
return false;
}
});
}, 1000);