Angular JS Protractor extract data - javascript

using protractor I would like to extract some specific data from my Angular JS application.
The data I want to extract is embedded in a external div with id "jobHolder" inside this div I have several embedded divs each have an id "job_i". where i goes from 1 to n...
Here is the HTML :
<div class="thumbJobs" id="jobHolder" style=
"height: 275px; overflow: hidden;" tabindex="5052">
<div class="job ng-scope" id="job_1">
<div class="viewerEye" id="job_1_viewerEye"></div>
<div class="jobBigPicto transition_2_opa" id="job_1_jobBigPicto">
<div class="jobsSmallPictos transition_2_opa" id=
"job_1_jobsSmallPictos">
<div class="jobDown transition_2_opa" id="job_1_jobDown">
<div class="jobTitle ng-binding">
TSK(Z87700J)(000)(Z87700JU00)(000)
</div>
<div class="jobText ng-binding"></div>
</div>
<div class="jobHoverInfo" id="job_1_jobHoverInfo"></div>
<div class="job ng-scope" id="job_2">
<div class="job ng-scope" id="job_3">
<div class="job ng-scope" id="job_4">
<div class="job ng-scope" id="job_5">
<div class="job ng-scope" id="job_6">
<div class="job ng-scope" id="job_7">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
What I would like to extract is the jobTitle in each inernal DIV. I have tried with repeaters but i could not extract all data so I am trying to use Id instead.
I want to extract all data ambedded in a div having id = job_i where i goes from 1 to the last index of the last DIV with the same id?
I have used this code to extract the data but the code Displays only the first 6 elements.
Could it be a synchronisation ot time out issue?
for (var i=1; i<20;i++)
{
var result = ptor.findElement(by.xpath('html/body/div[2]/div[1]/section[5]/div[4]/div['+i+']/div[4]/div[1]'));
result.getText().then(function(text)
{
console.log(text);
});
And here is the console output it shows only 6 elements whereas the web page is displaying 20 elements :
TSK(Z87700J)(000)(Z87700JU00)(000)
TSK(AGD170JFZZ)(000)
TSK(ZA1112O)(000)(ZA1111OU00)(000)
TSK(ZA1100O)(000)(ZA1100OU00)(000)
TSK(ZA1111O)(000)(ZA1111OU00)(000)
WAR27_STEP16 A TASK FOR CHAR FR
AN TASK WITH SPACE
WAR81_STEP_NETWORK_SESSION_MU
TSK(TTS758J)(000)(TTS758JN00)(000)
.
Finished in 10.851 seconds
1 test, 0 assertions, 0 failures

You may be hitting a timing issue since by default all findElement requests are asynchronous in nature and return a Promise. You might be better off writing your code as follows:
for (var i=1; i<20;i++)
{
ptor.findElement(by.xpath('html/body/div[2]/div[1]/section[5]/div[4]/div['+i+']/div[4]/div[1]'))
.then(function(result){
result.getText().then(function(text)
{
console.log(text);
});
});
This should wrap each one of the findElement requests so that they each get handled properly after the promise resolves.
Another thing you might look at is using findElements to get back an array that you then iterate and dump to the console.
Hope this helps.

Related

How to show element only if other element contains something using jQuery?

My guess is what I want to achieve should be easy, but due to my lack of knowledge of front-end development, I cannot manage to solve issue. Have a page that works with AJAX-filters that users can select. Filters that are currently applied show up within <div> with id=current-filters.
HTML looks like this:
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<!-- here every single applied filter is displayed -->
</div>
</div>
</div>
Need to hide the the entire DIV current-filters-box in case no filter is applied.
The page uses a Javascript file, bundle.js which is massive, but contains the following line:
s=document.getElementById("current-filters")
Therefore tried the following if-statement to hide the DIV:
if(s.length<1)$('#current-filters-box').hide()
and
if(s=0)$('#current-filters-box').hide()
But this does not seem to have any effect. Can someone tell, what I did wrong?
Demo of page can be found here
EDIT: this is what the HTML looks like when filters are applied:
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<div class="badge-search-public">
<strong>Humanities & Languages</strong> <span class="x" data-property="disciplines" data-value="4" onclick="filter.removeFilter(this)">×</span>
</div>
<div class="badge-search-public">
<strong>January</strong> <span class="x" data-property="months" data-value="1" onclick="filter.removeFilter(this)">×</span>
</div>
</div>
</div>
Both of your conditions are incorrect or I would say they are not doing what you think they do.
s.length will always prints undefined so instead of s.length<1 you could use s.children.length
and the second one is not a condition rather it is an assignment
s==0 // condition
s=0 //assignment
the correct condition for your requirement would be
if(s.children.length<1){
I have assigned snippets for illustration.
Without filters
s = document.getElementById("current-filters")
console.log(s.children.length);
if (s.children.length < 1) {
$('#current-filters-box').hide(1000)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="current-filters-box">
filter box
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<!-- here every single applied filter is displayed -->
</div>
</div>
</div>
Without filters
s = document.getElementById("current-filters")
console.log(s.children.length);
if (s.children.length < 1) {
$('#current-filters-box').hide(1000)
}
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<div class="badge-search-public">
<strong>Humanities & Languages</strong> <span class="x" data-property="disciplines" data-value="4" onclick="filter.removeFilter(this)">×</span>
</div>
<div class="badge-search-public">
<strong>January</strong> <span class="x" data-property="months" data-value="1" onclick="filter.removeFilter(this)">×</span>
</div>
</div>
</div>
Try this .
if( $('#current-filters').is(':empty') ) {
$('#current-filters-box').hide()// or $('#current-filters-box').css("display","none")
}
You are performing an assignment, try..
if (s.children.length)
Using vanilla JavaScript, you can check if the current-filters div is empty or not and toggle the parent div current-filters-box like this:
s= document.getElementById("current-filters");
t= document.getElementById("current-filters-box");
if(s.children.length<1) {
t.style.display = 'none';
// t.style.visibility= 'hidden'; <<-- use this if you want the div to be hidden but maintain space
}
else {
t.style.display = 'block';
// t.style.visibility= 'visible'; <<-- use this if you used visibility in the if statement above
}
You can achieve this by adding your own variable which counts or maintains your applied filters, e.g.
var applied_filter_count = 0;
at every time filter is applied
applied_filter_count++;
if(applied_filter_count) {
$('#current-filters-box').show()
}
and at every time filter is removed
applied_filter_count--;
if(!applied_filter_count) {
$('#current-filters-box').hide()
}
and by default current-filters-box should be display:none

jQuery: Appending multiple elements from .load() after the last occurrence of a specific class element on a page

I'm working on a listing page and I am trying to create a "Load More Items" functionality. I'm attempting to use .load() to append all ".vehicleListing" elements from another page url (the second listing page) and add them after the last occurrence of a a div with the class of "vehicleListing".
Page 1:
<div class="overview-feature-1">
<div class="vehicleListing">1</div>
<div class="vehicleListing">2</div>
<div class="vehicleListing">3</div>
<div class="vehicleListing">4</div>
<div class="vehicleListing">5</div>
<div class="vehicleListing">6</div>
<div class="controls"></div>
<div class="additional-controls"></div>
</div>
Page 2:
<div class="overview-feature-1">
<div class="vehicleListing">7</div>
<div class="vehicleListing">8</div>
<div class="vehicleListing">9</div>
<div class="vehicleListing">10</div>
<div class="vehicleListing">11</div>
<div class="vehicleListing">12</div>
<div class="controls"></div>
<div class="additional-controls"></div>
</div>
Desired Result:
Page 1 after "Load More" functionality is executed:
<div class="overview-feature-1">
<div class="vehicleListing">1</div>
<div class="vehicleListing">2</div>
<div class="vehicleListing">3</div>
<div class="vehicleListing">4</div>
<div class="vehicleListing">5</div>
<div class="vehicleListing">6</div>
<div class="vehicleListing">7</div>
<div class="vehicleListing">8</div>
<div class="vehicleListing">9</div>
<div class="vehicleListing">10</div>
<div class="vehicleListing">11</div>
<div class="vehicleListing">12</div>
<div class="controls"></div>
<div class="additional-controls"></div>
</div>
This is what I have so far, but it keeps adding it inside the last vehicleListing div instead of after it.
$(".vehicleListing").after().last().load('page2url' + ' .vehicleListing');
Can someone point out why it's inserting inside the last div instead of after it, and how I can correct this?
Here is what worked for me:
Add an empty div after the last vehicleListing in your first file
<div class="overview-feature-1">
<div class="vehicleListing">1</div>
<div class="vehicleListing">2</div>
<div class="vehicleListing">3</div>
<div class="vehicleListing">4</div>
<div class="vehicleListing">5</div>
<div class="vehicleListing">6</div>
<div id="container"></div>
<div class="controls"></div>
<div class="additional-controls"></div>
</div>
And change your JS
$("#container").load('http://aba.bbtj.dev/test2.html' + ' .vehicleListing', function(){
$('#container').replaceWith(function() {
return $('.vehicleListing', this);
});
$( '<div id="container"></div>' ).insertAfter( ".vehicleListing:last" );
});
This will load the new vehicles in the empty div, and then remove that div and keep the new vehicles (using the replaceWith function).
Then we re-add the empty div to be able to add more vehicule.
Load documntation:
Description: Load data from the server and place the returned HTML into the matched element.
$(".vehicleListing").after().last()
Targets the last vehicleListing div.
You can try smething like:
$.load('page2url' + ' .vehicleListing').insertAfter(".vehicleListing:last");
Your probably going to have to go about this differently. As mentioned, load() takes the response and loads it into the element it is operating upon. Since it replaces the contents, it doesn't really fit what you are trying to do which is to append additional content to an existing element. Your best bet is to probably use an ajax method instead.
$.get('page2url' + ' .vehicleListing', function(data){
$(".vehicleListing").last().after(data);
});

ng-repeat within ng-repeat in angular

I have a record that is returned from an angular $resource promise like below.
The record is an array and within each array of record there another variable array. I try displaying in my view like below.
div(ng-repeat="category in categories")
h6
img(src="{{category.ImageUrl}}")
|{{category.Name}}
ul(class="list-unstyled")
li(item in category.CategoryItems)
a(href="#") {{item.Item}} (0)
The problem is , category.CategoryItems returned undefined and empty as a result even though its actually an array of objects. Please how do i print those? Each category has category items of an array type. How do i best achieve this pls?
You didn't use ng-repeat the second time. Try this:
div(ng-repeat="category in categories")
h6
img(src="{{category.ImageUrl}}")
|{{category.Name}}
ul(class="list-unstyled")
li(ng-repeat="item in category.CategoryItems") //ng-repeat added
a(href="#") {{item.Item}} (0)
I used nested ng-repeat in my project some time ago. In my project the requirement was to show all blogs like in snapshot:
To achieve this you can use ng-repeat like in below code:
<div class="panel ">
<div class="panel-body">
<div class="col-sm-12 " ng-repeat="blogBlock in blogs" >
<h2 class="hot-topics-heading">{{blogBlock.year}}</h2>
<div class="blog-year>
<div class="col-sm-6" ng-repeat="months in blogBlock.data">
<span class="hot-topics-heading">{{months.monthName}}</span>
<div class="blog-month" >
<ul class="hot-topics-ul" >
<li class="blogTitle" ng-repeat="blog in months.data">
{{blog.title}}
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
In the above code ng-repeat inside the ng-repeat and also inside the ng-repeat.
<div ng-repeat="blogBlock in blogs" >
<div ng-repeat="months in blogBlock.data">
<ul>
<li ng-repeat="blog in months.data"></li>
</ul>
</div>
</div>

Arrange div inside another div with Javascript

So if you have some free time:
This is a quite complex thing, or I'm just too naive, as I've been working for hours without getting the desired output/result, I wish you could help me if you have some free time.
Firstly this is the data I have, which is retrieved from a PHP newsfeed, so is not a static number of items:
<span class="dateclass">date1</span>
<span class="dateclass">date2</span>
<span class="dateclass">date3</span>
....and so on
<br>
<div class="contentclass">content1</div>
<div class="contentclass">content2</div>
<div class="contentclass">content3</div>
....and so on
I need to work with the classes and IDs, because is no php template engine so I can't call a single element, the code is distributed among several files, and the easier way to achieve what I need would be via javascript and their IDs / Classes
I need to get the following output by copying the data above and, with Javascript, tweak the data in order to achieve the final result, which should be:
<div class="frame">
<div class="timeline-badge"> <i class="fa fa-twitch"></i> </div>
<span class="timeline-date"> <span class="dateclass">date1</span> </span>
<div class="timeline-content"> <div class="contentclass">content1</div> </div>
</div>
<div class="frame">
<div class="timeline-badge"> <i class="fa fa-twitch"></i> </div>
<span class="timeline-date"> <span class="dateclass">date2</span> </span>
<div class="timeline-content"> <div class="contentclass">content2</div> </div>
</div>
<div class="frame">
<div class="timeline-badge"> <i class="fa fa-twitch"></i> </div>
<span class="timeline-date"> <span class="dateclass">date3</span> </span>
<div class="timeline-content"> <div class="contentclass">content2</div> </div>
</div>
The <div class="timeline-badge"> <i class="fa fa-twitch"></i> </div> ones don't exist as data in order to "transform", yet those are part of the style and I'd need them as well, but I haven't gotten that far to actually worry about those :(
I know, what a change!, yet I've been close to the result, I've been using different modified versions of the following code:
setTimeout(function() {
var element = document.getElementById("unique_ID");
element.innerHTML = "";
Array.prototype.forEach.call(document.querySelectorAll(".contentclass"), function(e) {
var example = element.appendChild(e.cloneNode(true));
});
}, 300);
I'm not posting all the versions I've made because none of them were going nowhere, and none of them work :/ I don't think I even have a copy of those
So what I've tried unsuccessfully so far has been:
Adding IDs to <span class="timeline-date"> and <div class="timeline-content"> so I can manipulate them with js
Using a different div setups in order to achieve the final result by manipulating the js code, this means using the following div/HTML arrangement in order to paste the cloneNode results there with some added elements, such as var div = document.createElement('div'); with div.className += "frame";, etc. Yet nothing works.
I've tried adding an ID via javascript to a div created in the same code, something like this:
.....(a previously defined variable for counter, of course)
var div = document.createElement('div');
div.id = "id_frame"+counter;
counter++;
Yet it didn't work when I tried to send the results with getElementById and the ID generated with the counter
I'm about to give up, it has been quite complicated for me ;P ... Any suggestions? :(
As far as I could get was to something like this:
<div id="ID_unique">
<div class="frame">
<span class="timeline-date">date1</span>
</div>
<div class=" timeline-content">content1</div>
<div class="frame">
<span class="timeline-date">date2</span>
</div>
<div class=" timeline-content">content2</div>
<div class="frame">
<span class="timeline-date">date3</span>
</div>
<div class=" timeline-content">content3</div>
</div>
Which isn't actually that far from the final result if it wasn't for those <div class="frame"> that should cover the content tags as well :(
First thing i think you should do is get all dateClasses and contentclass, and then create your frame one by one:
var dateClasses = $('.dateClass'); // array of all your dateClasses
var contentClasses = $('.contentClasses'); // array of all your contentClasses
for(var i=0; i< Math.min(dateClasses.length,contentClasses.length); i++) {
var frame = $("<div>", {class: "frame"}); // create your frame node
var timeLineDate = $("<div">,{class: "timeline-date"});
var timeLineContent = $("<div">,{class: "timeline-content"});
//Append DateClass to your timeline-data:
timeLineData.append(dateClasses[i]);
//Append ContentClass to your timeline-content:
timeLineContent.append(contentClasses[i]);
//Append all to your frame
frame.append(timeLineData);
frame.append(timeLineContent);
}
I didnt run it or test it tough, but hope it will give you an idea on how to achieve what you want.
Hope it helped.

How to create an array of divs with content?

I'm trying to create an array of nested divs, in which I only need to change 3 values when writing the divs to the document (html).
My divs look like this:
<div class="item">
<div class="item-h"> <a class="item-anchor" href="1_water_bottle.html">
<div class="item-image"> <img class="item-image-first" src="images/img_1_water_bottle.png" alt="">
<div class="item-meta">
<h2 class="title">Water Bottle 1</h2>
<span class="item-arrow"></span> </div>
</div>
</a> </div>
</div>
I need to create an array of about 50 items, and then use the document.write function to write 4 of those arrays for each page, as a section for "similar stuff".
I searched on stackoverflow, and came up with :: this page :: , which explains how to create an array in javascript, and then found another script that uses the document.write function.
The script uses an array of categories, to populate a form selection. And it does so, but using an array : (var categories = new Array("a1", "a2", "a3", ...) and so on.
for(var hi=0; hi<categories.length; hi++)
document.write("<option value=\""+categories[hi]+"\">"+categories[hi]+"</option>");
Could I use these two scripts to populate a section with 4 items from the array of the divs?
If so, then how could I do it? I know it can be done in php, but don't know if this can be done in javascript.
I tried, and created this array in notepad++, but the code wasn't recognized as a string, per array element...
var array_divs = [
$('<div class="item">
<div class="item-h"> <a class="item-anchor" href="1_water_bottle.html">
<div class="item-image"> <img class="item-image-first" src="images/img_1_water_bottle.png" alt="">
<div class="item-meta">
<h2 class="title">Water Bottle 1</h2>
<span class="item-arrow"></span> </div>
</div>
</a> </div>
</div>') ,
$('<div class="item">
<div class="item-h"> <a class="item-anchor" href="1_water_bottle_2.html">
<div class="item-image"> <img class="item-image-first" src="images/img_1_water_bottle_2.png" alt="">
<div class="item-meta">
<h2 class="title">Water Bottle 2</h2>
<span class="item-arrow"></span> </div>
</div>
</a> </div>
</div>')
]
Trying to populate the section, with selective items from the array, for example:
document.write(array_divs[1],array_divs[2]);
I haven't tried this, but since notepad++ didn't treat my div as a string, I had to search again... but couldn't find any info regarding this.
Thanks for any help.
-

Categories

Resources